问个C++和linux内核的相关问题,挺奇怪的

sopro 2006-12-15 06:39:05
我写了程序,如下:
#include <iostream>
using namespace std;

char* func()
{
char cArray[] = "123456";
return cArray;
}

int main()
{
char* p = func();
cout << hex << reinterpret_cast<int>(p) << endl; //以16进制输出p的地址
}

结果:
bf8bcc41 (每次结果不一样)
bff442c1
...
(或者其他数值)

我觉的很奇怪!
我们暂且不论我返回的是一个局部数组的首地址(我知道这是绝对应该避免的),就现在出现的问题,我感到困惑。

一个进程再虚拟地址空间的分布我大概是了解的。在kernel下面,也就是0xc000000地址之下应该是进程的stack(根据函数调用的情况动态变化)。那么,认为,既然是相同的程序运行,进程在虚拟地址空间中的分布应该是一摸一样的,局部数组的首地址那么也应该是同一个虚拟地址(当然,物理地址很可能不一样,但是进程看到的应该只能是虚拟地址)

今天和其他人讨论了半天,没弄明白,特地注册了一个帐号到csdn上面请高手做答,谢谢!
...全文
1790 25 打赏 收藏 转发到动态 举报
写回复
用AI写文章
25 条回复
切换为时间正序
请发表友善的回复…
发表回复
fengfeiwuwq 2006-12-21
  • 打赏
  • 举报
回复
的确值得学习
lurenfu 2006-12-20
  • 打赏
  • 举报
回复
看看Security Enhanced Linux,有讲SE-Linux是如何防止缓冲区溢出攻击的,其中提到一点就是运行的起始地址还有栈地址在每次运行时是不同的,在以前的2.4内核中,同一个程序每次运行时的虚拟地址空间布局是一样的,2.6的内核作了改进
playmud 2006-12-20
  • 打赏
  • 举报
回复
线形地址,不是物理地址.
WaterWalker 2006-12-20
  • 打赏
  • 举报
回复
哪里有介绍捏?好象windows中的地址都不是物理地址吧???
windows也不让你操作物理地址吧,因为windows出来时候,就说访问物理地址是没有意义,
因为本身进程物理地址就可变,可搬移。你们说的windows地址实际上只是相对地址吧?

再研究研究。。。
---------------------------
物理地址可变化是为了虚拟内存的需要.这个操作系统基本都实现了.
逻辑地址可变化,这个在windows还没实现.
楼主的问题属于逻辑地址的问题.
test2002 2006-12-20
  • 打赏
  • 举报
回复
楼上你错了,这个不是linux的缺陷,而是新版本的linux做的一个改进。
windows实际上还没有这样,至少xp 不是,据微软的最新消息他们新版本的windows加入了这个功能,当然也不是特别新的消息。

------------------------------------------------------
哪里有介绍捏?好象windows中的地址都不是物理地址吧???
windows也不让你操作物理地址吧,因为windows出来时候,就说访问物理地址是没有意义,
因为本身进程物理地址就可变,可搬移。你们说的windows地址实际上只是相对地址吧?

再研究研究。。。
wd_6532 2006-12-20
  • 打赏
  • 举报
回复
那么,认为,既然是相同的程序运行,进程在虚拟地址空间中的分布应该是一摸一样的,局部数组的首地址那么也应该是同一个虚拟地址
==============
没有人保证这个。
sopro 2006-12-19
  • 打赏
  • 举报
回复
to: test2002(test2002)

http://community.csdn.net/Expert/topic/5235/5235454.xml?temp=.4043238
最后的几个回复(关于Address Space Layout Randomization),那个才是我要的答案

建议你先弄清楚进程的address space layout再说
test2002 2006-12-19
  • 打赏
  • 举报
回复
一个进程再虚拟地址空间的分布我大概是了解的。在kernel下面,也就是0xc000000地址之下应该是进程的stack(根据函数调用的情况动态变化)。那么,认为,既然是相同的程序运行,进程在虚拟地址空间中的分布应该是一摸一样的,局部数组的首地址那么也应该是同一个虚拟地址(当然,物理地址很可能不一样,但是进程看到的应该只能是虚拟地址)

