Chinaunix

标题: 全局变量的地址为什么会改变? [打印本页]

作者: ytl    时间: 2010-01-22 21:43
标题: 全局变量的地址为什么会改变?
例如一个全局变量:

int global_int;

然后在某个函数中打印其地址

printf("addr = %p \n", &global_int);

发现在运行中global_int的地址会突然改变。 可能是什么原因?

[ 本帖最后由 ytl 于 2010-1-29 15:51 编辑 ]
作者: 南极苍蝇    时间: 2010-01-22 22:41
是不是..溢出了..
作者: prolj    时间: 2010-01-22 22:45
同一次运行中么?
作者: bluewaterray    时间: 2010-01-22 23:00
LZ信息太不全了
作者: daybreakcx    时间: 2010-01-22 23:10
同一次运行中地址是不会变的,楼主的意思是说多次运行中吧,那个倒是有可能
作者: prolj2    时间: 2010-01-22 23:40
“张总,是这样的,您在家里Ctrl+C,在这Ctrl+V是不行的”  (娱乐一下呵)
作者: liexusong    时间: 2010-01-22 23:48
我发现好像没有变啊!
作者: ytl    时间: 2010-01-23 00:51
原帖由 daybreakcx 于 2010-1-22 23:10 发表
同一次运行中地址是不会变的,楼主的意思是说多次运行中吧,那个倒是有可能


当然是同一次运行了!不然还说什么?
用printf打印出来地址变了,在dbx中看到的又是正常的,但是程序却coredump了,证明实际上是异常的
作者: pmerofc    时间: 2010-01-23 08:25
提示: 作者被禁止或删除 内容自动屏蔽
作者: drowndog    时间: 2010-01-23 15:50
LZ多提供点信息吧。
程序是多线程的还是单线程的?32位的还是64位的?操作系统?
打印出来的地址总共有几种?各是什么值?
是在程序的同一处答应的吗?
这个现象是在程序启动时出现的(然后导致启动失败)?还是在运行过程中发生的?

我初步怀疑可能有变量名的冲突,你在代码中检查一下,或者把变量改个名字试试看。
作者: ubuntuer    时间: 2010-01-23 16:16
原帖由 prolj2 于 2010-1-22 23:40 发表
“张总,是这样的,您在家里Ctrl+C,在这Ctrl+V是不行的”  (娱乐一下呵)

prolj2
作者: ytl    时间: 2010-01-23 23:21
原帖由 drowndog 于 2010-1-23 15:50 发表
LZ多提供点信息吧。
程序是多线程的还是单线程的?32位的还是64位的?操作系统?
打印出来的地址总共有几种?各是什么值?
是在程序的同一处答应的吗?
这个现象是在程序启动时出现的(然后导致启动失败)? ...


在for循环中打印变量的地址,每次循环到特定的次数时,变量的地址突然+1, 然后程序就core了。但是奇怪的是,在dbx中看变量的地址却是正确的!
程序肯定是有错误,问题是什么样的错误会导致全局变量的地址改变?还有dbx的print命令看到的地址为什么会与程序中printf打印出来的不同?
作者: koolcoy    时间: 2010-01-24 00:07
全局变量的地址是绝对不会改变的.
作者: pmerofc    时间: 2010-01-24 00:22
提示: 作者被禁止或删除 内容自动屏蔽
作者: ytl    时间: 2010-01-24 00:39
原帖由 pmerofc 于 2010-1-24 00:22 发表
会不会是printf实参的问题?
比如类型或参数个数不对


不会。因为程序确实core了,证明数值确实异常
作者: 群雄逐鹿中原    时间: 2010-01-24 01:32
原帖由 ytl 于 2010-1-23 23:21 发表

还有dbx的print命令看到的地址为什么会与程序中printf打印出来的不同


