C mallocアサーションが失敗するのはなぜですか?


86

OpenCL実装に対してベンチマークできるように、分割統治多項式アルゴリズムを実装していますがmalloc、作業に取り掛かることができません。私がプログラムを実行すると、それはたくさんのものを割り当て、いくつかのものをチェックし、そしてsize/2アルゴリズムに送信します。それから私がmalloc再びラインを打つとき、それはこれを吐き出します:

malloc.c:3096: sYSMALLOc: Assertion `(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.
Aborted

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

サイズを、fprintfで確認しましたが、正の整数です(通常はその時点で50)。malloc普通の番号でもかけようとしましたが、それでもエラーが発生します。私は何が起こっているのか困惑しています、そして私がこれまでに見つけたグーグルからの何も役に立ちません。

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


問題は実際にはその前の行にあると思います。おそらくダブルフリー?
ミッチウィート2010年

プログラムの3行目:int * mult(int size、int * a、int * b){int * out、i、j、* tmp1、* tmp2、* tmp3、* tmpa1、* tmpa2、* tmpb1、* tmpb2 、d、* res1、* res2; fprintf(stdout、 "サイズ:%d \ n"、サイズ); out =(int *)malloc(sizeof(int)* size * 2);
クリス

回答:


100

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

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


1
修繕。Valgrindは間違いなく助けになりました。古いmatlabコードを間違って転記し、jを反復処理するforループがあり、その内部でj ++が実行され、書き込み中の配列が最も上書きされ、何らかの理由でmallocが失敗しました。助けてくれてありがとう!
クリス

Valgrindは、このエラーが発生したときに何が起こっていたかを把握するために必要なツールにすぎませんでした。言及してくれてありがとう。
alexwells 2012

78

これが発生する理由をよりよく理解するために、@ r-samuel-klatchkoの回答を少し拡張したいと思います。

を呼び出すとmalloc、実際に起こっていることは、単にメモリのチャンクを提供するよりも少し複雑です。内部では、malloc提供されたメモリに関するハウスキーピング情報(最も重要なのはそのサイズ)も保持しているため、電話をかけるとfree、解放するメモリの量などがわかります。この情報は通常、によって返されるメモリ位置の直前に保持されますmalloc。より網羅的な情報はinternet™で見つけることができますが、(非常に)基本的な考え方は次のようなものです。

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

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

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

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

前に述べたように、これは非常に単純化されすぎていますが、要点を説明するのに十分です。のglibcの実装はmalloc5k行を超えており、優れた動的メモリ割り当てメカニズムを構築する方法についてはかなりの量の研究が行われているため、SOの回答ですべてを網羅することは不可能です。うまくいけば、これにより、実際に問題を引き起こしている原因が少しわかります。


17

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

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

私はAddressSanitizerを使用して彼のプログラムをコンパイルしました

そして、実行しましたgdb newSIGABRT後続の原因でプログラムが終了すると、malloc()多くの有用な情報が出力されます。

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

最初の部分は、に無効な書き込み操作があることを示していnew.c:59ます。その行は

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

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

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


1
あなたは私の命を救った。
NateSymer20年

2

おそらくどこかで割り当てられたmemを超えてオーバーランしています。次に、mallocを呼び出すまで、基になるswはそれを取得しません

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

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

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


2

あなたのメッセージに似た次のメッセージが表示されました。

    プログラム: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) '失敗しました。

mallocを使用しているときに、以前にメソッド呼び出しを間違えました。符号なしchar配列にフィールドを追加する際に、sizeof()演算子の後の因数を更新するときに、乗算記号 '*'を '+'で誤って上書きしました。

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

    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番目の呼び出しは失敗しました。


0

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


0

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


-2

Linux経由でVisualCからgccに1つのアプリケーションを移植していましたが、同じ問題が発生しました。

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

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

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.