----------------------------------------------------------------
你要看为什么栈地址改变,看你的程序,只输出一次,你肯定在不同的进程中比较了,当然地址不同是正常的。

你在同一个进程中比较 看看,程序修改如下:

int main()
{
char* p;
for(int i=0;i<10;i++)
{
p = func();
cout << hex << reinterpret_cast<int>(p) << endl; //以16进制输出p的地址
}
}

看看每次输出是否一致!!!
test2002 2006-12-19
  • 打赏
  • 举报
回复
靠,都没说到点子上

char* func()
{
char cArray[] = "123456";
return cArray;
}

-----------------------
cArray这个字符数组,是局部变量。

每次程序运行的时候,局部变量由于分配在栈上的,而这个栈是动态改变的,应此,栈地址是动态改变的,当然每次运行分配的地址是不一样的阿,所以楼主每次输出的这个地址(野地址)是不一样的,有什么奇怪的!!!
playmud 2006-12-19
  • 打赏
  • 举报
回复
楼上你错了,这个不是linux的缺陷,而是新版本的linux做的一个改进。
windows实际上还没有这样,至少xp 不是,据微软的最新消息他们新版本的windows加入了这个功能,当然也不是特别新的消息。
test2002 2006-12-19
  • 打赏
  • 举报
回复
这句话本身没错,不过,从你回帖的上下文以及你举的例子来看,你理解错了。根据网友给出的解释,2.4内核之前如果运行这个程序,每次返回的地址是一样的。2.6内核之后,返回的地址不一样,你知道是什么原因么?
根据其他网友的解释,2.4内核中,对每个进程来说,不管这个进程运行了多少次,在地址空间的布局都是一样的,因此返回的地址是一样的。很明显(我以为),你认为就算是同一个进程,只要是不同的运行,在栈中的内存布局是不一样的。
现在返回的地址不一样的原因是安全性考虑的原因,而不是你当初理解的理由。
你这样算不算是错误的理解凑巧导致了正确的答案?

--------------------------------------------------------------
是的,linux以前版本的缺陷。
实际上编译原理已经解释得很清楚了,就是进程运行空间,时间的不可逆性。也就是说相同的程序,运行的轨迹不可重复性,当然包括运行空间的不可逆性了。

实际上windows也是一直这样的,他的物理地址也是变化的,如果是没有变化,只是逻辑上没有变化而已,而且windows进程是可重定位的,不确定的,可由操作系统随时搬移的。
sopro 2006-12-19
  • 打赏
  • 举报
回复
--------------
实际上地址改变,还是因为不同的进程的运行造成的,难道我说错了吗??
--------------
这句话本身没错,不过,从你回帖的上下文以及你举的例子来看,你理解错了。根据网友给出的解释,2.4内核之前如果运行这个程序,每次返回的地址是一样的。2.6内核之后,返回的地址不一样,你知道是什么原因么?
根据其他网友的解释,2.4内核中,对每个进程来说,不管这个进程运行了多少次,在地址空间的布局都是一样的,因此返回的地址是一样的。很明显(我以为),你认为就算是同一个进程,只要是不同的运行,在栈中的内存布局是不一样的。
现在返回的地址不一样的原因是安全性考虑的原因,而不是你当初理解的理由。
你这样算不算是错误的理解凑巧导致了正确的答案?


如果我误解了你,向你道歉。回帖的时候态度确实恶劣了点,sorry,sorry
大家共同进步吧,都是为了学习
test2002 2006-12-19
  • 打赏
  • 举报
回复
地址每次都在变化才是正常的,因为最新的linux发行版中加了入防止缓冲区溢出的诸多措施,运行时的启动地址是变化的,这样就可以避免猜测缓冲区溢出地址的可能,还有其它几种方法,如设置stack区和data区不可执行等,具体可以参考secure enhanced linux

------------------------------------
实际上地址改变,还是因为不同的进程的运行造成的,难道我说错了吗??

不要一来就说 “建议你先弄清楚进程的address space layout再说”,

我说的不同进程是同样程序运行多次(你这例子不是关了程序,然后再运行比较地址的吗?)

你在一个程序中调用10次,看看地址改了没有??

没搞懂别人什么意思就...





playmud 2006-12-19
  • 打赏
  • 举报
