1

私の質問は、引数が欠落している printf の後の動作に関するものです。

printf("%s blah blah %d", int); // integer was given as argument (and not int written)

フォーマットの引数が不十分な場合、動作が未定義であることはすでにわかっています。

問題は、それが printf の結果に対して未定義なのか、それともプログラム全体に対して未定義なのかということです。

  • %s が許可されていないメモリ アドレスから読み取ろうとすると、クラッシュが発生する可能性があります。(それは私に起こりました)
  • printf が完了した後 [長時間] クラッシュが発生する可能性はありますか? (ガベージ文字列と整数を出力)

編集:

明確にするために、コンパイル エラーや警告について質問しているわけではありません。また、この行の実行時にプログラムがクラッシュすることもありません。問題は、この行が既に実行された後に、この行がプログラムをランダムにクラッシュさせることができるかということです。

4

2 に答える 2

1

プログラム全体では未定義です。

実際、プログラムが存在する前でさえ定義されていません。テキストの存在下でコンパイラ自体が行うことは定義されていません。printf("%s blah blah %d", int);

于 2012-09-30T09:43:45.800 に答える
0

基本的にプログラム全体。Printf はスタックから引数を取得し始めます。この場合、値を取りintすぎます。これは通常、返信先住所のようなものです。したがって、printf が戻ると、たまたまスタックの次にある乱数に戻ります。運が良ければ、通常の結果はセグメンテーション違反です。

引数をスタックにプッシュするため、引数をポップして、int最初の引数を取得しようとします。

運が悪ければ、アドレス指定可能なコードのチャンクが見つかります。これは、アドレスがランダムな文字のハッシュのアドレスになる 2 番目のケースにつながります。次に、ランダムな NUL 文字が見つかるまで文字列を出力しようとします。

アップデート

Joachim が指摘しているように、これの詳細は呼び出し規約によって決定されるため、明示的な例を作成しましょう。printf 関数が呼び出されるとき、戻りアドレスが最初にプッシュされるか、最後にプッシュされます。最初にプッシュされると仮定します (通常のアーキテクチャではより一般的です)。したがって、この呼び出しには PUSH return-address、フォーマット文字列の PUSH アドレス、int 値の PUSH (42 としましょう) が必要になります。これにより、次のスタックが得られます。

RTN ADDR
ADDR OF STRING
42

スタック ポインタ SP は、スタック上の次の位置を指しているままになります。

ここで、printf が文字列の解釈を開始します。パラメータのアドレスを探し、intそれが SP-1 であることを突き止めます。したがって、文字列パラメーターのアドレスは SP-2 である必要があります...しかし、文字列パラメーターがないため、これは書式文字列のアドレスです。次に、フォーマット文字列のアドレスを探すときに SP-3 を見つけようとしますが、それは戻りアドレス、つまり実行可能コードのアドレスです。これにより、ほとんどのマシンでセグメンテーション違反が発生するはずです。

呼び出し規則の他のオプションを調べてみると、それらのすべてが何か間違ったことを見ていることがわかります。なぜなら、printf はスタックから 2 つではなく、3 つのものを参照する必要があると考えているからです。

于 2012-09-30T09:46:47.957 に答える