在解构器中堆积腐败

时间:2016-07-07 20:23:27

标签: c++

我正在创建一个用于反编译某些游戏脚本文件的程序。我添加的最新部分在处理动态数组时给了我一些错误。这是违法的代码:

typedef struct _COD9_ANIMREF_1
{
    DWORD name;
    DWORD reference;
};

typedef struct _COD9_USEANIM_1
{
    WORD name; // offset of name
    WORD numOfReferences; // reference count
    WORD numOfAnimReferences; // reference count
    WORD null1; // always null
    DWORD* references = NULL; // dynamic array of references, amount = numOfReferences
    _COD9_ANIMREF_1* animReferences = NULL; // dynamic array of references, amount = numOfAnimReferences
    ~_COD9_USEANIM_1()
    {
        if (references)
            delete[] references;
        if (animReferences) // program officially breaks here, if continued causes heap corruption
            delete[] animReferences;
    }
};
typedef struct _COD9_WORK_1
{
    _COD9_GSC_1 Hdr;
    char* data = NULL;
    int* includes = NULL;               //done
    _COD9_USEANIM_1* usingAnim = NULL;  //not done, heap corruption
    _COD9_STRING_1* strings = NULL; //done
    _COD9_FUNC_1* functions = NULL; //done
    _COD9_EXTFUNC_1* extFunctions = NULL; //done
    _COD9_RELOC_1* relocations = NULL;  //done
    ~_COD9_WORK_1()
    {
        if (data)
            delete[] data;
        if (includes)
            delete[] includes;
        if (usingAnim)
            delete[] usingAnim;
        if (strings)
            delete[] strings;
        if (functions)
            delete[] functions;
        if (extFunctions)
            delete[] extFunctions;
        if (relocations)
            delete[] relocations;
    }
};
if (tstg.Hdr.numOfUsinganimtree)
{
    tstg.usingAnim = new _COD9_USEANIM_1[tstg.Hdr.numOfUsinganimtree];
    igsc.seekg(tstg.Hdr.usinganimtreeStructs);
    for (int i = 0; i < tstg.Hdr.numOfUsinganimtree; i++)
    {
        _COD9_USEANIM_1 anim;
        igsc.read(reinterpret_cast<char*>(&anim.name), sizeof(anim.name));
        igsc.read(reinterpret_cast<char*>(&anim.numOfReferences), sizeof(anim.numOfReferences)); // this is 0 in this instance
        igsc.read(reinterpret_cast<char*>(&anim.numOfAnimReferences), sizeof(anim.numOfAnimReferences));
        igsc.read(reinterpret_cast<char*>(&anim.null1), sizeof(anim.null1));
        anim.references = new DWORD[anim.numOfReferences]; // allocate 0 size array so theres something to delete
        if(anim.numOfReferences) // should not be entered
        {
            igsc.read(reinterpret_cast<char*>(&anim.references), (anim.numOfReferences*sizeof(DWORD))); // if numOfReference = 0, function should return
        }
        anim.animReferences = new _COD9_ANIMREF_1[anim.numOfAnimReferences];
        for (int ii = 0; ii < anim.numOfAnimReferences; ii++)
        {
            _COD9_ANIMREF_1 animref;
            igsc.read(reinterpret_cast<char*>(&animref.name), sizeof(animref.name));
            igsc.read(reinterpret_cast<char*>(&animref.reference), sizeof(animref.reference));
            anim.animReferences[i] = animref;
        }
        tstg.usingAnim[i] = anim;
        printf("anim: %d\n", i); // program reaches this
    }
    printf("Anims Done\n"); // program doesn't reach this
    ReorderUsingAnim(&tstg);
}

以下是字段中的内容:

anim.name = 0x06BB
anim.numOfReferences = 0x0000
anim.numOfAnimReferences = 0x0001
anim.null1 = 0x0000

我认为发生错误的地方是引用数组,因为在这种情况下技术上大小为0。但是我不知道该怎么办,而且我对于堆损坏一般都很丢失。

1 个答案:

答案 0 :(得分:2)

_COD9_USEANIM_1(为什么新手会使用这些可怕的名字?为他们调用类似_Z_ASHD532___8AHQ_的变量吗?)有两个数组(为什么不是向量?),referencesanim_references。它有一个析构函数,如果指针不为零,则释放数组。 但没有构造函数。这是危险的。至少,您应该提供一个构造函数,将它们referencesanim_references初始化为零。您还需要复制构造函数。记住规则:如果你提供三个中的一个(默认构造函数,析构函数,复制构造函数),你几乎肯定需要这三个。

好的,现在开始循环

for (int i = 0; i < tstg.Hdr.numOfUsinganimtree; i++)

在循环中声明变量anim

_COD9_USEANIM_1 anim;

您分配了referencesanimReferences

anim.references = new DWORD[anim.numOfReferences];
...
anim.animReferences = new _COD9_ANIMREF_1[anim.numOfAnimReferences];

最后将其复制到tstg.usingAnim

tstg.usingAnim[i] = anim;

你知道复制时会发生什么吗?所有字段都被复制。现在,references的{​​{1}}和animReferences指向与动画的tstg.usingAnim[i]references相同的地址。

然后,块结束。邪恶的计算机调用animReferences的析构函数。析构函数调用animanim.references的delete []。但是,anim.animReferences的{​​{1}}和references指向相同的地址。换句话说,他们现在指向被删除的数组。

现在堆的行为是不可预测的。

最好的建议:忘记数组,并使用向量。您知道,animReferences来自标准库。

第二个最佳建议:提供默认构造函数和复制构造函数。 (PS:和赋值运算符!)

(请注意,您的程序也可能有其他错误。)