用我的推理给解释一下:
dbx凭什么得到一个变量,当然是凭地址了,那一个全局变量,dgx凭什么要得到一个变化的地址?
作者: starwing83    时间: 2010-01-24 05:14
你检查一下编译的汇编文件吧。理论上说,静态变量的地址是直接硬编码进code的,实在不行也是一个lea指令,你检查一下到底是怎么回事。
作者: ytl    时间: 2010-01-24 12:12
原帖由 starwing83 于 2010-1-24 05:14 发表
你检查一下编译的汇编文件吧。理论上说,静态变量的地址是直接硬编码进code的,实在不行也是一个lea指令,你检查一下到底是怎么回事。


既然静态变量的地址是直接硬编码进code的,难道是code被修改了?
作者: prolj    时间: 2010-01-24 12:22
全局变量的地址在编译时就是确定的,gcc再sb也不至于这么sb。
用错了吧,检查自己的代码吧。
作者: mik    时间: 2010-01-24 12:25
思维要开拓点,不要老往一处想。

如果,打印的结果真的是不同了,那说明,问题出在 printf() 这里

在程序的某一个地方,传给 printf() 的参数 &global_int 在栈里被修改了,或许就是栈溢出的结果。
作者: starwing83    时间: 2010-01-24 12:38
那一定是在传进参数以后,和printf实际做write(stdout, text)之前的事情了。可是这整个过程应该是由库函数来管,不可能溢出的吧?(除非printf地址以后又printf一个不对齐的数字,导致覆盖,可是这样是在传进去的时候就覆盖了,不可能突然改变,而是一开始就不正确)。又不可能是另外一个线程,因为线程有自己独立的栈(野指针总不会每次都凑巧刚刚改了哪个数字吧?),应该也不是系统内核的问题,因为好像大家都很少遇到这种错误。

