现在的位置: 首页 > 综合 > 正文

检测不了的错误(2) — 分析

2019年08月07日 ⁄ 综合 ⁄ 共 1607字 ⁄ 字号 评论关闭
为什么编译和运行时都不能检测到这个问题呢. 为什么一个空指针还能够调用对象的成员函数呢? 我们要看看汇编代码.

MyClass::Foo() 其实是一个全局函数, 在符号表中的名字是 "_ZN7MyClass2FooEv". 所以调用时并不需要通过对象指针. 不过在调用这个函数时,会传递对象指针进去.

函数的定义:

.globl _ZN7MyClass3FooEv
.type _ZN7MyClass3FooEv, @function
_ZN7MyClass3FooEv:
.LFB1442:
pushl %ebp
.LCFI4:
movl %esp, %ebp
.LCFI5:
subl $8, %esp
.LCFI6:
subl $8, %esp
pushl $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
subl $12, %esp
pushl $.LC0
pushl $_ZSt4cout
.LCFI7:
call _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
addl $20, %esp
pushl %eax
.LCFI8:
call _ZNSolsEPFRSoS_E
addl $16, %esp
leave
ret

函数的调用:

ptr = NULL;

ptr->Foo();

return 0;

对应的汇编

movl $0, -4(%ebp) ;; ptr = NULL;

subl $12, %esp ;; 通过堆栈进行参数传递,传入ptr. 不过Foo()没有用到它.
pushl -4(%ebp) ;;

call _ZN7MyClass3FooEv ;; ptr->Foo()
addl $16, %esp

movl $0, %eax ;; return 0
leave
ret

通过上面的分析,我们明白了为什么这个让人迷惑的语句可以通过编译和运行了.

如果Foo()访问对象的成员,那么肯定是会出错的. 因为Foo()需要使用传入的ptr,而ptr的值是NULL.

比如

void Foo()

{

cout






0
0

抱歉!评论已关闭.