带有 2 个参数的 MSVC 析构函数

逆向工程 微信
2021-07-05 04:06:38

我正在反转一个我认为是用 MSVC 编译的程序。似乎每个 vtable 中的第一个条目是类的析构函数。但是,当我查看反汇编和反编译时,似乎析构函数都采用第二个参数,并且只有在第二个参数为非空时才释放对象的内存。

这第二个论点的目的是什么?我认为,如果它是一个析构函数,则应该始终销毁该类并释放其内存。那么为什么第二个参数可以禁止释放内存呢?

1个回答

这些包装器在具有虚拟析构函数的类中使用以涵盖两种情况:

  1. 确保operator delete在对象销毁后通过delete pClass;语句调用正确

  2. 删除通过new Class[N]语句中的表达式分配的数组delete [] class_array;以确保使用正确的项目删除正确数量operator delete并处理过程中的潜在异常

我的旧文章

当类有虚析构函数时,编译器会生成一个辅助函数——删除析构函数。它的目的是确保operator delete在销毁类时调用适当的删除析构函数的伪代码如下所示:

virtual void * A::'scalar deleting destructor'(uint flags)
{
  this->~A();
  if (flags&1) A::operator delete(this);
};

这个函数的地址被放置在 vftable 中,而不是析构函数的地址。这样,如果另一个类覆盖了虚拟析构函数,operator delete则将调用该类的。尽管在实际代码中operator delete很少被覆盖,因此通常您会看到对默认 delete() 的调用。

有时编译器也可以生成一个向量删除析构函数它的代码如下所示:

virtual void * A::'vector deleting destructor'(uint flags)
{
  if (flags&2) //destructing a vector
  {
    array = ((int*)this)-1; //array size is stored just before the this pointer
    count = array[0];
    'eh vector destructor iterator'(this,sizeof(A),count,A::~A);
    if (flags&1) A::operator delete(array);
  }
  else {
    this->~A();
    if (flags&1) A::operator delete(this);
  }
};

有关更多详细信息,另请参阅Visual C++ 的主要开发人员之一 Jan Gray 的C++:Under the Hood

我还建议您使用自定义运算符 new/delete 制作一些类并检查生成的代码。