3

これは私にとっては非常に奇妙なことですが、プログラムを起動すると、予期しないランダムなセグメンテーション違反が発生します。動作する場合もあれば、クラッシュする場合もあります。Dev-C++のデバッガーは、ファイルの行を指し示します:stl_construct.h

/**
   * @if maint
   * Constructs an object in existing memory by invoking an allocated
   * object's constructor with an initializer.
   * @endif
   */
  template<typename _T1, typename _T2>
    inline void
    _Construct(_T1* __p, const _T2& __value)
    {
      // _GLIBCXX_RESOLVE_LIB_DEFECTS
      // 402. wrong new expression in [some_]allocator::construct
     -> ::new(static_cast<void*>(__p)) _T1(__value);
    }

ちなみに私はSTLを広範囲に使用しています。セグメンテーション違反の原因を検出するにはどうすればよいですか?役立つツールはありますか?このようなランダムなクラッシュにつながる可能性がある理由は何ですか。

編集:

私のプログラムは約5000行のコードを数えます。問題の原因がわからないので、助けを得るためにどのコードを表示する必要があるのか​​わかりません。デバッガーから得たのは、STLに関係しているということだけです。

編集:

ここに移動しましたCode::Blocks。これがコールスタックです。

#0 00464635 std::_Construct<std::pair<double const, int>, std::pair<double const, int> >(__p=0xb543e8, __value=@0x10) (C:/Program Files/CodeBlocks/MinGW/bin/../lib/gcc/mingw32/3.4.5/../../../../include/c++/3.4.5/bits/stl_construct.h:81)
#1 00462306 std::_Rb_tree<double, std::pair<double const, int>, std::_Select1st<std::pair<double const, int> >, std::less<double>, std::allocator<std::pair<double const, int> > >::_M_create_node(this=0x406fe50, __x=@0x10) (C:/Program Files/CodeBlocks/MinGW/bin/../lib/gcc/mingw32/3.4.5/../../../../include/c++/3.4.5/bits/stl_tree.h:367)
#2 00461DA7 std::_Rb_tree<double, std::pair<double const, int>, std::_Select1st<std::pair<double const, int> >, std::less<double>, std::allocator<std::pair<double const, int> > >::_M_clone_node(this=0x406fe50, __x=0x0) (C:/Program Files/CodeBlocks/MinGW/bin/../lib/gcc/mingw32/3.4.5/../../../../include/c++/3.4.5/bits/stl_tree.h:379)
#3 004625C6 std::_Rb_tree<double, std::pair<double const, int>, std::_Select1st<std::pair<double const, int> >, std::less<double>, std::allocator<std::pair<double const, int> > >::_M_copy(this=0x406fe50, __x=0x0, __p=0x406fe54) (C:/Program Files/CodeBlocks/MinGW/bin/../lib/gcc/mingw32/3.4.5/../../../../include/c++/3.4.5/bits/stl_tree.h:1029)
#4 00462A9D std::_Rb_tree<double, std::pair<double const, int>, std::_Select1st<std::pair<double const, int> >, std::less<double>, std::allocator<std::pair<double const, int> > >::_Rb_tree(this=0x406fe50, __x=@0xb59a7c) (C:/Program Files/CodeBlocks/MinGW/bin/../lib/gcc/mingw32/3.4.5/../../../../include/c++/3.4.5/bits/stl_tree.h:559)
#5 0045A928 std::map<double, int, std::less<double>, std::allocator<std::pair<double const, int> > >::map(this=0x406fe50, __x=@0xb59a7c) (C:/Program Files/CodeBlocks/MinGW/bin/../lib/gcc/mingw32/3.4.5/../../../../include/c++/3.4.5/bits/stl_map.h:166)
#6 0040B7E2 VehicleManager::get_vehicles_distances(this=0xb59a50) (C:/Program Files/CodeBlocks/MinGW/projects/AHS/VehicleManager.cpp:232)
#7 00407BDA Supervisor::IsMergeInstruction(id_vehicle=1) (C:/Program Files/CodeBlocks/MinGW/projects/AHS/Supervisor.cpp:77)
#8 00408430 CheckingInstructionsThread(arg=0x476100) (C:/Program Files/CodeBlocks/MinGW/projects/AHS/Supervisor.cpp:264)
#9 00413950 _glfwNewThread@4() (??:??)
#10 75A24911    KERNEL32!AcquireSRWLockExclusive() (C:\Windows\system32\kernel32.dll:??)
#11 00476100    std::__ioinit() (??:??)
#12 0406FFD4    ??() (??:??)
#13 76E5E4B6    ntdll!RtlInitializeNtUserPfn() (C:\Windows\system32\ntdll.dll:??)
#14 00476100    std::__ioinit() (??:??)
#15 70266582    ??() (??:??)
#16 00000000    ??() (??:??)

さらにいくつかの精度:

1/マルチスレッドアプリケーションです。2 /メソッド:get_vehicles_distances(); マップを返します。3 / IsMergeInstruction()によって呼び出されるまでに、マップが初期化されていない可能性があります。

編集:

どうやらセグメンテーション違反を引き起こしている行は次のとおりです:

