堆栈异常处理和析构函数展开。如何使用这些信息

时间:2016-03-25 23:22:55

标签: c++ exception gcc

在我的程序中,我有一个垃圾收集器,我需要跟踪哪些对象保存在我的程序中的局部变量上,以避免在它们存活时进行垃圾收集。

虽然我使用了创建复合类型的链表,但我刚刚意识到C ++语言必须保留该链表,因为它自己的析构函数目的尤其与异常处理有关。

所以我想通过使用C ++异常处理程序保存的信息来简化我的代码。有可行的方法吗?

如果没有关于g ++和clang的信息?

顺便说一下,当我使用多任务处理时,我应该能够为每个任务执行此操作(这些正在等待垃圾收集器运行时)。

我真正需要的是遍历具有析构函数设置的局部变量(并以非破坏性方式执行)。

2 个答案:

答案 0 :(得分:0)

这就是析构函数的用途。如果您需要知道某个对象(无论是在堆上还是堆栈上)何时超出范围,那么您将使用析构函数。

答案 1 :(得分:0)

通过检查gnu gcc编译器发出的代码,我发现有关执行哪些析构函数的信息以代码形式“保存”,代码知道它必须要破坏它并处理它。因此,重新获得这些信息太难了。

实现可能有所不同,代码可能已作为返回地址推送到处理器堆栈中,析构函数代码的地址以及结构实例的地址。

所以我准备放弃努力,但我找到了另一条骇客的路线。

我注意到gnu编译器在16字节的边界上对齐堆栈上的结构。 由于我的结构是8个字节,因此还有8个未使用的字节。 所以我认为我可以使用它们来跟踪堆栈上分配的对象。 必须要说的是,根据编译标志为-m64,-mx32的内容会发生变化,必须加以修改。

我设法让代码编译并在-m64和-mx32模式下工作。

它不是纯粹的“C ++”(恰恰相反),但代码有效并具有预期的效果。

#include <stdio.h>

#define ONSTACK(x) (((size_t)x)&0xf0000000)==0xf0000000
struct A;
void* P=nullptr;

struct A{
    static int i;
    long long a;
    A(){
        if(ONSTACK(this)){
            *(void**)(this+1)=P;
            P=(void*)(this+1);
        }
        printf("this=%p\n",this);
        a=0x1111111111111111*i;i++;
    }
    ~A(){
        if(ONSTACK(this))
            P=*(void**)(this+1);
            *(void**)(this+1)=nullptr;
        a=0xFFFFFFFFFFFFFFFF;}
};

int A::i=0xA;
void* p;

void r1(){
    A x;int xx=0x66666666;
    A y;int yy=0x77777777;
    A z;int zz=0x88888888;
    int b=0x2222222222222222;
    printf("hello world %p\n",&b);

    for(void* i=P;i!=nullptr;i=*(void**)i){
        printf("a=%llX\n",(((A*)i)-1)->a);
    }
}

void r2(){
    long long r2a;
    r2a=0x3333333333333333;
    r1();
}

A A0;

int main(int argc, char **argv)
{   int i;p=(char*)&i-0x100;
    printf("sizeof(P)=%i\n",sizeof(P));
    r2();
}