我已经搜索过但找不到任何结果(我的术语可能已关闭),请原谅我,如果以前曾经问过这个问题。我可能使用了错误的搜索关键字。
我理解如何使用vtable来处理指针上的虚函数调用,特别是当“免费使用”漏洞发挥作用时。 但是,假设你有一个指向myclass的指针,并且当myfunction未虚拟实现时你调用函数myfunction? 根据一点读数,有一个较少的获取,IE而不是获取函数的地址,然后获取函数,然后调用,它是直接获取。
如果在使用之前释放了指向myclass的指针,那么让我感到困惑的是如何工作。 编辑:上一段不清楚,我试图弄清楚可能会出现什么样的未定义行为。
任何人都可以为我清除这个吗?如果我的问题不清楚,我会澄清......
CodeLion
编辑:
MyClass *myclass;
free(myclass);
myclass->DoSomething();
Declaration of DoSomething()
void DoSomething{...} // NOT virtual void DoSomething
答案 0 :(得分:6)
简短的回答是未定义的行为。
长期答案基于典型的C ++实现。
对于非virtual
方法,该方法基本上是一个带有额外参数的函数,该参数自动传递,称为this
:通常也使用非典型调用约定,但这并不重要
因此foo->method()
变为Foo::method(foo)
,传递错误(已释放)foo
就像传递任何其他错误/已释放的参数一样。
依赖于此是一个坏主意,因为如果您使用无效的this
来调用非virtual
方法,编译器可以随意使用。
答案 1 :(得分:2)
这是因为函数的地址在编译时是已知的,因为它不可能是其他任何东西。而对于虚函数,它需要使用vtable来确定在运行时调用哪个函数。
如果指向调用该方法的对象的指针的内存已经被释放,那么它只是未定义的行为,就像它是一个虚函数调用一样,因为指针不指向My的实例类。
答案 2 :(得分:1)
让我对OP的问题作出不同的解释。
如果DoSomething是虚函数,那么
myclass->DoSomething () ; // Should be my object
要求编译器生成检查我的类的对象引用的代码,并确定在运行时调用哪些DoSomething。如果myclass已被删除
delete myclass ;
然后,此查找期间的行为未定义,并且转换过程本身提供了一个失败点。
如果DoSomething是非虚函数,那么这不需要编译器实现一个过程来确定在运行时调用哪个DoSomething。编译可能使用完全相同的过程与虚函数一起使用,但这不是严格必要的。假设编译器不为运行时查找生成代码,执行类似
的操作 CALL MyClass_DoSomething
然后这不会为myclass引用的未定义对象提供失败点。但是,该方法需要知道哪个对象称为它。编译器可能会将此作为参数执行,执行类似于代码的操作:
MOV EAX, myclass
CALL MyClass_DoSomething
或
PUSH myclass
CALL MyClass_DoSomething
对该对象的引用具有未定义的,不确定的行为。