vehicles_distances_.erase(vehicles_distances_.begin(), vehicles_distances_.end());

ここで、vehicles_distances_はマップです。この行はメソッドの一部です:VehicleManager :: MoveAllVehicles();

void VehicleManager::MoveAllVehicles() {

     vehicles_distances_.erase(vehicles_distances_.begin(), vehicles_distances_.end());

     vector<Vehicle>::iterator iter_end = VehicleManager::vehicles_.end();
     for(vector<Vehicle>::iterator iter = VehicleManager::vehicles_.begin();
     iter != iter_end; ++iter) {

          (*iter).MoveVehicle();

          vehicles_distances_[(*iter).get_vec_vehicle_position().y] = (*iter).get_id_vehicle();

     }

}

それの何が問題になっていますか?

編集:

map :: clear();を使おうとしました。map :: Erase();の代わりとして; しかし、同じ問題が発生します!

編集:

わかったと思います...スレッドがクリアされている間、vehicles_distances_を利用しようとしています..(?)

編集:

問題が解決しました!つまり、それはmap :: Erase();から来ていました。予想通り。<key, value>マップを更新できるように、ペアが反転された別のマップ変数を作成することで、問題を回避しました。(必要なキーは距離であり、距離は毎回変化するため一意ではありませんが、id_vehicleは一意であるためです!)最後に、私はそのマップを取得し、<key, value>再度反転して、各サイクルで再宣言できる元のマップに転送しました...

みんな、ありがとう !

4

13 に答える 13

10

まず、すべてを愛するために、まあ、愛らしいので、Dev-C++を使用しないでください。人々がどのようにしてそのがらくたにぶつかり続けるのかを知っていたらいいのにと思います。それは何もの間維持されていません、そしてそれが維持されたとしても、それはまだ非常に基本的な機能を欠いたバグのあるジャンクでした。それを捨てて、数え切れないほどのより良い無料の選択肢の1つに行きましょう。

さて、あなたの質問に移りましょう。あなたが以前に違法なことをしたので、あなたのプログラムはランダムにセグフォールトします。そうしないでください。;)

プログラムがどこかで範囲外に書き込むと、何かが起こる可能性があります。割り当てられていないページにヒットする可能性があります。その場合、セグメンテーション違反が発生します。または、プロセスに割り当てられたページの未使用のデータにヒットする可能性があります。その場合、実用的な効果はありません(後で適切に初期化され、最初の不正な書き込みを上書きしてから、そこから読み取ろうとしない限り) 、元の(無効な)値がまだ存在することを期待します。または、実際に使用されているデータにヒットする可能性があります。その場合、プログラムがそのデータを読み取ろうとすると、後でエラーが発生します。

データを読み取る場合も、ほぼ同じシナリオが存在します。運が良ければすぐにセグメンテーション違反が発生するか、未使用の初期化されていないメモリにアクセスしてガベージデータを読み取るか(後でそのデータが使用されるとエラーが発生する可能性があります)、メモリアドレスから読み取ることができます。すでに使用されています(これによりゴミも出ます)。

そうです、これらのエラーを見つけるのは難しいです。私ができる最善のアドバイスは、1)基本的な不変条件が維持されるようにコード全体にアサートを振りかけること、および2)プログラムをステップ実行し、すべてのステップで、そうでないアドレスに対して読み取りまたは書き込みを行っていないことを確認することです。 tはあなたのものです。

MSVCには、デフォルトで有効になっている安全なSCLオプションがあり、STLコードの境界チェックを実行します。これは、このようなエラーの発見に役立ちます。

GCCには同様のことを行うオプションがあると思います(ただし、デフォルトでは有効になっていません)。

セグフォールトは厄介です。人々がこのようなエラーに数回噛まれると、範囲外のメモリにアクセスすることを避けて、より規律を保つ傾向があります。:)

于 2009-05-21T17:56:42.340 に答える
6

問題を見つけるのに役立つ方法としてValgrindを試すことができます。あなたが質問に入れた行を考えると、あなたがヒープを破壊したか、スタックに問題があると推測する必要があります。

于 2009-05-21T17:50:39.073 に答える
6

明らかな質問は「_pとは何か」です。デバッガーでは、コールスタックを確認できるはずです。_pをたどって元に戻ります。正しいサイズであること、削除されていないこと、実際に存在していることを確認してください。

それが簡単ではない場合は、ランダムな(疑わしい)コードを機能するまでコメントアウトするか、戻って既知の機能するコピーと比較するという強引な方法が常にあります。

于 2009-05-21T17:51:35.970 に答える
2

これは非常に曖昧なので、答えることはほとんど不可能です。明らかな提案の1つは、すべての変数を初期化しているかどうかを確認することです。一部のコンパイラは、デバッグで初期化されていないものをゼロにし、リリースではそれを行わないため、ランダムで予期しない結果が発生します。

于 2009-05-21T17:51:11.430 に答える
2

