web-dev-qa-db-ja.com

C mallocアサーションエラーが発生するのはなぜですか?

分割統治多項式アルゴリズムを実装しているため、OpenCL実装に対してベンチマークを実行できますが、mallocが機能しません。プログラムを実行すると、たくさんのものを割り当て、いくつかのことをチェックして、size/2アルゴリズムに。それからmalloc行をもう一度押すと、これが吐き出されます:

malloc.c:3096:sYSMALLOc:アサーション `(old_top ==(((mbinptr)(((char *)&((av)-> bins [((1)-1)* 2]))-__builtin_offsetof(struct malloc_chunk、fd)))))&& old_size == 0)|| ((unsigned long)(old_size)> =(unsigned long)((((__ builtin_offsetof(struct malloc_chunk、fd_nextsize))+((2 *(sizeof(size_t)))-1))&〜((2 *(sizeof (size_t)))-1)))&&((old_top)-> size&0x1)&&((unsigned long)old_end&pagemask)== 0) 'は失敗しました。中止

問題の行は次のとおりです。

int *mult(int size, int *a, int *b) {
    int *out,i, j, *tmp1, *tmp2, *tmp3, *tmpa1, *tmpa2, *tmpb1, *tmpb2,d, *res1, *res2;
    fprintf(stdout, "size: %d\n", size);

    out = (int *)malloc(sizeof(int) * size * 2);
}

fprintfでサイズを確認しましたが、正の整数です(通常はその時点で50)。 mallocも普通の番号で呼び出してみましたが、それでもエラーが発生します。私は何が起こっているかに困惑しており、これまでのところ私が見つけたGoogleからの助けは何もありません。

何が起こっているのでしょうか?コンパイラエラーである場合に備えて、新しいGCCをコンパイルする方法を見つけようとしていますが、実際には疑っています。

69
Chris

メモリが破損している可能性が99.9%(バッファのオーバーフローまたはアンダーフロー、解放後のポインタへの書き込み、同じポインタで2回freeと呼ばれるなど)

Valgrind でコードを実行して、プログラムがどこか間違ったことをした場所を確認します。

83

whyの理解を深めるために、@ r-samuel-klatchkoの回答を少し拡張したいと思います。

mallocを呼び出すとき、実際に起こっていることは、単にメモリの塊を与えて遊ぶよりも少し複雑です。内部では、mallocは、与えられたメモリに関するハウスキーピング情報(最も重要なのはそのサイズ)も保持しているため、freeを呼び出すと、メモリの量などを把握できます。自由。通常、この情報は、mallocによってメモリロケーションが返される直前に保持されます。より包括的な情報を見つけることができます インターネット™上 ですが、(非常に)基本的な考え方は次のようなものです:

+------+-------------------------------------------------+
+ size |                  malloc'd memory                +
+------+-------------------------------------------------+
       ^-- location in pointer returned by malloc

これに基づいて(そして大幅に簡素化して)mallocを呼び出すとき、利用可能なメモリの次の部分へのポインタを取得する必要があります。これを行うための非常に簡単な方法の1つは、前のメモリのビットを調べて、sizeバイトをメモリ内でさらに下(または上)に移動することです。この実装では、p1p2、およびp3を割り当てた後、次のようなメモリになります。

+------+----------------+------+--------------------+------+----------+
+ size |                | size |                    | size |          +
+------+----------------+------+--------------------+------+----------+
       ^- p1                   ^- p2                       ^- p3

だから、あなたのエラーの原因は何ですか?

まあ、あなたが割り当てたメモリの量を超えてコードが誤って書き込むことを想像してください(問題のように必要よりも少ない量を割り当てたか、コードのどこかで間違った境界条件を使用しているためです)。コードがp2に大量のデータを書き込み、p3sizeフィールドの内容を上書きし始めたとします。次にmallocを呼び出すと、返された最後のメモリ位置を確認し、そのサイズフィールドを確認し、p3 + sizeに移動して、そこからメモリの割り当てを開始します。ただし、コードはsizeを上書きしているため、このメモリの場所は以前に割り当てられたメモリの後ではなくなります。

言うまでもなく、これは大混乱を引き起こす可能性があります!したがって、mallocの実装者は、多くの「アサーション」またはチェックを行い、それらが発生する場合、これ(および他の問題)をキャッチするために多数の健全性チェックを試行します。あなたの特定のケースでは、これらのアサーションに違反しているため、mallocが中止され、コードが本当にすべきでないことをしようとしていたことがわかります。

前述のように、これは非常に単純化しすぎていますが、ポイントを説明するには十分です。 mallocのglibc実装は5k行以上であり、適切な動的メモリ割り当てメカニズムを構築する方法についてかなりの量の研究が行われているため、すべてをSO答えは不可能です。うまくいけば、実際に何が問題を引き起こしているのかを少し理解できるでしょう。

61
Jon Gjengset

Valgrindを使用する私の代替ソリューション:

友達がプログラムをデバッグするのを手伝っただけなので、とてもうれしいです。彼のプログラムには、GDBからの同じエラーメッセージで、この正確な問題(malloc()がアボートを引き起こす)がありました。

Address Sanitizer を使用して彼のプログラムをコンパイルしました

_gcc -Wall -g3 -fsanitize=address -o new new.c
              ^^^^^^^^^^^^^^^^^^
_

そして_gdb new_を実行しました。プログラムが後続のmalloc()で引き起こされたSIGABRTで終了すると、多くの有用な情報が出力されます:

_=================================================================
==407==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6060000000b4 at pc 0x7ffffe49ed1a bp 0x7ffffffedc20 sp 0x7ffffffed3c8
WRITE of size 104 at 0x6060000000b4 thread T0
    #0 0x7ffffe49ed19  (/usr/lib/x86_64-linux-gnu/libasan.so.4+0x5ed19)
    #1 0x8001dab in CreatHT2 /home/wsl/Desktop/hash/new.c:59
    #2 0x80031cf in main /home/wsl/Desktop/hash/new.c:209
    #3 0x7ffffe061b96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96)
    #4 0x8001679 in _start (/mnt/d/Desktop/hash/new+0x1679)

0x6060000000b4 is located 0 bytes to the right of 52-byte region [0x606000000080,0x6060000000b4)
allocated by thread T0 here:
    #0 0x7ffffe51eb50 in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.4+0xdeb50)
    #1 0x8001d56 in CreatHT2 /home/wsl/Desktop/hash/new.c:55
    #2 0x80031cf in main /home/wsl/Desktop/hash/new.c:209
    #3 0x7ffffe061b96 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21b96)
_

出力、特にスタックトレースを見てみましょう。

最初の部分では、_new.c:59_に無効な書き込み操作があります。その行は

_memset(len,0,sizeof(int*)*p);
             ^^^^^^^^^^^^
_

2番目の部分は、不正な書き込みが発生したメモリが_new.c:55_に作成されることを示しています。その行は

_if(!(len=(int*)malloc(sizeof(int)*p))){
                      ^^^^^^^^^^^
_

それでおしまい。私の友人を数時間混乱させたバグを見つけるのに、たった30分もかからなかった。彼はなんとか失敗を突き止めましたが、失敗したのは後続のmalloc()呼び出しであり、以前のコードでこのエラーを見つけることができませんでした。

まとめ:GCCまたはClangの_-fsanitize=address_を試してください。メモリの問題をデバッグするときに非常に役立ちます。

7
iBug

どこかに割り当てられたメモリを超えてオーバーランしている可能性があります。その後、mallocを呼び出すまで、基礎となるswはそれを取得しません。

Mallocによってキャッチされているガード値が破壊されている可能性があります。

編集...境界チェックのヘルプのためにこれを追加しました

http://www.lrde.epita.fr/~akim/ccmp/doc/bounds-checking.html

2
pbernatchez

あなたと同じような次のメッセージが表示されました。

 
プログラム:malloc.c:2372:sysmalloc:アサーション `(old_top ==((((mbinptr)(((char *)&((av)-> bins [((1) -1)* 2]))-__builtin_offsetof(struct malloc_chunk、fd)))))&& old_size == 0)|| ((unsigned long)(old_size)> =(unsigned long)((((__ builtin_offsetof(struct malloc_chunk、fd_nextsize)))+((2 *(sizeof(size_t)))-1))&〜((2 *(sizeof (size_t)))-1)))&&((old_top)-> size&0x1)&&((unsigned long)old_end&pagemask)== 0) 'failed。
 

