3

私は非常に最小限のメモリ読み取りライブラリを構築して、そこからいくつかunsigned intの を読み取ろうとしました。ReadUnsignedIntただし、メソッドが戻りたいときに、「HEAP CORRUPTION DETECTED」というエラー メッセージが表示されます。

ヒープ破損が検出されました。CRT は、アプリケーションがバッファーの終了後にメモリに書き込んだことを検出しました。

私が読んだように、これは何かを二重に削除しようとするときの原因かもしれません。これは の誤った使用が原因である可能性がありますが、何が間違っているのstd::tr1::shared_ptrか特定できません。コードは次のとおりです (エラー処理は省略)。

unsigned int Memory::ReadUnsignedInt (unsigned int address) const {
    std::tr1::shared_ptr<byte> bytes = 
        this->ReadBytes(address, sizeof(unsigned int));
    return *((int*)bytes.get());
    // correct value (how to improve this ugly piece of code?)
}

std::tr1::shared_ptr<byte> Memory::ReadBytes (
    unsigned int address, int numberOfBytes) const
{
    std::tr1::shared_ptr<byte> pBuffer(new byte(numberOfBytes));
    ReadProcessMemory(m_hProcess.get(), (LPCVOID)address, 
        pBuffer.get(), numberOfBytes * sizeof(byte), NULL))
    return pBuffer;
}
4

4 に答える 4

4

MichaelとNaveenはどちらも、コードに同じ大きな欠陥を見つけましたが、唯一の欠陥ではありません。

shared_ptrdelete参照カウントがゼロになると、ポイントされたオブジェクトになります。

newこれは、 -によって割り当てられたオブジェクトのみを指定できることを意味しますnew[]

shared_ptr<vector<byte> >またはboost::shared_array<byte>代わりに使用することをお勧めします。

于 2009-10-14T16:51:22.847 に答える
2

問題は次のとおりです。

new byte(numberOfBytes)

これにより、numberOfBytes の値を持つ 1 バイトが割り当てられます。

あなたがしたい:

new byte[numberOfBytes]    

numberOfBytes の長さのバイト配列を割り当てます。

しかし、4 バイトしか読み取っていないことがわかっているのに、わざわざメモリを割り当てる必要はありません。スタック上の unsigned int のアドレスを渡すだけです。

于 2009-10-14T16:50:08.403 に答える
2

コードの基本的な問題はすでに指摘されています。しかし、それを見ると、なぜここで shared_ptr を使用するのか疑問に思っています。もし私がそれをしていたら、おそらく次のようなものを使うでしょう:

unsigned Memory::ReadUnsignedInt(unsigned address) { 
    unsigned ret;
    ReadProcessMemory(m_hProcess.get(), (void *)address, &ret, sizeof(ret), NULL);
    return ret;
}

std::vector<char> Memory::ReadBytes(unsigned address, int num) { 
    std::vector<char> ret(num);
    ReadProcessMemory(m_hProcess.get(), (void *)address, &ret[0], num, NULL);
    return ret;
}

次に、ReadUnsignedInt の代わりに、テンプレートを使用したくなるでしょう。

template <class T>
T Memory::Read(unsigned address) { 
    T ret;
    ReadProcessMemory(m_hProcess.get(), (void*)address, &ret, sizeof(ret), NULL);
    return ret;
}

テンプレート パラメーターの型を推測できるパラメーターを渡さないため、常に明示的に指定する必要があります。

int x = Read<int>(wherever);
char a = Read<char>(wherever);

別の方法は、宛先をパラメーターとして渡すことです。

template <class T>
Memory::Read(unsigned address, T &t) { 
    ReadProcessMemory(my_hProcess.get(), (void *)address, &t, sizeof(t), NULL);
};

次のように使用します。

Read(wherever, some_int);
Read(somewhere, some_long);

等々。

char のベクトルを返すことの非効率性について心配している場合は、おそらくすべきではありません -- VC++ (他のほとんどの最新のコンパイラと同様) には、「名前付き戻り値の最適化」と呼ばれるものがあります。これは、このような状況を意味します。結果を割り当てるベクトルへの非表示の参照を渡します。ReadBytes はそれを使用して、最終的にどこにデータを直接格納します。さらに言えば、合理的な最適化がまったくオンになっている場合、ReadBytes はほぼ確実にインライン関数になるため、関連するものは実際には何も「渡され」たり「返されたり」しません。

一方、このコードは古いコンパイラでは特にうまく機能しません。また、十分に古いコンパイラでは、メンバ テンプレート関数を使用するバージョンはおそらくコンパイルすらできません。ただし、適度に最新のコンパイラを使用している限り、寿命は良好です。

于 2009-10-14T17:48:02.740 に答える
0

new byte(numberOfBytes)私はそうあるべきだと信じていますnew byte[numberOfBytes]。それ以外の場合は、1バイトのみを割り当てます。答えを完成させるために、@ ephemientが示したように、ここではshared_ptrを使用できません。これdeleteは、必要な場所で実行されるためですdelete[]。このように行わないと、動作は未定義になります。

于 2009-10-14T16:50:59.433 に答える