1

C ++プログラムがいくつかの.png画像をディレクトリに書き込もうとすると、オーバーフローランタイムエラーが発生します。

画像が書き込まれるディレクトリは、コマンドライン引数として指定されます。プログラムはgcc-ggdb3-O3でコンパイルされます。再実行時にディレクトリを別のディレクトリに変更したり、最適化せずにプログラムをコンパイルしたりすると、エラーが消えるのは不思議です。私は混乱しています。最適化されていない実行可能ファイルまたは別のディレクトリで生成されたイメージを取得できますが、最適化された実行可能ファイルでランタイムエラーが発生する可能性があるため、結果が信頼できるかどうか疑問に思います。または、最適化によってエラーが発生しやすい実行可能ファイルが生成される可能性はありますか?誰でもそれを説明できますか?

gcc -ggdb3 -O3でコンパイルされているため、最適化された実行可能ファイルをデバッグしようとしましたが、オーバーフローエラーが発生する場所からソースコードが得られないため、手がかりが得られません。

(gdb)bt

#0 0x00007fbd29573fb5 in raise()from /lib/libc.so.6

#1 0x00007fbd29575bc3 in abort()from /lib/libc.so.6

#2 0x00007fbd295b3228 in ?? ()/lib/libc.so.6から

#3 /lib/libc.so.6の__fortify_fail()の0x00007fbd296402c7

#4 0x00007fbd2963e170 in __chk_fail()from /lib/libc.so.6

#5 0x00007fbd2963d519 in ?? ()/lib/libc.so.6から

#6 0x00007fbd295b7426 in _IO_default_xsputn()from /lib/libc.so.6

#7 /lib/libc.so.6のvfprintf()の0x00007fbd29586fdb

#8 0x00007fbd2963d5b9 in __vsprintf_chk()from /lib/libc.so.6

#9 0x00007fbd2963d500 in __sprintf_chk()from /lib/libc.so.6

#10 0x0000000000408695メイン()

(gdb)f 10

#10 0x0000000000408695メイン()

現在の言語:自動; 現在asm

(gdb)リスト

1 /build/buildd/glibc-2.9/build-tree/amd64-libc/csu/crtn.S:そのようなファイルまたはディレクトリはありません。

/build/buildd/glibc-2.9/build-tree/amd64-libc/csu/crtn.Sにあります

(gdb)

ランタイムエラーの出力が問題の分析に役立つかどうかはわかりません。可能であれば、エラーメッセージは次のようになりますが、少し長くなります。

*バッファオーバーフローが検出されました*:/ cis / home / tim / research / absurdity / absurditylinux / binio21 / release/absurdityが終了しました

[新しいスレッド0x7fbd2acd9740(LWP 2347)]

=======バックトレース:=========

/lib/libc.so.6(__fortify_fail+0x37)[0x7fbd296402c7]

/lib/libc.so.6[0x7fbd2963e170]

/lib/libc.so.6[0x7fbd2963d519]

/lib/libc.so.6(_IO_default_xsputn+0x96)[0x7fbd295b7426]

/lib/libc.so.6(_IO_vfprintf+0x63b)[0x7fbd29586fdb]

/lib/libc.so.6(__vsprintf_chk+0x99)[0x7fbd2963d5b9]

/lib/libc.so.6(__sprintf_chk+0x80)[0x7fbd2963d500]

/ cis / home / tim / research / absurdity / absurditylinux / binio21 / release / absurdity [0x408695]

/lib/libc.so.6(__libc_start_main+0xe6)[0x7fbd2955f5a6]

/ cis / home / tim / research / absurdity / absurditylinux / binio21 / release / absurdity [0x4045d9]

=======メモリマップ:========

00400000-00471000 r-xp 00000000 00:39 52084894 / cis / home / tim / research / absurdity / absurditylinux / binio21 / release / absurdity

00671000-00672000 r--p 00071000 00:39 52084894 / cis / home / tim / research / absurdity / absurditylinux / binio21 / release / absurdity

00672000-00673000 rw-p 00072000 00:39 52084894 / cis / home / tim / research / absurdity / absurditylinux / binio21 / release / absurdity

00673000-00675000 rw-p 00673000 00:00 0

00943000-00964000 rw-p 00943000 00:000[ヒープ]

7fbd273f7000-7fbd29339000 rw-p 7fbd273f7000 00:00 0

7fbd29339000-7fbd29340000 r-xp 00000000 08:01 35791448 /lib/librt-2.9.so

7fbd29340000-7fbd2953f000 --- p 00007000 08:01 35791448 /lib/librt-2.9.so

7fbd2953f000-7fbd29540000 r--p 00006000 08:01 35791448 /lib/librt-2.9.so

7fbd29540000-7fbd29541000 rw-p 00007000 08:01 35791448 /lib/librt-2.9.so