Mallocを使用する際に、以前に何らかのメソッド呼び出しを間違えました。符号なしchar配列にフィールドを追加する際にsizeof()-operatorの後に係数を更新するときに、乗算記号「*」を誤って「+」で上書きしました。

私の場合のエラーの原因となるコードは次のとおりです。

 
 UCHAR * b =(UCHAR *)malloc(sizeof(UCHAR)+5); 
 b [INTBITS] =(一部の計算); 
 b [ BUFSPC] =(一部の計算); 
 b [BUFOVR] =(一部の計算); 
 b [BUFMEM] =(一部の計算); 
 b [MATCHBITS] =(一部計算);

後で別の方法で、mallocを再度使用すると、上記のエラーメッセージが生成されました。呼び出しは(十分に単純な)でした:

 
 UCHAR * b =(UCHAR *)malloc(sizeof(UCHAR)* 50); 
 

最初の呼び出しで「+」記号を使用すると、誤算が発生し、アレイの即時初期化(アレイに割り当てられていないメモリの上書き)がmallocのメモリマップに混乱をもたらします。 したがって、2回目の呼び出しは失敗しました。

2

Sizeof(int)で乗算するのを忘れたため、このエラーが発生しました。 malloc(..)の引数はバイト数であり、マシンワードの数などではないことに注意してください。

1
Phob

Linux上で1つのアプリケーションをVisual Cからgccに移植しましたが、同じ問題が発生しました

malloc.c:3096:sYSMALLOc:UBUNTU 11でgccを使用したアサーション。

同じコードを(他のコンピューター上の)Suseディストリビューションに移動しましたが、問題はありません。

問題はプログラムにあるのではなく、独自のlibcにあるのではないかと思います。

0
JMH

同じ問題が発生しました。新しいchar * stringデータを追加するためのループで、mallocをn回以上使用しました。私は同じ問題に直面しましたが、割り当てられたメモリを解放した後 void free() 問題がソートされました

0
namila007