C ++如何处理指针上的非虚函数调用?

时间:2014-05-25 21:23:49

标签: c++ function pointers

我已经搜索过但找不到任何结果(我的术语可能已关闭),请原谅我,如果以前曾经问过这个问题。我可能使用了错误的搜索关键字。

我理解如何使用vtable来处理指针上的虚函数调用,特别是当“免费使用”漏洞发挥作用时。 但是,假设你有一个指向myclass的指针,并且当myfunction未虚拟实现时你调用函数myfunction? 根据一点读数,有一个较少的获取,IE而不是获取函数的地址,然后获取函数,然后调用,它是直接获取。

如果在使用之前释放了指向myclass的指针,那么让我感到困惑的是如何工作。 编辑:上一段不清楚,我试图弄清楚可能会出现什么样的未定义行为。

任何人都可以为我清除这个吗?如果我的问题不清楚,我会澄清......

CodeLion

编辑:

MyClass *myclass;
free(myclass);
myclass->DoSomething();

Declaration of DoSomething()
void DoSomething{...} // NOT virtual void DoSomething

3 个答案:

答案 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

对该对象的引用具有未定义的,不确定的行为。