2016-07-07 22 views
-2

いくつかのゲームスクリプトファイルを逆コンパイルするためのプログラムを作成しています。私が追加した最新の部分は、動的配列を扱う際にいくつかのエラーを出すことです。これは、問題のあるコードです:deconstructorのヒープ破損

私は技術的にサイズがこの中に0であるため、エラーが、参照配列とされて起こると考え
anim.name = 0x06BB 
anim.numOfReferences = 0x0000 
anim.numOfAnimReferences = 0x0001 
anim.null1 = 0x0000 

:ここ

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); 
} 

がフィールドに読み込まれているものですインスタンス。しかし、私はそれについて何をすべきか分からず、ヒープの破損についても一般的にはかなり失われています。

+3

(。あなたは、プログラムがあまりにも他のバグを持っていることに注意してください)と 'のstd :: vector'を使用しています。 – Barmar

+5

多くの 'if(membervar)delete [] membervar'ステートメントがあります。これらはすべて、変数が割り当てられていない場合はnullにデフォルト設定されていますが、初期化するコンストラクタは表示されません。 – Barmar

+1

これはC++なので、 'typedef struct'の必要はありません。これは 'C'からのホールドオーバーであり、C++では不要です。 – PaulMcKenzie

答えて

2

_COD9_USEANIM_1は(初心者は、このような恐ろしい名前を使用する理由それらを変数に_Z_ASHD532___8AHQ_ ??のようなものを呼び出すようにするために、なぜああ??それは楽しいです)二つの配列(なぜベクトル??)、referencesanim_referencesを持っています。ポインタがゼロでない場合、配列を解放するデストラクタがあります。 コンストラクタはありません。これは危険です。最低でも、referencesanim_referencesを0に初期化するコンストラクタを提供する必要があります。コピーコンストラクタも必要です。ルールを覚えておいてください。あなたが3つのうちの1つ(デフォルトのコンストラクタ、デストラクタ、コピーコンストラクタ)を提供するならば、ほぼ確実に3つすべてが必要です。

今、あなたのループはあなたが最後にあなたがそれをコピーしてreferencesanimReferences

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

を割り当てる変数anim

_COD9_USEANIM_1 anim; 

を宣言ループで

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

を起動し、[OK]を〜tstg.usingAnim

tstg.usingAnim[i] = anim; 

コピーするとどうなりますか?すべてのフィールドがコピーされました。だから今referencesanimReferenceststg.usingAnim[i]referencesanimReferencesと同じアドレスを指しています。

そして、ブロックが終了します。邪悪なコンピュータはデストラクタをanimのために呼び出します。デストラクタはanim.referencesanim.animReferencesのdelete []を呼び出します。しかし、referencesanimReferenceststg.usingAnim[i]は同じアドレスを指しています。つまり、削除された配列を指しています。

これでヒープの動作が予測できなくなりました。

ベストプラクティス:配列を忘れて、ベクターを使用する。あなたは、標準ライブラリからstd::vectorを知っています。

次善の提案:デフォルトのコンストラクタとコピーコンストラクタを提供します。 (PS:!と代入演算子)

は、配列を使用して停止

+0

私はそれについても考えていませんでした。しかし、私はベクトルに入りたくないので、コピーコンストラクタをできるだけ早く調べます。それが動作しない場合は、私は選択肢がないと思う。明確にしていただきありがとうございます。 – user1425470

+1

3のルールは、**デフォルトコンストラクタ**、コピーコンストラクタ、およびデストラクタではありません。コピーコンストラクタ、デストラクタ、**代入演算子**のためのものです。 –

+1

それは本当です。しかし、この場合、デフォルトコンストラクタも実装する必要があります。 – user31264

関連する問題