malloc()を使用して割り当てられたメモリブロックのサイズを取得するにはどうすればよいですか? [複製]
-
05-07-2019 - |
質問
可能な重複:
入手方法Cのポインターからの配列のサイズ?
ありますプログラムでC ++配列のサイズを決定する方法はありますか?そうでない場合、なぜですか?
Cスタイル関数から割り当てられたメモリのチャンクへのポインタを取得します。 さて、デバッグの目的でどのように知るのは本当に興味深いでしょう このポインタが指す割り当てられたメモリブロックは大きいです。
盲目的にその境界を越えて走って例外を引き起こすよりもエレガントなものはありますか?
事前に感謝します、 アンドレアス
編集:
WindowsではVC ++ 2005を、LinuxではGCC 4.3を使用しています
EDIT2:
VC ++ 2005では _msize
があります
残念ながら、デバッグモードでは例外が発生します。...
EDIT3:
まあ。例外を除いて上記で説明した方法を試しましたが、動作します。 少なくとも私がデバッグし、呼び出しの直後にそれを保証している間 ライブラリ出口に対して、バッファ境界を越えて実行します。チャームのように機能します。
それは単にエレガントではなく、本番コードでは決して使用できません。
解決
標準ではありませんが、ライブラリにサイズを提供する msize()
関数がある場合。
一般的な解決策は、サイズと結果のメモリ範囲とともに各リクエストを記録する独自の関数で malloc
をラップすることです。リリースビルドでは、「実際の」に切り替えることができますmalloc
。
他のヒント
デバッグのために不愉快な暴力を気にしない場合は、#defineマクロを使用してmallocの呼び出しをフックし、最初の4バイトをサイズで解放してパディングできます。
の曲へ
void *malloc_hook(size_t size) {
size += sizeof (size_t);
void *ptr = malloc(size);
*(size_t *) ptr = size;
return ((size_t *) ptr) + 1;
}
void free_hook (void *ptr) {
ptr = (void *) (((size_t *) ptr) - 1);
free(ptr);
}
size_t report_size(ptr) {
return * (((size_t *) ptr) - 1);
}
then
#define malloc(x) malloc_hook(x)
など
Cランタイムライブラリはそのような機能を提供しません。さらに、意図的に例外を引き起こしても、ブロックの大きさはわかりません。
通常、この問題をCで解決する方法は、割り当てられたブロックのサイズを追跡する別の変数を維持することです。もちろん、これは時々不便ですが、一般に他に知る方法はありません。
Cランタイムライブラリは、割り当てられたブロックを照会できるヒープデバッグ関数を提供する可能性があります(結局、 free()
はブロックの大きさを知る必要があります)この種のものはどれも携帯できません。
gcc
および GNUリンカー
を使用すると、 malloc
#include <stdlib.h>
#include <stdio.h>
void* __real_malloc(size_t sz);
void* __wrap_malloc(size_t sz)
{
void *ptr;
ptr = __real_malloc(sz);
fprintf(stderr, "malloc of size %d yields pointer %p\n", sz, ptr);
/* if you wish to save the pointer and the size to a data structure,
then remember to add wrap code for calloc, realloc and free */
return ptr;
}
int main()
{
char *x;
x = malloc(103);
return 0;
}
およびコンパイル
gcc a.c -o a -Wall -Werror -Wl,--wrap=malloc
(もちろん、これはg ++でコンパイルされたc ++コード、および必要に応じて(マングルされた名前を使用して)new演算子でも動作します。)
実質的に、静的/動的にロードされたライブラリも __ wrap_malloc
を使用します。
いいえ。実装のドキュメントに記載されていない限り、境界をオーバーランするときに例外に依存することはできません。これは、プログラムを書くために本当に知る必要のないものの一部です。本当に知りたい場合は、コンパイラのドキュメントまたはソースコードを調べてください。
これを行うための標準C関数はありません。プラットフォームによっては、移植できない方法があるかもしれません-あなたはどのOSとCライブラリを使用していますか?
例外の呼び出しは信頼性が低いことに注意してください-あなたが持っているチャンクの直後に他の割り当てがあるかもしれないので、現在のチャンクの制限を超えてから長い間例外を受け取らないかもしれません。
Valgrindのmemcheck や GoogleのTCMalloc (ヒープチェッカー部分)は、この種のことを追跡します。
TCMallocを使用して、割り当てられた場所を示すヒーププロファイルをダンプするか、 SameHeap()。
部分的な解決策:Windowsでは、 PageHeap を使用して、割り当てられたブロック外のメモリアクセスをキャッチできます。
PageHeapは、Windowsカーネルに存在する代替メモリマネージャーです(NTの種類ですが、最近は他のバージョンを使用するべきではありません)。プロセス内のすべての割り当てを取得し、メモリページの最後に位置合わせされたメモリブロックを返します。その後、次のページにアクセスできなくなります(読み取り、書き込みアクセスなし)。プログラムがブロックの終わりを超えて読み書きしようとすると、お気に入りのデバッガーでキャッチできるアクセス違反が発生します。
入手方法:MicrosoftからWindows用デバッグツールパッケージをダウンロードしてインストールします: http://www.microsoft.com/whdc/devtools/debugging/default.mspx
GFlagsユーティリティを起動し、3番目のタブに移動して実行可能ファイルの名前を入力し、キーを押します。 [PageHeap]チェックボックスをオンにして、[OK]をクリックすると準備完了です。
最後のこと:デバッグが完了したら、GFlagsを再度起動し、アプリケーションのPageHeapを無効にすることを忘れないでください。 GFlagsはこの設定をレジストリ(HKLM \ Software \ Microsoft \ Windows NT \ CurrentVersion \ Image File Execution Options \)に入力するため、再起動しても保持されます。
また、PageHeapを使用すると、アプリケーションのメモリニーズが大幅に増加する可能性があることに注意してください。
希望することを行う方法は、アロケータを BE することです。すべてのリクエストをフィルタリングし、デバッグのためにそれらを記録すると、メモリが解放されたときに必要なものを見つけることができます。
さらに、プログラムの最後で、割り当てられたすべてのブロックが解放されたかどうかを確認し、解放されていない場合はリストすることができます。この種の野心的なライブラリは、マクロを介して FUNCTION および LINE パラメータを受け取り、メモリリークが発生している場所を正確に知ることができます。
最後に、MicrosoftのMSVCRTは、デバッグバージョンでメモリの問題を見つけるために使用できる多くの便利なツールを備えたデバッグ可能なヒープを提供します。 http://msdn.microsoft.com/en-us/library/bebs9zyz.aspx
Linuxでは、valgrindを使用して多くのエラーを見つけることができます。 http://valgrind.org/