LZ有没有出错的程序?贴一下吧,再说明一下硬件配置和操作系统
作者: 群雄逐鹿中原    时间: 2010-01-24 12:38
标题: 回复 #20 mik 的帖子
显然很可能溢出导致函数的返回地址错位, 然后 for循环变量++ 使用到 &global_int 的地址.
需要注意 printf 前后的函数调用情况.
作者: ytl    时间: 2010-01-24 18:28
原帖由 starwing83 于 2010-1-24 12:38 发表
那一定是在传进参数以后,和printf实际做write(stdout, text)之前的事情了。可是这整个过程应该是由库函数来管,不可能溢出的吧?(除非printf地址以后又printf一个不对齐的数字,导致覆盖,可是这样是在传进去 ...


AIX 4.1系统。程序是单线程的,大致如下

int global_int = 0;

for (int i = 0; ; i++)
{
      printf("addr = %p, value = %d\n", &global_int, global_int);
      global_int++;
      int_arr[global_int] = global_int;
      /* other codes */
}

每次都是循环到同一个次数时, global_int地址突然加1,导致global_int的值很大,从而int_arr[global_int]发生内存越界
作者: ytl    时间: 2010-01-24 18:31
原帖由 群雄逐鹿中原 于 2010-1-24 12:38 发表
显然很可能溢出导致函数的返回地址错位, 然后 for循环变量++ 使用到 &global_int 的地址.
需要注意 printf 前后的函数调用情况.


全局变量的地址应该是放在代码段的,代码段应该是read only的,怎么可能被修改呢?
作者: prolj    时间: 2010-01-24 19:18
谁说全局变量放在代码段的?基本常识都没有。
作者: ytl    时间: 2010-01-24 19:21
原帖由 prolj 于 2010-1-24 19:18 发表
谁说全局变量放在代码段的?基本常识都没有。


请自掌嘴巴20次!
作者: stephen_du    时间: 2010-01-24 19:23
标题: 我给的解答
你把那个全局变量volatile掉再试试。
你的for循环疯狂去访问那个变量编译器会做优化
也就是说并不是每次都从内存读,自然出问题,
至于全局变量的地址不会变。

[ 本帖最后由 stephen_du 于 2010-1-24 19:26 编辑 ]
作者: net_robber    时间: 2010-01-24 19:25
没有跳出条件的循环

  1. for(;;i++)
  2. {
  3.    OOXX[i];
  4. }
复制代码

作者: ytl    时间: 2010-01-24 19:26
原帖由 stephen_du 于 2010-1-24 19:23 发表
你把那个全局变量volatile掉再试试。
你的for循环疯狂去访问那个变量以及它的地址编译器会做优化
也就是说并不是每次都从原来位置读,自然出问题。


无论怎么优化也不应该出问题。如果优化出问题了,只能说编译器有问题
作者: stephen_du    时间: 2010-01-24 19:28
标题: 回复 #29 ytl 的帖子
建议你自己亲自做做试验再评论我的话ok?
作者: ytl    时间: 2010-01-24 19:28
原帖由 net_robber 于 2010-1-24 19:25 发表
没有跳出条件的循环

for(;;i++)
{
   OOXX;
}


这个不重要,还没到跳出循环的时候就出问题了
作者: ytl    时间: 2010-01-24 19:32
原帖由 stephen_du 于 2010-1-24 19:28 发表
建议你自己亲自做做试验再评论我的话ok?

早就试验过了: 去掉一部分代码就没问题了。所以看起来是程序本身的问题,编译器有问题的可能性很小
如果编译器没有问题,则无论怎么优化,printf输出的结果都应该是正确的
作者: stephen_du    时间: 2010-01-24 19:35
标题: 回复 #32 ytl 的帖子
不是说是编译器有bug,优化不是bug,
你去掉的是什么代码?
作者: ytl    时间: 2010-01-24 19:38
原帖由 stephen_du 于 2010-1-24 19:35 发表
不是说是编译器有bug,优化不是bug,
你去掉的是什么代码?


优化不会改变逻辑,否则就是bug了
去掉的都是一些执行不到的死代码
作者: stephen_du    时间: 2010-01-24 19:43
你理解我说的“访问过频的变量,程序会不从内存里面读取”的意思吗?
你工作中有我说的这个问题的经验吗?
算了,算我多管闲事。
作者: ytl    时间: 2010-01-24 19:52
原帖由 stephen_du 于 2010-1-24 19:43 发表
你理解我说的“访问过频的变量,程序会不从内存里面读取”的意思吗?
你工作中有我说的这个问题的经验吗?
算了,算我多管闲事。


你是否想验证编译器存在bug? 如果不是,你的出发点就错了!因为优化不应该改变逻辑
再说了,变量的地址跟是否从内存读取有关系吗?
如果你怀疑编译器有问题,那就另当别论了
作者: 群雄逐鹿中原    时间: 2010-01-24 20:17
原帖由 ytl 于 2010-1-24 18:31 发表
全局变量的地址应该是放在代码段的,代码段应该是read only的,怎么可能被修改呢?


这个问题不跟你争论, 不要忘了是 &global_int  突变, 而不是 global_int 不对.

贴完整的代码吧, 这里很多人10分钟之内能看出这个问题.
作者: ytl    时间: 2010-01-24 20:26
原帖由 群雄逐鹿中原 于 2010-1-24 20:17 发表


这个问题不跟你争论, 不要忘了是 &global_int  突变, 而不是 global_int 不对.

贴完整的代码吧, 这里很多人10分钟之内能看出这个问题.


代码前面贴了。完整的不可能,共几十个甚至上百个文件!
需要说明: &global_int变了,global_int自然就不对了,程序也就core了

[ 本帖最后由 ytl 于 2010-1-24 20:27 编辑 ]
作者: 群雄逐鹿中原    时间: 2010-01-24 20:28
标题: 回复 #38 ytl 的帖子
那几行代码显然不可能说明问题, 爱莫能助了
作者: ytl    时间: 2010-01-24 20:33
原帖由 群雄逐鹿中原 于 2010-1-24 20:28 发表
那几行代码显然不可能说明问题, 爱莫能助了


代码太多了,所以我想先了解下哪些方面的错误可能导致全局变量地址改变,然后再有针对性地分析代码
作者: 奇门遁甲-lu    时间: 2010-01-24 21:08
标题: re
是程序先core,然后你看到了错误的打印信息吧;
打死都不信全局变量地址会变
作者: ytl    时间: 2010-01-24 21:29
原帖由 奇门遁甲-lu 于 2010-1-24 21:08 发表
是程序先core,然后你看到了错误的打印信息吧;
打死都不信全局变量地址会变


用dbx单步执行可以看到,是先打印出地址,然后才core的
作者: liexusong    时间: 2010-01-24 22:38
贴代码吧LZ!
作者: ytl    时间: 2010-01-24 23:26
原帖由 liexusong 于 2010-1-24 22:38 发表
贴代码吧LZ!


前面有代码。太多,不能全贴
作者: prolj    时间: 2010-01-25 01:24
掌你大爷! 找不到问题所在?活该!
各位也不用给Y怀疑是编译器的问题了,就是Y自己写代码的基本功不行,犯一些低级错误。
作者: 群雄逐鹿中原    时间: 2010-01-25 01:30
标题: 回复 #45 prolj 的帖子
干吗这么激动?
作者: ytl    时间: 2010-01-25 02:23
标题: 回复 #45 prolj 的帖子
连别人说的是什么都没搞清楚, 你还能发现什么问题?
谁说是编译器的问题了?本来就是请大家从代码的角度出发给出可能的原因. 再次证明你根本不知道别人在说什么!
作者: beepbug    时间: 2010-01-25 07:33
题外话,举一个例子。
搞DOS控制系统的,常要做几个驻留程序。这类程序的运行过程:
启动时,和常规程序一样,占最低空闲空间。然后自举到高端,最高空闲区。
这个是整体搬家,代码、数据,一块走。
作者: sithui    时间: 2010-01-25 09:10
标题: 回复 #23 ytl 的帖子
你试着在没有问题的代码上面一点一点打开你屏蔽掉的代码看看加入哪些会引出问题。
凭直觉应该是某个地方的一个小疏忽造成的
作者: cppexplore    时间: 2010-01-25 09:28
1 编译器优化掉经常被访问的变量 而导致逻辑出错是很正常的,也不能算gcc的bug。
2 代码贴的不全 或者 没有把问题隔离出来,让别人从代码的角度想出问题在哪里, 是不可能的。
  任何的内存读写错误 都有可能造成这种错误。
3 楼主这个问题 不能valgrind吗?
作者: chinesedragon    时间: 2010-01-25 09:53
原帖由 prolj2 于 2010-1-22 23:40 发表
“张总,是这样的,您在家里Ctrl+C,在这Ctrl+V是不行的”  (娱乐一下呵)


作者: huangwei0413    时间: 2010-01-25 09:54
原帖由 ytl 于 2010-1-24 18:28 发表


AIX 4.1系统。程序是单线程的,大致如下

int global_int = 0;

for (int i = 0; ; i++)
{
      printf("addr = %p, value = %d\n", &global_int, global_int);
      global_int++;
      int_a ...



每次都循环到同一个数?是哪个值呢?
是不是对int_array赋值导致越界了?

另外,全局变量的地址肯定不会变,不管同一次运行还是多次运行,链接的时候就定了!
作者: prolj    时间: 2010-01-25 09:58
我呸! 这样的弱智问题老娘只有在大一的时候才犯的,不知道哪儿出轨了吧?o(∩_∩)o...哈哈,基本功很烂就别这么牛B,我来很确定的告诉大家,xlc绝对没有问题,就是lz开内存出轨了。
作者: hb12112    时间: 2010-01-25 10:14
原帖由 ytl 于 2010-1-24 18:31 发表


全局变量的地址应该是放在代码段的,代码段应该是read only的,怎么可能被修改呢?



全局变量啥时放到代码段了?还是先把基本功练扎实吧。

错就错了,别人给你指出问题还这么牛就不对了。
作者: LF_532    时间: 2010-01-25 10:17
原帖由 ytl 于 2010-1-24 19:21 发表


请自掌嘴巴20次!



全局变量是在数据段。
作者: prolj    时间: 2010-01-25 10:20
全局变量的地址
地址能说放在哪儿么?
你们家地址是“放在”哪儿的?
作者: versaariel    时间: 2010-01-25 10:23
LZ的意思是
int g_test = 0;
while(1)
{
    printf("%d",&g_test);
}
每次输出不一样?
作者: writer15    时间: 2010-01-25 10:25
标题是  变量的地址为什么会改变呢?
内容说的却是 全局变量。
可见楼主表达能力不行,或者说逻辑不严谨。。。。

还有楼主对你指出错误,你却别人自掌嘴巴? 什么态度。。。
全局变量的地址是固定的,但可能硬编码进汇编中,也就是说它的地址保存在代码断。
但是全局变量是保存在数据段的。


最后你想解决问题把代码都帖出来,或者反汇编上来吧,你看不出,不代码别人看不出。 牛人还是很多的。
作者: 老手    时间: 2010-01-25 10:44
lz说的变量的地址是不变的,这个很容易验证! 看起来变了那是printf造成的 , 而printf之所以产生这种现象当然是楼主造成的.
通常的可能是格式和类型没有匹配.
作者: ytl    时间: 2010-01-25 11:07
原帖由 prolj 于 2010-1-25 10:20 发表
全局变量的地址
地址能说放在哪儿么?
你们家地址是“放在”哪儿的?


看透了,你算是不能醒悟了!
作者: ytl    时间: 2010-01-25 11:09
原帖由 writer15 于 2010-1-25 10:25 发表
标题是  变量的地址为什么会改变呢?
内容说的却是 全局变量。
可见楼主表达能力不行,或者说逻辑不严谨。。。。

还有楼主对你指出错误,你却别人自掌嘴巴? 什么态度。。。
全局变量的地址是固定的,但可 ...


你也该自掌嘴巴!全局变量难道不是变量? 要是能在标题里说清楚还要内容干嘛?

[ 本帖最后由 ytl 于 2010-1-25 11:20 编辑 ]
作者: ytl    时间: 2010-01-25 11:11
原帖由 versaariel 于 2010-1-25 10:23 发表
LZ的意思是
int g_test = 0;
while(1)
{
    printf("%d",&g_test);
}
每次输出不一样?


某次输出不一样,比如第100万次
作者: ytl    时间: 2010-01-25 11:15
原帖由 hb12112 于 2010-1-25 10:14 发表



全局变量啥时放到代码段了?还是先把基本功练扎实吧。

错就错了,别人给你指出问题还这么牛就不对了。


你什么意思! 我说说自己的理解,怎么就牛了? 莫名其妙!
还有,您老人家视力有问题吧, “全局变量的地址”怎么能看成“全局变量”?一开始有人搞错还情有可原,讨论这么久了还犯这么低级的错误?

[ 本帖最后由 ytl 于 2010-1-25 11:18 编辑 ]
作者: versaariel    时间: 2010-01-25 11:21
别吵了,大家都是来学习的,呵呵
作者: ytl    时间: 2010-01-25 11:27
贴出全部代码是不现实的,因为代码有几十万行,而且没有哪一块看起来跟这个问题本身有紧密地关系
这里只是想请高手说说有哪些机制可能导致全局变量的地址改变,比如地址越界?还是堆栈溢出?而不是找出代码的具体问题
作者: ytl    时间: 2010-01-25 11:34
几点说明:
1. 应该不是printf参数的问题,因为接下来程序就core掉了,证明变量的内容变了,看起来应该是地址变化引起的
2. 但是dbx中看到的地址和内容都是正确的
3. 不排除内存访问越界导致的,如果是这种情况,请高手说说访问越界如何改变全局变量的地址?如果不是,可能的原因还有那些?
4. 地址改变可能只是个假象,可能是某些数据被破坏导致的。那么哪些数据结构(包括寄存器等)会影响全局变量的地址呢?
5. 亦或是地址根本没有改变,而是读写溢出导致printf参数没有正确传递?那么接下来的coredump还是无法解释!

[ 本帖最后由 ytl 于 2010-1-25 11:55 编辑 ]
作者: koolcoy    时间: 2010-01-25 13:19
全局变量不一定在数据段的,当然绝大多数情况下全局变量时在数据段的。

binutils中的ld支持链接脚本,通过自己写链接脚本就可以把全局变量放到代码段里面去。如果最终可执行程序是elf格式的,你甚至可以自己创立一个段,名字叫个global段啥的,专门用来放全局变量。

在多数linux下面,find /usr -type d -name ldscripts可以找到一个专门用来保存ld脚本的文件夹
作者: koolcoy    时间: 2010-01-25 13:29
标题: 回复 #66 ytl 的帖子
1. 全局变量的地址是不可能改变的。它的地址在链接或者装载的时候就已经确定了,也就是说你传给printf的参数实际上是个常量。跟printf("%p", 0x1234)这种差不多。
2. 你这个肯定是溢出或者野指针造成的。
3. 去搜一下你用的aix版本的函数调用的abi,看看printf的几个参数到底是怎么传的。然后在保存参数的那个内存地址设一个watch point,再gdb。程序溢出的时候你就可以看到到底是哪个地方溢出了。
4. 可以试一下purify

============================

ps,我不知道aix下面有没有gdb

[ 本帖最后由 koolcoy 于 2010-1-25 13:31 编辑 ]
作者: prolj    时间: 2010-01-25 13:33
标题: 回复 #68 koolcoy 的帖子
你给Y讲这些,凭他的智商是根本理解不了的,Y就认为Y的代码没问题,还硬扯上编译器,我都猜到是什么问题了。等Y自己醒悟吧,又不是我们自己的工作内容。
作者: ytl    时间: 2010-01-25 13:38
原帖由 prolj 于 2010-1-25 13:33 发表
你给Y讲这些,凭他的智商是根本理解不了的,Y就认为Y的代码没问题,还硬扯上编译器,我都猜到是什么问题了。等Y自己醒悟吧,又不是我们自己的工作内容。


你猜到了什么了?猜到我们在说什么了吧?
作者: ytl    时间: 2010-01-25 13:39
原帖由 koolcoy 于 2010-1-25 13:29 发表
1. 全局变量的地址是不可能改变的。它的地址在链接或者装载的时候就已经确定了,也就是说你传给printf的参数实际上是个常量。跟printf("%p", 0x1234)这种差不多。
2. 你这个肯定是溢出或者野指针造成的。:mrgr ...


90%是内存访问越界。问题是,内存越界怎么会使得全局变量的地址发生改变的?
作者: prolj    时间: 2010-01-25 13:47
现在都不明白我们在说什么,转行吧。
全局变量的地址没有变,是把一个变的东西当作全局变量的地址了。哎呀,就这个,哎呀,怎么连内存都不理解的人还写C啊?
我说了,智商在哪儿摆着呢,而且我从来不愿意正面回答这种弱智问题。要是再不能理解,唉,进这个帖子是我的错,永远不该指望能唱歌。
作者: 群雄逐鹿中原    时间: 2010-01-25 13:56
原帖由 ytl 于 2010-1-25 13:39 发表


90%是内存访问越界。问题是,内存越界怎么会使得全局变量的地址发生改变的?


什么叫 “全局变量的地址发生改变” ?
是CPU将全局变量的地址读出来放进寄存器,写到printf使用到的stack上。
你内存越界,可能造成函数返回地址或其他方式导致PC偏移那么一下,导致多执行那么一两行代码,
以致寄存器在写到printf 的stack上之前,被意外++了,于是你看到全局变量地址变了,你拿到的值也变了。其实都是障眼法。
作者: llsshh    时间: 2010-01-25 14:15
假设global_int地址发生变化,那么global_int的值有没有变化呢,得到的是原来的值么?
编译器应该没问题。
但不否定某些系统的内核是存在bug的。

[ 本帖最后由 llsshh 于 2010-1-25 14:16 编辑 ]
作者: koolcoy    时间: 2010-01-25 14:20
版主锁帖吧
作者: pmerofc    时间: 2010-01-25 14:23
提示: 作者被禁止或删除 内容自动屏蔽
作者: koolcoy    时间: 2010-01-25 14:35
标题: 回复 #73 群雄逐鹿中原 的帖子
你认为他看得懂么
作者: llsshh    时间: 2010-01-25 14:40
假定ytl老兄没有其他bug在代码里的话,可能ytl你中奖了。系统内核有bug被你测到了,你可以向系统提供商提bugissue,有奖励哦。

[ 本帖最后由 llsshh 于 2010-1-25 15:02 编辑 ]
作者: koolcoy    时间: 2010-01-25 14:47
建议某些人找本书看看一个C程序从代码到执行的各个步骤,最少熟悉这几步:编译,链接,装载,运行。在这几步中,编译器,连接器,装载器,内存,CPU,都在干啥。
作者: 老手    时间: 2010-01-25 15:00
原帖由 koolcoy 于 2010-1-25 14:47 发表
建议某些人找本书看看一个C程序从代码到执行的各个步骤,最少熟悉这几步:编译,链接,装载,运行。在这几步中,编译器,连接器,装载器,内存,CPU,都在干啥。 u ...


现在学C的人本来就少了 , 你再这样说会把剩下人全吓跑.

C的问题 , 就在C的层面解决 , 哪有那么多的事 !
作者: koolcoy    时间: 2010-01-25 15:05
标题: 回复 #80 老手 的帖子
爱学不学,没人学C了,让那些用C开发的公司都tmd倒闭
作者: 故哈    时间: 2010-01-25 17:38
我遇到过.  是因为其他地方溢出导致的.
作者: 松饼熊    时间: 2010-01-25 17:45
唯一能够想到的就是data段的其他地方溢出,而且一直溢到text段了。
存放于text段的内容被修改了?!
传说中的缓冲区溢出,一个string就可以让系统执行制定代码的事情可能让楼主遇到了。

在我这里,只有一些刚到手的很不成熟的开发板和OS能出现这种情况。
作者: ytl    时间: 2010-01-25 19:19
大致知道其中原理了
看来要搞明白具体细节,还是要研究汇编指令
作者: Alligator27    时间: 2010-01-26 02:47
全局变量的地址当然是不变的。既然楼主能够重复core dump, 那就很容易找到原因了。

你需要确定全局变量的地址是如何传给printf函数的,最简单的就是列出printf前面的十几条指令。找出第二个参数(GR4)是如何传出的。它应当来源于TOC (GR2)的对应条目,调入临时栈内存或寄存器(决定于优化选项)。如果是栈内存,可能被bug冲掉。

printf("addr = %p, value = %d\n", &global_int, global_int);
作者: on-fire    时间: 2010-01-26 10:41
AIX 4.1系统。程序是单线程的,大致如下

int global_int = 0;        /*如果是全局变量,应该定义在所有函数外边,这里未能体现出是个全局变量*/

for (int i = 0; ; i++)       /*死循环,暂时不知道退出条件。疑惑中。可能导致global_int越界超过int类型在该系统的最大值*/
{
      printf("addr = %p, value = %d\n", &global_int, global_int);
      global_int++;          /*基本不可能出现int_arr[0]的赋值,在死循环中有可能出现global_int超过int的最大值从而越界,产生不确定行为。最终可能导致global_int地址突然加1,导致global_int的值很大。*/
      int_arr[global_int] = global_int;
      /* other codes */
}

每次都是循环到同一个次数时, global_int地址突然加1,导致global_int的值很大,从而int_arr[global_int]发生内存越界

总的来说我认为不是编译器的问题,应该是编码不严谨而导致越界问题。硬把global_int的值从int可能扩展成为long(个人猜测)所以地址会变。

我是C语言的初学者,不对请指正。

[ 本帖最后由 on-fire 于 2010-1-26 10:44 编辑 ]
作者: 思一克    时间: 2010-01-26 10:42
编译器的问题不可能。就是越界等起到的破坏作用。
作者: ytl    时间: 2010-01-26 11:10
标题: 回复 #86 on-fire 的帖子
那只是示意代码,已确定发生问题时i和global_int的值都应该在有效的范围
作者: on-fire    时间: 2010-01-26 11:17
原帖由 ytl 于 2010-1-26 11:10 发表
那只是示意代码,已确定发生问题时i和global_int的值都应该在有效的范围


从您简略的示范代码中只能看出这样的问题,其它只能看真实的代码了。
作者: yuanbao2004    时间: 2010-01-26 11:58
AIX 4.1系统。程序是单线程的,大致如下

int global_int = 0;      
for (int i = 0; ; i++)      {
      printf("addr = %p, value = %d\n", &global_int, global_int);
      global_int++;         
      int_arr[global_int] = global_int;  ---这个int_arr,是在哪里定义的?局部变量么?初始大小是多少?建议去掉这一句再跑,跑到global_int超过了int最大值为止,应该是不会出现问题的。
      /* other codes */
}



这个代码本身很不严谨。
一个是死循环。
另外就是,int值不断增加,总会超出表示范围了。
超出范围之后,int_arr,global_int都会有问题。
int_arr的赋值,很容易造成野指针,后续行为不太好定义了。
可以贴出来int_arr的定义位置,方便分析。
作者: ytl    时间: 2010-01-26 15:31
楼上是谁家的宠物跑出来了?
作者: ytl    时间: 2010-01-26 15:32
原帖由 yuanbao2004 于 2010-1-26 11:58 发表
AIX 4.1系统。程序是单线程的,大致如下

int global_int = 0;      
for (int i = 0; ; i++)      {
      printf("addr = %p, value = %d\n", &global_int, global_int);
      global_int++;          ...


见88楼的解说
作者: jiangsheng84    时间: 2010-01-26 18:06
学习一下!
作者: shanwx    时间: 2010-01-26 18:36
调用printf的时候,global_int的地址是作为参数压入栈中的,循环导致溢出把栈上这个位置覆盖了,不是全局变量的地址变了。这么个简单问题连编译器bug都整出来了,去查一下函数调用时栈帧是怎么变化的不就清楚了。
作者: caravsapm70    时间: 2010-01-27 12:34
楼上的,你说这些没用。楼主可是认为全局数据是在代码段,read-only的。你觉得lz懂你说的啥吗。
作者: 奶茶dsk    时间: 2010-01-27 14:42
是的,楼上的,楼主明显新手,,基本概念都没搞清楚,,扯啥编译器bug,,
作者: ytl    时间: 2010-01-27 15:00
原帖由 caravsapm70 于 2010-1-27 12:34 发表
楼上的,你说这些没用。楼主可是认为全局数据是在代码段,read-only的。你觉得lz懂你说的啥吗。


第一个说这话的人,我让他自掌嘴巴20次;对于你,找块豆腐撞死算了...
搞不清楚变量与变量地址的区别不是你的错,出来丢人现眼就是你的不对了!
作者: ytl    时间: 2010-01-27 15:05
原帖由 奶茶dsk 于 2010-1-27 14:42 发表
是的,楼上的,楼主明显新手,,基本概念都没搞清楚,,扯啥编译器bug,,


马甲出来骂人了?
谁扯编译器bug?我是一直坚持不要往编译器bug上头想,倒是某些人偏往编译器上扯,又是优化,又是......最后反而倒打一耙,真是小丑!
作者: ytl    时间: 2010-01-27 15:22
标题: 回复 #97 奶茶dsk 和 #96 caravsapm70 的帖子
上面回复了你们后感到恶心!其实你们用的就是街头混混吵架的伎俩: 声大,重复,颠倒黑白!
令人痛心的是,如今这种混混也冒充C程序员了。。。。。。
作者: shanwx    时间: 2010-01-27 15:24
原帖由 ytl 于 2010-1-27 15:00 发表


第一个说这话的人,我让他自掌嘴巴20次;对于你,找块豆腐撞死算了...
搞不清楚变量与变量地址的区别不是你的错,出来丢人现眼就是你的不对了!

你真没救了。调用printf("addr = %p, value = %d\n", &global_int, global_int)的时候,栈底是返回地址,bp+4 放的是global_int的值,bp+8放的是global_int的地址,global_int值溢出覆盖了bp+8处的内容。你这水平也敢写C,胆儿够大的。

[ 本帖最后由 shanwx 于 2010-1-27 15:26 编辑 ]




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2