7fbd29541000-7fbd296a9000 r-xp 00000000 08:01 35791428 /lib/libc-2.9.so

7fbd296a9000-7fbd298a9000 --- p 00168000 08:01 35791428 /lib/libc-2.9.so

7fbd298a9000-7fbd298ad000 r--p 00168000 08:01 35791428 /lib/libc-2.9.so

7fbd298ad000-7fbd298ae000 rw-p 0016c000 08:01 35791428 /lib/libc-2.9.so

7fbd298ae000-7fbd298b3000 rw-p 7fbd298ae000 00:00 0

7fbd298b3000-7fbd298c9000 r-xp 00000000 08:01 35790870 /lib/libgcc_s.so.1

7fbd298c9000-7fbd29ac9000 --- p 00016000 08:01 35790870 /lib/libgcc_s.so.1

7fbd29ac9000-7fbd29aca000 r--p 00016000 08:01 35790870 /lib/libgcc_s.so.1

7fbd29aca000-7fbd29acb000 rw-p 00017000 08:01 35790870 /lib/libgcc_s.so.1

7fbd29acb000-7fbd29ad3000 r-xp 00000000 08:01 71705955 /usr/lib/libgomp.so.1.0.0

7fbd29ad3000-7fbd29cd2000 --- p 00008000 08:01 71705955 /usr/lib/libgomp.so.1.0.0

7fbd29cd2000-7fbd29cd3000 r--p 00007000 08:01 71705955 /usr/lib/libgomp.so.1.0.0

7fbd29cd3000-7fbd29cd4000 rw-p 00008000 08:01 71705955 /usr/lib/libgomp.so.1.0.0

7fbd29cd4000-7fbd29d58000 r-xp 00000000 08:01 35791436 /lib/libm-2.9.so

7fbd29d58000-7fbd29f57000 --- p 00084000 08:01 35791436 /lib/libm-2.9.so

7fbd29f57000-7fbd29f58000 r--p 00083000 08:01 35791436 /lib/libm-2.9.so

7fbd29f58000-7fbd29f59000 rw-p 00084000 08:01 35791436 /lib/libm-2.9.so

7fbd29f59000-7fbd2a04a000 r-xp 00000000 08:01 71704918 /usr/lib/libstdc++.so.6.0.10

7fbd2a04a000-7fbd2a24a000 --- p 000f1000 08:01 71704918 /usr/lib/libstdc++.so.6.0.10

7fbd2a24a000-7fbd2a251000 r--p 000f1000 08:01 71704918 /usr/lib/libstdc++.so.6.0.10

7fbd2a251000-7fbd2a253000 rw-p 000f8000 08:01 71704918 /usr/lib/libstdc++.so.6.0.10

7fbd2a253000-7fbd2a266000 rw-p 7fbd2a253000 00:00 0

7fbd2a266000-7fbd2a27d000 r-xp 00000000 08:01 35791446 /lib/libpthread-2.9.so

7fbd2a27d000-7fbd2a47c000 --- p 00017000 08:01 35791446 /lib/libpthread-2.9.so

7fbd2a47c000-7fbd2a47d000 r--p 00016000 08:01 35791446 /lib/libpthread-2.9.so

7fbd2a47d000-7fbd2a47e000 rw-p 00017000 08:01 35791446 /lib/libpthread-2.9.so

7fbd2a47e000-7fbd2a482000 rw-p 7fbd2a47e000 00:00 0

7f

プログラムは信号SIGABRTを受信し、中止されました。

[スレッド0x7fbd2acd9740(LWP 2347)への切り替え]

/lib/libc.so.6からのraise()の0x00007fbd29573fb5

本当にあなたの助けに感謝します!

ありがとう、よろしく!


@@ UPDATE @@:あなたたちは正しいです!長いファイル名のchar配列のサイズを大きくしましたが、問題ありません。

実行可能ファイルは/cis/ home / tim / research / absurdity / absurditylinux / binio21 / release/absurdityです。動作しないディレクトリは、コマンドライン引数--result-path = .. / results1 / FrancContinuity1 / noise0 / train-imgsとして指定され、以下のglobal.result_pathに格納されます。

あなたが言った問題だとあなたがどのように疑っているのか教えてもらえますか?__sprintf_chk()と__vsprintf_chk()は常にsprintf()によって呼び出されますか?

これがコードです。

パート1:

      char filename[50];
      sprintf(filename, "%s/%d_%d.png", global.result_path, train_samples[n].label, train_samples[n].label==1 ? ++nb_pos : ++nb_neg);
      train_samples[n].write_png(filename);

パート2:

class Global { //parameters of program
public:
  int niceness; //The process scheduling priority
  int random_seed; //The seed for the random sequence used in the computation
  char result_path[1024]; //Where to store the generated results (images, logs, etc.)
...
}

Global global;
4

4 に答える 4

3

