2

しばらく前にプログラム (Mac OS X、C++、SDL、FMOD) を書きましたが、かなり良いパフォーマンスが得られました。しかし最近、その機能を拡張したいと思い、さらにコードを追加しました。そして今、それを実行して新しい機能をテストしようとすると、プログラムが SIGABRT でクラッシュします。

デバッガーを調べると、関数スタックで次のように表示されます。

  • _殺す
  • kill$UNIX2003
  • 高める
  • __アボート
  • __stack_chk_fail
  • odtworz <- 変更された関数

私の知る限り、「__stack_chk_fail」はスタック オーバーフローを示します。しかし、それはそれについて最も奇妙なことではありません。この関数「odtworz」には、次のようなコードがあります。

...

koniec = 0;
while ( koniec == 0 ) {
    ...
    if (mode == 1) {
        ...
    }
    else if (mode == 2) {
        ...
    }
    else if (mode == 3) {
       piesniOrkiestrowe[0] = '\0'; 
       while ( piesniOrkiestrowe[0] == '\0' ) { 
           losowaPiesn(); 
           char * piesnOrkiestrowa = szukajPiesniOrkiestrowej(); 
           if ( piesnOrkiestrowa != NULL ) 
              strcpy(piesniOrkiestrowe, piesnOrkiestrowa); 
       } 
       char nowyPiesnPlik[25]; 
       sprintf(nowyPiesnPlik, "%sorch/%s", PIESNI_DIR.c_str(), piesniOrkiestrowe);
    }
}

mode はグローバル変数で、以前の関数で値「2」に設定されています。そして想像してみてください - このモードでは決して実行されない 3 番目の if ステートメント (モード == 3) を削除しても、プログラムはクラッシュしません! 実行されることさえないコードを削除すると、状況が改善されます!

このコードはプログラムの他のモード用であるため、削除したくありません。そして、それはそこでうまく機能します。それで、私が検索できるヒントはありますか?これで何が間違っている可能性がありますか?

4

4 に答える 4

16

スタックオーバーフローエラーではありません。__stack_chk_failは、スタックフレームの破損が検出されたときに呼び出されます。スタックを破壊する従来の方法は、バッファオーバーフローです。それを引き起こすコードはあなたのスニペットではなく、ドットの中にあります。


コメントからのコードで質問を更新した後:strcpyとsprintfの両方の呼び出しは、スタック破損の優れた候補です。私が最初の答えで述べたバッファオーバーフローの問題。推測すると、nowyPiesnPlikは非常に小さく見えます。sprintf()関数は、バッファに書き込む文字が多すぎて「カナリア」を上書きします。カナリアが踏みつけられると、ランタイムは家禽を口笛で鳴らします:)

配列を大きくすることができます。実際の解決策ではありません。snprintf()など、これらの関数の安全な代替手段を使用してください。strncpy()については言及しません。

于 2010-06-14T13:44:29.813 に答える
2

非常によく似た問題が発生しました。コードが でクラッシュし__stack_chk_failます。私の場合、上記で推奨されている解決策は、を取り除くことでしsprintf()た。

于 2011-11-18T04:43:46.697 に答える
0

それを見つけた!

犯人は私が与えたコードの前にありました、しかしハンス・パッサントは私に何を見るべきかについての手がかりを与えました。それはこのように見えました:

char piesnPlik[25];
if ( mode == TRYB_PIANINO )
    sprintf(piesnPlik, "%spiano/%s.mp3", PIESNI_DIR.c_str(), wybranaPiesn);
else if ( tryb == TRYB_ORKIESTRA )
    sprintf(piesnPlik, "%sorch/%s", PIESNI_DIR.c_str(), piesniOrkiestrowe);
else if ( tryb == TRYB_NAGRANIE )
    sprintf(piesnPlik, "%s/%s", NAGRANIA_DIR.c_str(), nazwaNagraniaMP3);

そこで、今日、どのユーザーが「piesnPlik」変数であるかを3番目に追加しました。ただし、「nazwaNagraniaMP3」は、そこにコピーされた他の2つの変数よりも長いため、スタックが破損しました。しかし、関数から戻った後にクラッシュするだけで、その後すべてのSDLのもので動作することができたのは信じられないことです。

あなたの提案をありがとう!

于 2010-06-14T19:05:33.110 に答える
0

まったく奇妙ではありません。スタック オーバーフローやヒープ破損に関しては、奇妙なことが予想されます。スタック ポインター、プログラム カウンター、またはその他のプログラムの状態が破損しているため、デバッガーまたはトレース ツールは、クラッシュ時にプログラムがどこにあったかを正確に報告できません。バグは、投稿したスニペットから遠く離れた、コードの他の場所にある可能性があります。最近変更されたコードから始めます。

編集:あなたはすでに発見したように、スタック破損の良い例を自分で書いています。とにかくここに1つあります:

void foo (){ 
    int x[0];
    x[-99] = -1;
}
于 2010-06-14T13:48:55.217 に答える