プログラムの最初に使用_CrtSetDbgFlag()して、いくつかのヒープデバッグオプションを有効にすることができます。CRTデバッグヒープも参照してください。これは、メモリを使って悪いことをしている場所を追跡するのに役立つ場合があります。これは、MinGWコンパイラがデフォルトでリンクするMicrosoftのCランタイムで利用できます。代わりにGNUのCランタイムを使用している場合、このルートを使用することはできません。

于 2009-05-21T17:58:28.513 に答える
2

問題は、stl_construct.hよりもコードにある可能性がはるかに高くなります。ファイルはDev-C++のSTLディストリビューションの一部であると想定しています。stl_construct.hのテンプレートを使用してインスタンス化されたコードでセグメンテーション違反が発生している可能性がありますが、問題の根本的な原因は他の場所にあります。クラッシュ時にスタックトレースを取得することで、これを解決しようとします。スタックトレース内の各関数(特に新しく書き込まれた関数)について、コードを調べて、次のタイプの考えられるエラーを探してみてください。

  • 初期化されていない変数(特に配列アクセスに使用されるインデックス)
  • 解放または削除された後に使用されたメモリ。
  • 配列の境界外への配列アクセス
  • NULLをチェックせずに使用されるメモリ割り当て(nullを返さないため、newを使用しても問題ありません。例外がスローされます)
于 2009-05-21T17:59:22.707 に答える
2

あなたの説明と呼び出しスタックは、静的変数の初期化中にプログラムがクラッシュしていることを示唆しています。これはC++の一般的な落とし穴です。静的変数の初期化の順序を制御する簡単な方法はありません。

たとえば、プログラムにオブジェクトfooに依存するオブジェクトがある場合がありますbarfooただし、プログラムがコンストラクターを作成する前に、コンストラクターを呼び出している可能性がありますbar。それは悪いことであり、あなたが説明しているような問題を引き起こす可能性があります。(CheckingInstructionsThreadスレッドを生成する静的変数ですか?それが問題になる可能性があります。)

これを修正するには、プログラムの.cppファイルで静的変数(クラスの静的変数とグローバル変数を含む)、特にあるクラスタイプの変数を調べる必要がある場合があります。stderrにいくつかのトレースを書き込むようにコンストラクターを変更することは役立つ場合とそうでない場合があります。fprintfそうする場合ではなく、使用cerrしてください。

編集:それが静力学と関係があるかどうかわからない場合は、このような行を先頭に置いてみてくださいmain()

 fprintf(stderr, "main() entered\n");

これは、問題の原因として静的初期化を除外するものではありません。以前にクラッシュしなかったとしても、main()データ構造が正しく設定されていない可能性があります。ただし、fprintfにアクセスできない場合は、静的初期化が原因であることがわかります。

于 2009-05-22T04:12:22.640 に答える
1

コアファイルを使用してデバッガーを実行した後、スタックトレースから何がわかりますか?gdbを通常の方法で実行しますgdba.out

次に、コアファイルを調べます

コアa.out.core

そしてスタックを見てください

bt

于 2009-05-21T17:53:32.813 に答える
1

これはおそらく無効化されたイテレータに関連しています-コンテナを反復処理する場所を検索するか、イテレータをコンテナに保持し、同時に要素を削除/挿入します。
そして、他のみんなが指摘したように、正確な場所を見つけるためにコールスタックを使用してください。

于 2009-05-21T17:57:07.783 に答える
1

危険な機能のようです:)

しかし、1つのことが私を襲った。割り当てられたメモリはどこに行きますか?直感的には、最初の引数としてポインターへのポインターを設定し、それを逆参照したいと思います。このような:

template<typename _T1, typename _T2>
    inline void
    _Construct(_T1** __p, const _T2& __value)
    {

       ::new(static_cast<void*>(*__p)) _T1(__value);
    }

または、ポインタへの参照:

template<typename _T1, typename _T2>
    inline void
    _Construct(_T1*& __p, const _T2& __value)
    {

       ::new(static_cast<void*>(__p)) _T1(__value);
    }
于 2009-05-21T23:39:32.210 に答える
1

徹底的にテストされたコードにたどり着いたときに最初にやらなければならないことは、自分のコードにたどり着くまでコールスタックを上げることです。ここで、この問題の原因となった情報を見つけることができます。

呼び出しスタックで確認する最も重要な場所は、コード(呼び出し元)と、呼び出した関数(呼び出し先)に渡したパラメーターです。

この情報がなければ、私たちはあなたをこれ以上助けることはできません。;-)

セグメンテーション違反の詳細:http://en.wikipedia.org/wiki/Segmentation_fault
(必読、「関連項目」および「外部リンク」のリンクも参照)

于 2009-05-22T00:01:29.840 に答える
1

マップはスレッドフレンドリーではありません。スレッドコードでマップ操作を実行する場合は、実際にそのマップへのすべてのアクセスをロックし、保持している可能性のあるイテレータが無効になる可能性があることを認識する必要があります。

于 2009-05-22T03:51:13.240 に答える
-1

デバッガーを使用すると、呼び出しスタックを上げることができます。このようにして、セグメンテーション違反を引き起こしている自分のコード内の場所を確認できるはずです。

于 2009-05-21T17:51:32.427 に答える