记忆总是会慢慢褪去,所以让文字记住一切~
分类: C/C++
2014-10-27 14:13:54
前一段是时间一直比较忙,终于项目快GM了。来喘口气,分享之前遇到的一个问题。在公司开发产品,写完代码一般会进行Code Review。由于和我搭档的同事比较忙,所以review就没有去做(也许是对我写的代码足够放心~)。偶尔闲了下来,无聊翻看之前写的代码,忽然眼前一亮,一个函数的实现在某一条执行分支上会没有返回值。实际函数的原型应该具有返回值的。大体可简化如下的一个示例。
点击(此处)折叠或打开
如果忽略这样一个warning,或者编译器干脆没有提示,这样一段代码如果执行会发生什么呢?运行发现结果如下:
可以发现,当argc =0 时,get函数返回了1,那么这个1是哪里来的呢?我们看一下get函数的汇编代码:
可以看到第三行汇编指令sub $0x4, %esp将栈顶指针下移了4个字节,预留了4个字节的空间,其实际被用作临时保存返回值。可以看出:
1) 在正确返回时,其会将$ebp-0x4存放的值复制给eax寄存器(0x0804869c地址处指令),可以发现,最终eax存放的将是get函数返回给调用者的数据;
2) 当不能正确执行返回语句:从get(int)+22 -> get(int)+27 -> leave -> ret,此间eax寄存器没有被任何指令赋值,所以eax寄存器的值将保留其进入函数的值。
那么eax在进入函数之前它存放的值是哪里来的呢?
可以看出eax的内容取自ecx寄存器存放地址所指向的值,如下图所示,即在进入get函数之前,eax将被赋值为1。
其实ecx存放的即为main函数调用时参数的地址,接下来就不深究了,这跟整个函数的调用过程中的栈变化有很大的关系。
假设我们get函数没有参数传入,改为如下:
点击(此处)折叠或打开
那么运行结果会很不确定,因为eax寄存器的值此时也不是某一个传递参数的值
【结论】:当我们的函数在某一条分支上没有返回值时,eax 寄存器的值将作为返回值赋给函数调用者,而eax的值一般又与我们调用时提供的参数有关系,如果我们的函数没有提供参数,那么eax寄存器中的值就会很不确定,总之,如果漏掉了一个返回分支,隐含的bug会让程序在某一天突然崩溃的~
p.s. 本以为自己犯了一个很严重的错误,最后发现我查看的代码并非最终版本,中间由于修改代码逻辑产生了这样的一个片断(被check in 到代码库中了),原来是虚惊一场~。~