ディレクトリ名の長さと、それを保存しようとしているバッファの長さはどれくらいですか? あなたは私たちに先に進むことをあまり与えていません.いくつかのコードを見せてみませんか? おそらく、main() のどこかで sprintf が呼び出され、関連する変数が宣言されているのでしょうか?

編集:入力ディレクトリと追加するファイル名を考えると、ファイル名はより大きな配列である必要があるようです! 簡単な修正: たとえば、50 文字ではなく 1500 文字として宣言してみてください。より良い修正: C++ を使用しているので、std::string および ostringstream クラスを調べてください。これらのクラスは、バッファー オーバーフローを防ぐためにサイズを変更します。

フォローアップの質問に答えるには:

結果パスの「../」は、絶対パスに展開されるべきではありません。

sprintf() が関係しているという私の予感は、「バッファー オーバーフロー」メッセージと gdb トレースバックの最後の数行に基づいた幸運な推測でした。私は glibc の内部構造にはあまり詳しくありませんが、おそらく__sprintf_chk()sprintf __vsprintf_chk() () のバッファ オーバーフロー チェックの変種ですか?

于 2009-09-03T00:01:10.967 に答える
2

私はずっと前に、あらゆる場所で snprintf を使用する習慣を身につけました。それを愛することを学びましょう。それでも正しいファイルの書き込みに失敗する可能性はありますが、少なくともセキュリティ ホールを残すことはありません。

次に、なぜプログラムが という名前のファイルを作成するのか疑問に思い始めたら、"this_is_a_long_file_na"戻って修正して、のバッファPATH_MAXまたは動的サイズの malloc バッファを使用することができます。バッファーを大きくする必要がある場合は、snprintf を使用すると適切なサイズを見つけることができます。

または、C++ に切り替えて std::string を使用することもできます。

于 2009-09-03T02:01:04.273 に答える
1

sprintf を使用して、もちろん長さ 50 のバッファ 'filename[50]' に出力します。現在、出力している文字列はサイズ 1024 のバッファです。これは潜在的な問題だと思います。global.result_path が 50 よりも長い場合 (整数も出力しているため、実際にはさらに少ない)、オーバーフローが発生します。

C++ std::string および std::stringstream を使用してみてください。

//Part 1:

std::stringstream ss;
ss << global.result_path << /* other data */;
train_samples[n].write_png(ss.str().c_str());

//Part 2:

class Global
{
    std::string result_path;
    ...
}

上記のコードを使用すると、文字バッファーのオーバーフローやその他の醜いものについて心配する必要がなくなります。

于 2009-09-03T00:49:04.793 に答える
1

結果パスが小さすぎます。

result_path を 1024 に変更するだけです。一部のシステムでは、マクロ MAX_PATH が定義されています。また、サイズを sizeof(result_path) として、sprintf を snprintf に変更します。

snprintf() 関数は、バッファの長さが与えられることを除いて、sprintf() と同じです。これにより、バッファ オーバーフローが防止されます。

戻り値は書き込んだ文字数です。buff_size 制限のために出力が切り捨てられた場合、戻り値は、十分なスペースが利用可能であった場合に最終文字列に書き込まれる文字数 (末尾の '\0' を含まない) です。

あなたが sprintf に問題があることを知ったのは、バックトレースでした。

すなわち

(gdb) bt

#0 0x00007fbd29573fb5 in raise () from /lib/libc.so.6

#1 0x00007fbd29575bc3 in abort () from /lib/libc.so.6

#2 0x00007fbd295b3228 in ?? () from /lib/libc.so.6

#3 0x00007fbd296402c7 in __fortify_fail () from /lib/libc.so.6

#4 0x00007fbd2963e170 in __chk_fail () from /lib/libc.so.6

#5 0x00007fbd2963d519 in ?? () from /lib/libc.so.6

#6 0x00007fbd295b7426 in _IO_default_xsputn () from /lib/libc.so.6

#7 0x00007fbd29586fdb in vfprintf () from /lib/libc.so.6

#8 0x00007fbd2963d5b9 in __vsprintf_chk () from /lib/libc.so.6

#9 0x00007fbd2963d500 in __sprintf_chk () from /lib/libc.so.6

#10 0x0000000000408695 in main ()

つまり、コードに main 関数があります。そして __sprintf_chk は腹が立つところです。sprintf を呼び出す必要がありました。その後、死亡した。だから私の推測では、あなたはそれに悪い議論を渡していた. sprintf がひどく死ぬ唯一の方法は、バッファ オーバーフローです。したがって、出力先の文字列が小さすぎるというのは良い仮定です。snprintf を使用すると、より安全になります。その後、印刷して結果をデバッグできます。これを行っていれば、result_path が 50 文字で切り捨てられ、プログラムがクラッシュしなかったため、バッファーが小さすぎることがすぐにわかりました (少なくともその時点で:)。

于 2009-09-03T02:38:25.110 に答える