回复
原来如此,我说怎么2.4内核没这种情况呢,原来为了安全作了一些改动.
长知识了.
TinyAnt 2006-12-18
  • 打赏
  • 举报
回复
你在什么系统下运行这程序?有没有调试工具,跟踪下char* func()应该可以得出答案。
TinyAnt 2006-12-18
  • 打赏
  • 举报
回复
楼主知道cArray是野指针啦,只是想知道为什么cArray返回随机值
xiaodong_ustb 2006-12-18
  • 打赏
  • 举报
回复
char* func()
{
char cArray[] = "123456";
return cArray;
}
野指针呀,局部变量是在栈内分配内存空间,当程序从func函数退出时,系统回收该内存空间,所有你返回的指针所指向的空间系统可以分配给其它函数使用,所以你打印出的东西每次都不一样,这是很危险的,如果那个地方正好放着你的100万银行账户,你给它改成0,嘿嘿.....
playmud 2006-12-18
  • 打赏
  • 举报
回复
//test.c
#include <stdio.h>
void func()
{
int i=10;
printf("%x\n",&i);
}
int main()
{
func();
return 0;
}
playmud 2006-12-18
  • 打赏
  • 举报
回复
2.6内核对进城的进城空间布局变化不小,2.4内核不会出现这种情况。
应该和操作系统的进程调用相关
Andrionda 2006-12-18
  • 打赏
  • 举报
回复
return cArray; 程序有错误!
char cArray[] = "123456"; 是存在于函数得临时栈区,函数反馈回来得时候,该存储区已经释放掉了,return反馈回来得东东很随机得!
加载更多回复(5)
这是一门linux下c++通讯架构实战课程,针对c/c++语言已经掌握的很熟并希望进一步深造以将来用c++在linux下从事网络通讯领域/网络服务器的开发和架构工作。这门课程学习难度颇高但也有着极其优渥的薪水(最少30K月薪,最高可达60-80K月薪),这门课程,会先从nginx源码的分析和讲解开始,逐步开始书写属于自己的高性能服务器框架代码,完善个人代码库,这些,将会是您日后能取得高薪的重要筹码。本课程原计划带着大家逐行写代码,但因为代码实在过于复杂和精细,带着写代码可能会造成每节课至少要4~5小时的超长时间,所以老师会在课前先写好代码,主要的时间花费在逐行讲解这些代码上,这一点望同学们周知。如果你觉得非要老师领着写代码才行的话,老师会觉得你当前可能学习本门课程会比较吃力,请不要购买本课程,以免听不懂课程并给老师差评,差评也会非常影响老师课程的销售并造成其他同学的误解。 这门课程要求您具备下面的技能:(1)对c/c++语言掌握的非常熟练,语言本身已经不是继续学习的障碍,并不要求您一定熟悉网络或者linux;(2)对网络通讯架构领域有兴趣、勇于挑战这个高难度的开发领域并期望用大量的付出换取高薪;在这门课程中,实现了一个完整的项目,其中包括通讯框架和业务逻辑框架,浓缩总结起来包括如下几点:(1)项目本身是一个极完整的多线程高并发的服务器程序;(2)按照包头包体格式正确的接收客户端发送过来的数据包, 完美解决收包时的数据粘包;(3)根据收到的包的不同来执行不同的业务处理逻辑;(4)把业务处理产生的结果数据包正确返回给客户端;本项目用到的主要开发技术和特色包括:(1)epoll高并发通讯技术,用到的触发模式是epoll中的水平触发模式【LT】;(2)自己写了一套线程池来处理业务逻辑,调用适当的业务逻辑处理函数处理业务并返回给客户端处理结果;(3)线程之间的同步技术包括互斥量,信号量等等;(4)连接池中连接的延迟回收技术,这是整个项目中的精华技术,极大程度上消除诸多导致服务器程序工作不稳定的因素;(5)专门处理数据发送的一整套数据发送逻辑以及对应的发送线程;(6)其他次要技术,包括信号、日志打印、fork()子进程、守护进程等等;

23,124

社区成员

发帖
与我相关
我的任务
社区描述
Linux/Unix社区 应用程序开发区
社区管理员
  • 应用程序开发区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