ヒープマネージャーがそこから割り当てられないように、メモリのセグメントを「境界外」としてマークすることは可能ですか?
-
28-09-2019 - |
質問
今日、私は尋ねました この質問.
この問題の調査に時間を費やした後、私は何が起こっているのかを発見しました。私はこれを新しい質問として投稿しています。なぜなら、それは別の問題として追跡するのに十分な面白いと思うからです。その質問を答え(およびこれへのリンク)で更新します。
デバッガーからユニットテストを開始します
// Construct object
Object* pObject = new Object(...);
// Pointer value of pObject == 0x05176960
// Lots of other code
// ...
// Destroy object
delete pObject;
// Construct object again
pObject = new Object(...);
// Pointer value of pObject == 0x05560194 /* Different memory location */
コマンドラインからユニットテストを起動します
// Construct object
Object* pObject = new Object(...);
// Pointer value of pObject == 0x05176960
// Lots of other code
// ...
// Destroy object
delete pObject;
// Construct object again
pObject = new Object(...);
// Pointer value of pObject == 0x05176960 /* Same memory location */
要約すれば:
- からユニットテストを開始するとき コマンドライン, 、後続の呼び出し
new
ANを割り当てるにはObject
(delete
以前にObject
新しいものを割り当てる前に)は常に戻ります 同じ メモリ内のアドレス。 - からユニットテストを開始するとき デバッガ, 、後続の呼び出し
new
ANを割り当てるにはObject
(delete
以前にObject
新しいものを割り当てる前に)は常にaを返します 個性的 メモリ内のアドレス。
問題は、の割り当てのためです Object
コマンドラインを介して起動するときは、常にメモリ内で同じアドレスを取得します。 年 ポインターは引き続き使用でき、テストはクラッシュしません。しかし、欠陥の修正が整っていないときにユニットテストをクラッシュさせて、静かに失敗し、欠陥が戻ってこないようにしたいと考えています。
私の質問には2つの部分があります。
ヒープマネージャーは、コマンドラインからユニットテストを開始するときにメモリの同じ部分を再利用するのはなぜですか?
テストハーネスで使用できるコンパイラ設定、またはヒープマネージャーが削除したメモリのセクションを再利用しないようにするために呼び出す方法はありますか? 1
1明らかにこれを行う1つの方法は、元のオブジェクトを削除しないことですが、これを私の制作コードに割り当てるコードの部分は、これを行うとメモリリークが発生します。
解決
未定義の動作に依存しているため、ユニットテストには欠陥があります。未定義の動作に依存しないように、ユニットテストを書き直す必要があります。その場合、メモリマネージャーがメモリの割り当てを決定する方法に関係なく、常に合格します。
あなたがしていることはこれです:
Object* pObject = new Object(...);
...
delete pObject;
pObject = new Object(...);
// Use dangling pointer to first object, and if it crashes, the unit test fails
// This is WRONG since a crash isn't guaranteed
代わりに、ユニットテストを再構築して、次のように機能します。
Object* pObject = new Object(...);
...
// Check to see if there are dangling references to pObject right before we
// delete it. If there are, assert() and fail the unit test.
assert(NoDanglingReferences(pObject));
delete pObject;
// Continue on with more tests
他のヒント
交換できます new
と delete
あなたが望む動作を持つあなた自身のバージョンで。
まず第一に - 「通常の」メモリマネージャーではありません。メモリを扱うと、メモリの所有権をメモリマネージャーに渡すと、後者はそれを再利用できます。
あなたは出来る カスタムマネージャーを書きます なので ユーザーアンドレアスブリンク 提案しますが、それは何をしますか?それは空気からメモリを作成するのではなく、CRTヒープやオペレーティングシステムのヒープのようなどこかからそれを要求します。
シナリオA.メモリは基礎となるヒープに戻りません。リークがあり、メモリブロックは引き続きアドレス空間にマッピングされ、アクセス可能になります。
シナリオB.メモリは下にあるヒープに戻ります。その後、マネンガーが再びメモリを割り当てようとすると、下にあるヒープが再びそのブロックを返すことができます。また、メモリを返すときに、基礎となるヒープが何をするかわかりません。マッピングされていないかどうかにかかわらない可能性があります。そのため、そのメモリにアクセスすることはクラッシュするかどうかです。
一番下の行はあなたがねじ込まれていることです。未定義の動作をテストしようとすることは、あまり生産的ではありません。
これは未定義の動作の例です。 C ++もヒープマネージャーも、メモリの割り当て方法を定義しません。どちらのメモリも再利用されているか、再利用されないことに頼ることはできません。上記のようなことをするとき、返されたポインターが最初の割り当てとは異なるかどうかを判断または変更する方法はありません。