ある変数へのポインタが与えられた場合、それが静的に割り当てられたか動的に割り当てられたかを確認する方法はありますか?
8 に答える
あなたのコメントから引用:
基本的に構造体を取り除くメソッドを作成しています。mallocされているかどうかに応じて、解放したいものへのポインタであるデータメンバーがあります。
正しい方法は、構造体に別のメンバーを追加することです: 解放関数へのポインターです。
静的割り当てと動的割り当てだけではありません。可能なアロケータはいくつかmalloc()
ありますが、そのうちの1 つにすぎません。
Unix ライクなシステムでは、次のようになります。
- 静的変数
- スタック上
- スタック上にあるが動的に割り当てられる (つまり
alloca()
) - で割り当てられたヒープ上
malloc()
- で割り当てられたヒープ上
new
- ヒープ上で、割り当てられた配列の途中
new[]
- ヒープ上で、割り当てられた構造体内
malloc()
- ヒープ上で、割り当てられたオブジェクトの基本クラス内
new
- で割り当て
mmap
- カスタムアロケータで割り当て
- 上記のいくつかの組み合わせやバリエーションを含む、さらに多くのオプション
Windows では、複数のランタイム、、、LocalAlloc
(簡単に作成できる複数のヒープを含む) などもあります。GlobalAlloc
HeapAlloc
使用したアロケータの正しい解放関数を使用して、常にメモリを解放する必要があります。したがって、メモリの割り当てを担当するプログラムの部分もメモリを解放するか、メモリを解放するコードに正しい解放関数 (またはその周りのラッパー) を渡す必要があります。
また、ポインターが常に特定のアロケーターで割り当てられるようにするか、アロケーターを自分で提供することで、問題全体を回避することもできます (メモリを割り当てる関数と、場合によってはメモリを解放する関数の形式で)。アロケーターを自分で提供する場合は、(タグ付きポインターなどの) トリックを使用して、静的割り当ても使用できるようにすることもできます (ただし、このアプローチの詳細についてはここでは説明しません)。
Raymond Chenのブログ投稿 (Windows 中心ですが、概念はどこでも同じです):モジュール境界を越えたメモリの割り当てと解放
ACEライブラリはこれをあらゆる場所で実行します。あなたは彼らがそれをどのように行うかをチェックすることができるかもしれません。一般的に、そもそもこれを行う必要はないでしょう...
ヒープ、スタック、および静的データ領域は一般に異なる範囲のメモリを占有するため、プロセスメモリマップを熟知していれば、アドレスを調べて、どの割り当て領域にあるかを判断できます。この手法は両方ともアーキテクチャです。コンパイラ固有であるため、コードの移植がより困難になります。
ほとんどの libc malloc 実装は、ブロックのサイズに関する情報と「マジック」値を含むフィールド (free() 呼び出しで使用される) を持つ各返されたメモリ ブロックの前にヘッダーを格納することによって機能します。この魔法の値は、ユーザーが割り当てられていないポインターを誤って削除する (またはユーザーによって上書きされたブロックを解放する) のを防ぐためのものです。これは非常にシステム固有であるため、libc ライブラリの実装を調べて、どのような魔法の値があったかを正確に確認する必要があります。
それがわかったら、指定されたポインターをヘッダーに戻してから、マジック値を確認します。
LD_PRELOADなどを使用して、mallocデバッガーのようにmalloc()自体にフックできますか?もしそうなら、あなたはすべての割り当てられたポインタのテーブルを保持し、それを使用することができます。そうでなければ、私にはわかりません。mallocの簿記情報を入手する方法はありますか?
標準機能ではありません。
mallocライブラリのデバッグバージョンには、これを行うための関数が含まれている場合があります。
そのアドレスを静的であることがわかっているものと比較し、それがどこから来るべきかを知っていれば、それが遠くにある場合にのみマロックされていると言うことができますが、そのスコープが不明である場合、それを本当に信頼することはできません。
1.) 持っているコードのマップ ファイルを取得します。
2.) 基盤となるプロセス/ハードウェア ターゲット プラットフォームには、通常、メモリの開始アドレス (スタック、ヒープ、global0、そのブロックのサイズ、そのメモリ ブロックの読み取り/書き込み属性) を示すメモリ マップ ファイルが必要です。
3.) 1.) で mao ファイルからオブジェクト (ポインター変数) のアドレスを取得した後、そのアドレスがどのブロックに該当するかを確認します。あなたはいくつかのアイデアを得るかもしれません。
=西暦