munmap_chunk():不正なポインタとSegmentation faultのバグを解決。
最近のC++プロジェクトでは、ログにエラーが報告されないまま、プログラムが勝手に終了してしまうというバグに遭遇しました。返ってきたシステムエラーメッセージは次のようなものでした。
*** glibc detected *** . /a: munmap_chunk(): invalid pointer: 0x000000000c67eb28 ***
======= Backtrace: =========
/lib64/libc.so.6(cfree+0x166)[0x375d2729d6]
. /a[0x4c8ec3]
. /a[0x4ca65b]
. /a[0x4d7139]
. /a[0x4d7457]
. /a[0x4dc049]
. /a[0x4dc092]
. /a[0x4dc0d0]
. /a[0x4dc0ee]
/usr/lib64/libboost_thread.so.1.53.0[0x2b992b0ba114]
/lib64/libpthread.so.0[0x375de0673d]
/lib64/libc.so.6(clone+0x6d)[0x375d2d40cd]
======= Memory map: ========
00400000-005bd000 r-xp 00000000 08:03 2733788 /home/path/a/bin/a
007bd000-007bf000 rw-p 001bd000 08:03 2733788 /home/path/a/bin/a
0c5ba000-0c72e000 rw-p 0c5ba000 00:00 0 [heap]
410ce000-410cf000 ---p 410ce000 00:00 0
410cf000-41acf000 rwxp 410cf000 00:00 0
41acf000-41ad0000 ---p 41acf000 00:00 0
41ad0000-424d0000 rwxp 41ad0000 00:00 0
424d0000-424d1000 ---p 424d0000 00:00 0
424d1000-42ed1000 rwxp 424d1000 00:00 0
42ed1000-42ed2000 ---p 42ed1000 00:00 0
42ed2000-438d2000 rwxp 42ed2000 00:00 0
438d2000-438d3000 ---p 438d2000 00:00 0
438d3000-442d3000 rwxp 438d3000 00:00 0
442d3000-442d4000 ---p 442d3000 00:00 0
442d4000-44cd4000 rwxp 442d4000 00:00 0
44cd4000-44cd5000 ---p 44cd4000 00:00 0
44cd5000-456d5000 rwxp 44cd5000 00:00 0
456d5000-456d6000 ---p 456d5000 00:00 0
456d6000-460d6000 rwxp 456d6000 00:00 0
460d6000-460d7000 ---p 460d6000 00:00 0
460d7000-46ad7000 rwxp 460d7000 00:00 0
375ca00000-375ca1c000 r-xp 00000000 08:03 1660075 /lib64/ld-2.5.so
375cc1b000-375cc1c000 r--p 0001b000 08:03 1660075 /lib64/ld-2.5.so
375cc1c000-375cc1d000 rw-p 0001c000 08:03 1660075 /lib64/ld-2.5.so
375ce00000-375ce14000 r-xp 00000000 08:03 3265266 /usr/lib64/libz.so.1.2.3
375ce14000-375d013000 ---p 00014000 08:03 3265266 /usr/lib64/libz.so.1.2.3
375d013000-375d014000 rw-p 00013000 08:03 3265266 /usr/lib64/libz.so.1.2.3
375d200000-375d34e000 r-xp 00000000 08:03 1660080 /lib64/libc-2.5.so
375d34e000-375d54e000 ---p 0014e000 08:03 1660080 /lib64/libc-2.5.so
375d54e000-375d552000 r--p 0014e000 08:03 1660080 /lib64/libc-2.5.so
375d552000-375d553000 rw-p 00152000 08:03 1660080 /lib64/libc-2.5.so
375d553000-375d558000 rw-p 375d553000 00:00 0
375d600000-375d682000 r-xp 00000000 08:03 1660096 /lib64/libm-2.5.so
375d682000-375d881000 ---p 00082000 08:03 1660096 /lib64/libm-2.5.so
375d881000-375d882000 r--p 00081000 08:03 1660096 /lib64/libm-2.5.so
375d882000-375d883000 rw-p 00082000 08:03 1660096 /lib64/libm-2.5.so
375da00000-375da02000 r-xp 00000000 08:03 1660081 /lib64/libdl-2.5.so
375da02000-375dc02000 ---p 00002000 08:03 1660081 /lib64/libdl-2.5.so
375dc02000-375dc03000 r--p 00002000 08:03 1660081 /lib64/libdl-2.5.so
375dc03000-375dc04000 rw-p 00003000 08:03 1660081 /lib64/libdl-2.5.so
375de00000-375de16000 r-xp 00000000 08:03 1660087 /lib64/libpthread-2.5.so
375de16000-375e015000 ---p 00016000 08:03 1660087 /lib64/libpthread-2.5.so
375e015000-375e016000 r--p 00015000 08:03 1660087 /lib64/libpthread-2.5.so
375e0
3763200000-37632e6000 r-xp 00000000 08:03 3265297 /usr/lib64/libstdc++.so.6.0.8
37632e6000-37634e5000 ---p 000e6000 08:03 3265297 /usr/lib64/libstdc++.so.6.0.8
37634e5000-37634eb000 r--p 000e5000 08:03 3265297 /usr/lib64/libstdc++.so.6.0.8
37634eb000-37634ee000 rw-p 000eb000 08:03 3265297 /usr/lib64/libstdc++.so.6.0.8
37634ee000-3763500000 rw-p 37634ee000 00:00 0
3765c00000-3765c15000 r-xp 00000000 08:03 1660103 /lib64/libnsl-2.5.so
3765c15000-3765e14000 ---p 00015000 08:03 1660103 /lib64/libnsl-2.5.so
3765e14000-3765e15000 r--p 00014000 08:03 1660103 /lib64/libnsl-2.5.so
3765e15000-3765e16000 rw-p 00015000 08:03 1660103 /lib64/libnsl-2.5.so
3765e16000-3765e18000 rw-p 3765e16000 00:00 0
3dd5a00000-3dd7fd7000 r-xp 00000000 08:03 292898 /usr/lib/oracle/11.2/client64/lib/libclntsh.so.11.1
3dd7fd7000-3dd80d6000 ---p 025d7000 08:03 292898 /usr/lib/oracle/11.2/client64/lib/libclntsh.so.11.1
3dd80d6000-3dd826c000 rw-p 025d6000 08:03 292898 /usr/lib/oracle/11.2/client64/lib/libclntsh.so.11.1
3dd826c000-3dd8291000 rw-p 3dd826c000 00:00 0
3dd8400000-3dd8689000 r-xp 00000000 08:03 292897 /usr/lib/oracle/11.2/client64/lib/libnnz11.so
3dd8689000-3dd8788000 ---p 00289000 08:03 292897 /usr/lib/oracle/11.2/client64/lib/libnnz11.so
3dd8788000-3dd87ca000 rw-p 00288000 08:03 292897 /usr/lib/oracle/11.2/client64/lib/libnnz11.so
3dd87ca000-3dd87cc000 rw-p 3dd87ca000 00:00 0
2aaaaaaab000-2aaaac297000 rw-p 2aaaaaaab000 00:00 0
2b992a276000-2b992a29d000 rw-p 2b992a276000 00:00 0
2b992a2a6000-2b992a326000 r-xp 00000000 08:03 3265653 /usr/lib64/liblog4cplus-1.1.so.7
2b992a326000-2b992a525000 ---p 00080000 08:03 3265653 /usr/lib64/liblog4cplus-1.1.so.7
2b992a525000-2b992a52b000 rw-p 0007f000 08:03 3265653 /usr/lib64/liblog4cplus-1.1.so.7
2b992a52b000-2b992a52c000 rw-p 2b992a52b000 00:00 0
2b992a52c000-2b992a538000 r-xp 00000000 08:03 3265656 /usr/lib64/librabbitmq.so.1
2b992a538000-2b992a737000 ---p 0000c000 08:03 3265656 /usr/lib64/librabbitmq.so.1
2b992a737000-2b992a738000 rw-p 0000b000 08:03 3265656 /usr/lib64/librabbitmq.so.1
2b992a738000-2b992a76e000 r-xp 00000000 08:03 3265657 /usr/lib64/libSimpleAmqpClient.so.2
2b992a76e000-2b992a96d000 ---p 00036000 08:03 3265657 /usr/lib64/libSimpleAmqpClient.so.2
2b992a96d000-2b992a970000 rw-p 00035000 08:03 3265657 /usr/lib64/libSimpleAmqpClient.so.2
2b992a970000-2b992a971000 rw-p 2b992a970000 00:00 0
2b992a971000-2b992aabc000 r-xp 00000000 08:03 1432281 /usr/lib/oracle/11.2/client64/lib/libocci.so.11.1
2b992aabc000-2b992abbc000 ---p 0014b000 08:03 1432281 /usr/lib/oracle/11.2/client64/lib/libocci.so.11.1
2b992abbc000-2b992abc7000 rw-p 0014b000 08:03 1432281 /usr/lib/oracle/11.2/client64/lib/libocci.so.11.1
2b992abc7000-2b992abc8000 rw-p 2b992abc7000 00:00 0
2b992abc8000-2b992aca8000 r-xp 00000000 08:03 3131049 /usr/lib64/libiconv.so.2.5.0
2b992aca8000-2b992aea8000 ---p 000e0000 08:03 3131049 /usr/lib64/libiconv.so.2.5.0
2b992aea8000-2b992aeaa000 rw-p 000e0000 08:03 3131049 /usr/lib64/libiconv.s
ここにあるのは、たくさんの情報です
munmap_chunk(): invalid pointer
以上、"invalid pointer"と表示されました。いろいろ調べてみると、この問題は、ポインタが新しくなって、途中で変更され、deleteと呼ばれるようになったことが問題なのだろうと、おおよそ理解できました。
移動した部分をよく見ると、配列がnewで始まり、関数の最後でdelete[]オフする関数があり、その途中に、以下のような文章があります。
char *a = new char[300];
char b[30] = { 0 };
memset(a, 0, sizeof(Contect));
sprintf(b, "%u", temp->EventID);
OneClass oneClass;
a = const_cast<char *>(oneClass.mFunction(b).c_str());
boost::shared_ptr< std::string> buff(new std::string(a));
doSomething(buff);
delete[]a;
return 0;
もっと詳しく見る
<pre name="code" class="cpp">a = const_cast<char *>(oneClass.mFunction(b).c_str());
まず、この行はポインタaを変更しており、aの値自体も変わっています。
少なくとも配列への値の代入はmemcpyやsnprintf関数で行うべきでしょう。
また、このように直接これを実行してもオーバーフローする可能性があります。
そこで、char[]をstd::stringに置き換えることにしました。実際、char[]を使う必要はありませんし、変換することで複雑さとリスクが増えます。
そして、これで問題は解決です。
無効なポインタが消えました。Segmentation fault が発生し、プログラムが自己終了します。
gdbを直接実行したときの情報です。
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x40a00940 (LWP 28517)]
0x00000037632b76d2 in __gnu_cxx::__exchange_and_add(int volatile*, int) () from /usr/lib64/libstdc++.so.6
これは、直接的な情報が少ないため、常に悪名高い問題であり、これを直接見ることは、何の問題もない。
良い点は、gdbを使えば簡単にデバッグできることです。少なくとも、どこがどうなっているのか大体わかるので、それを変更しに行ったり、肉眼でいくつかのコードを自分でトラブルシュートしたりすることができます。
という場所を見ました。
log("u: , info: %s ", u, info.c_str());
これはログを書き出す行で、型が一致しない、uはunsigned int型、ここでは%uをミスしている、実際の効果はuを文字列として扱い、' \0' に行く、この文のシングルテストはパラグラフエラーとなる。
このコードの行が問題だとほぼ結論づけられるでしょう。出力ログは問題を突き止めるためのものでしたが、結果的にトラブルを引き起こしてしまいました。
セグメントエラーの後、まだgdbでデバッグ中。whereやbtコマンドを実行すると、一番内側のレベルから一番外側のレベルまで、数字が振られたメッセージがいくつか出力され、その中のいくつかのレベルでは、使い慣れた自分の関数がいくつか確認できます。
このメッセージは、エラーが関数内で発生したことを明確に指し示しています。さまざまな関数呼び出しの関係を考えると、自分の肉眼で見つけた行もその範囲内であることがわかるでしょう。もちろん、後々のことを考えると、まず間違いなく肉眼ではなくgdbを使うべきでしょう、何しろ運の要素がありますから。
その過程で、他の部分も修正されました。主に、いくつかの古いコードでchar[]を置き換えるために、確かにcスタイルの文字配列は良い選択ではなく、必要がなければ控えめに使用すべきです。
もちろん、すべてのブランチを隅々までテストする必要があることも教えてくれています。そうしないと、一見単純に見えることが、ひどくうまくいかないこともあるのです。
関連
-
エラー: 'xxx' は事前宣言と C++ ヘッダーファイルが互いに含まれているため、型名になりません。
-
C++コンパイルエラー:||error: ld returned 1 exit status|.
-
C++ - 文字列クラス超詳細紹介
-
C++プリントベクター
-
void* から char* への無効な変換」および「文字列定数から 'char*' への非推奨の変換」を解決 "
-
error: '&' トークンの前にイニシャライザーがあるはずです。
-
error: label 'xxxxxxx' [-fpermissive] にジャンプします。
-
C++ [エラー] 'std::string {aka std::basic_string<char>}' を 'char*' に変換できないエラー
-
C++ ダイナミックオープンスペース
-
[エラー]'cout' はこのスコープで宣言されていません。
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
C++のostreamの詳細な使用方法
-
コンパイルエラー: 制御が非ボイド関数の末尾に達する可能性がある
-
ソースファイルをコンパイルするとDev C++のランタイムエラーが発生し、コンパイルできない
-
C++] error: 'const xxx' を 'this' 引数として渡すと修飾子が破棄される [-fpermissive] [C++] error: 'const xxx' を 'this' 引数として渡すと修飾子が破棄される。
-
const char*' から `char*' への変換が無効な場合の対処法
-
[C++] 不完全な型へのメンバーアクセスエラー
-
sort(...)」への呼び出しに対応する関数がない、エラー
-
一意でないテーブル/エイリアス
-
抽象クラス型 "my class "のオブジェクトは使用できません 解決方法
-
c/c++の "undefined reference to "の解決法