3

重複の可能性:
未定義、未指定、および実装定義の動作

これはセグメンテーション フォールトです。なぜだろう。

    #include <string.h>
    #include <stdio.h>

    char str1[] = "Sample string. Sample string. Sample string. Sample string. Sample string. ";
    char str2[2];

    int main ()
    {
      strcpy (str2,str1);
      printf("%s\n", str2);
      return 0;
    }

次のコマンドで gcc バージョン 4.4.3 を使用しています。

    gcc -std=c99 testString.c -o test

また、最適化を o (-O0) に設定してみました。

4

5 に答える 5

8

これはセグメント フォールトのはずです

セグメンテーション違反を「すべき」理由はありません。コードの動作は未定義です。これは、必ずしもクラッシュする必要があるという意味ではありません。

于 2012-01-27T17:37:10.600 に答える
4

セグメンテーション違反は、メモリへのアクセスを実行すると、オペレーティング システムが想定されていないことを認識している場合にのみ発生します。

したがって、OS がメモリをページ単位 (通常は約 4KiB) に割り当てる可能性があります。str2はおそらく と同じページにstr1あり、ページの最後まで実行していないため、OS は認識しません。

それが未定義の動作に関することです。何でも起れる。現在、そのプログラムはあなたのマシン上で実際に「動作」しています。明日、str2ページの最後に配置され、その後 segfault が発生する可能性があります。または、メモリ内の何か他のものを上書きして、まったく予測できない結果になる可能性があります。

編集:セグメンテーション違反を引き起こす方法:

ふたつのやり方。1 つはまだ未定義の動作ですが、もう 1 つはそうではありません。

int main() {
    *((volatile char *)0) = 42; /* undefined behavior, but normally segfaults */
}

または、定義された方法でそれを行うには:

#include <signal.h>

int main() {
    raise(SIGSEGV); /* segfault using defined behavior */
}

編集: segfault の 3 番目と 4 番目の方法

以下は、strcpy を使用した最初の方法のバリエーションです。

#include <string.h>

const char src[] = "hello, world";
int main() {
    strcpy(0, src); /* undefined */
}

そして、この変種は私のためにのみクラッシュします-O0:

#include <string.h>

const char src[] = "hello, world";
int main() {
    char too_short[1];
    strcpy(too_short, src); /* smashes stack; undefined */
}
于 2012-01-27T17:40:23.367 に答える
2

プログラムは、割り当てられた配列の境界を超えて書き込みます。これにより、Undefined Behaviorが発生します。
プログラムの形式が正しくないため、クラッシュする可能性もあれば、クラッシュしない可能性もあります。説明できる場合とできない場合があります。

使用されていない配列の境界を超えて一部のメモリを上書きするため、おそらくクラッシュしませんが、そのメモリの正当な所有者がアクセスしようとすると、クラッシュします。

于 2012-01-27T17:35:36.320 に答える
0

これが破損している可能性があるものを本当に知りたい場合は、上書きされたメモリの後に何が続くかを確認することをお勧めします。リンカーマップファイルを生成すると、公正なアイデアが得られますが、これもすべて、メモリ内での配置方法に依存します、これを gdb で実行して、segfault を実行する理由としない理由を説明することもできます。そうは言っても、アクセス違反 (HW 支援) の組み込みチェックの粒度は、何らかのソフトウェア マジックが投入されない限り、ページよりも細かくすることはできません (このページの粒度アクセス チェック すぐ次のページが実際に実行しているプログラムの別の何かを指しており、それが書き込み可能なページである可能性があります)、valgrind について知っている人は、そのようなアクセスを検出できる方法を説明できます違反(libefenceも)、おそらく(この説明は非常に間違っているかもしれませんが、間違っていたら訂正してください!) 範囲外のアクセスが発生したかどうかを確認するために、何らかの形式のマーカーまたは比較を使用します。

于 2012-01-27T19:51:46.910 に答える