セグメンテーション違反とは何ですか?


598

セグメンテーション違反とは何ですか?CとC ++では違いがありますか?セグメンテーション違反とぶら下がりポインタはどのように関連していますか?


94
セグメンテーション違反により、コンパイラーの状態が悪くなります。
Benjamin Crouzier

22
その場合、コンパイラーが何も文句を言わないのはなぜですか、すべて順調に進みましたが、実行時にシステムがセグメンテーション違反(コアダンプ)をスローしますか?T_T
ジムRaynor

3
何か問題が発生したときのメモリダンプです。
resultsway 2015

7
@pinouchon:おかしいですが、コンパイラーはいつセグメントフォールトと関係がありますか?ランタイム環境ではありませんか?
2015

1
通常、nullポインターを逆参照しようとすることによって呼び出されるため、セグメンテーション違反は多くの場合Javaに類似していますNullPointerException
Raedwald 2017

回答:


673

セグメンテーション違反は、「自分のものではない」メモリへのアクセスによって引き起こされる特定の種類のエラーです。これは、メモリの破損やデバッグが困難なメモリバグの発生を防ぐヘルパーメカニズムです。segfaultを受け取ったときはいつでも、メモリで何か問題があることを知っています。すでに解放されている変数にアクセスしたり、メモリの読み取り専用部分に書き込んだりするなどです。セグメンテーションフォールトは、ほとんどの言語で同じですメモリ管理では、CとC ++のsegfaultに主な違いはありません。

segfaultを取得する方法はたくさんありますが、少なくともC(++)などの低レベル言語ではそうです。segfaultを取得する一般的な方法は、nullポインターを逆参照することです。

int *p = NULL;
*p = 1;

読み取り専用としてマークされたメモリの一部に書き込もうとすると、別のセグメンテーション違反が発生します。

char *str = "Foo"; // Compiler marks the constant string as read-only
*str = 'b'; // Which means this is illegal and results in a segfault

ぶら下がりポインタは、次のように存在しないものを指します。

char *p = NULL;
{
    char c;
    p = &c;
}
// Now p is dangling

ポインターは、ブロックの終了後に存在しなくなったp文字変数cを指すため、ぶら下がります。また、ダングリングポインター(など*p='A')を逆参照しようとすると、おそらくセグメンテーション違反が発生します。


154
最後の例は、私がビルドするときに特に厄介です:int main(){char * p = 0; {char c = 'x'; p =&c; } printf( "%c \ n"、* p); 0を返します。} gccまたは他のいくつかのコンパイラのいずれかを使用すると、動作するように見えます。コンパイル時に警告はありません。セグフォルトなし。これは、範囲外の '}'が実際にデータを削除するのではなく、再度使用できるようにマークするだけだからです。コードは何年もの間、運用システムで問題なく実行できます。コードの別の部分を変更し、コンパイラーなどを変更すると、BOOOOOM!
Chris Huang-Leaver 2010

36
バンプは申し訳ありませんが、余談ですが... segfaultの原因となる例はありません。実際、これは未定義の動作です;-)
oldrinb

18
@oldrinb:必ずしも segfaultを引き起こすコードを書くことは不可能です。特に、メモリ保護なしで動作するシステムがあるため、メモリの一部が実際に「自分に属している」かどうかを判断できず、セグメンテーション違反を認識できず、未定義の動作しかありません...(たとえば、従来のAmigaOS)
DevSolar 2014年

7
@ ChrisHuang-Leaver c、それがローカルであることを理解する必要があります。つまり、それは後にスタックにプッシュされ、後にスタックから{ポップされたことを意味します}。ダングリングポインターは、スタックから外れたオフセットへの参照にすぎません。そのため、単純なプログラムで変更しても、segfaultはトリガーされません。一方、より複雑な使用例ではsegfaultが発生する可能性があり、他の関数呼び出しがスタックを拡張して、ダングリングポインターが指すデータを含む可能性があります。そのデータへの書き込み(ローカルVARS)未定義の動作(セグメンテーション違反&Co社)につながる
アイマンKhamouma

3
@ ChrisHuang-Leaver、通常、スコープ外に出ると、コンパイラーはいくつかのスタックスペースを回復して未使用のスタックスペースを解放する必要がありますが、これは常に発生するわけではありません(gccはこのコンパイラーの1つです)。また、割り当てられたスタックスペースは通常再び再利用されるため、未使用のスタックページをシステムに返し、そのスペースをの対象とするオペレーティングシステムはないと聞いたSIGSEGVので、そのような信号がスタックを乱すことからは期待できません。
Luis Colorado

111

セグメンテーションフォールトは、別のプロセスメモリに直接アクセスすることによって引き起こされるのではないことに注意する価値があります(これは私が時々聞いていることです)。仮想メモリでは、すべてのプロセスに独自の仮想アドレス空間があり、ポインタの値を使用して別のプロセスにアクセスする方法はありません。これの例外は、(おそらく)異なる仮想アドレスにマップされた同じ物理アドレススペースである共有ライブラリと、すべてのプロセスで同じようにマップされたカーネルメモリです(syscallでのTLBフラッシュを回避するためだと思います)。そしてshmat;)のようなもの-これらは私が「間接的」アクセスとして数えるものです。ただし、通常はプロセスコードから遠くにあり、通常はそれらにアクセスできることを確認できます(これが理由です)

それでも、不適切な方法で(たとえば、書き込み不可能なスペースに書き込もうとするなど)自分の(プロセス)メモリにアクセスした場合、セグメンテーション違反が発生する可能性があります。しかし、その最も一般的な理由は、物理アドレス空間にまったくマッピングされいない仮想アドレス空間の部分へのアクセスです。

そして、仮想メモリシステムに関するすべてのことです。


共有メモリ/メモリマップファイルを使用すると、他の誰かがあなたのメモリを混乱させる可能性があります。WIN32には、「WriteProcessMemory」などの厄介なAPIもあります。
ポール14

1
@paulm:はい、知っています。これは、「そしてshmatのようなもの;)-私が「間接的な」アクセスとして数えるものであると私が心に描いていたものです。
konrad.kruczynski 2014

仮想メモリのオペレーティングシステムでは、プロセスが別のプロセスの仮想メモリにアクセスする方法はありません(通常、オペレーティングシステムの実装者は、これについては非難しないでください)。アクセス。通常、仮想メモリアドレスは、検討中のプロセスによって異なる意味を持ちます。
Luis Colorado

38

セグメンテーション違反は、プロセスが記述子テーブルにリストしていないページに対する要求、またはリストにあるページに対する無効な要求(たとえば、読み取り専用ページでの書き込み要求)が原因で発生します。

ダングリングポインターは、有効なページを指す場合とそうでない場合がありますが、メモリーの「予期しない」セグメントを指すポインターです。


10
これは本当ですが、セグメンテーション違反が何であるかをすでに知らない場合は、本当に役に立ちますか?
zoul

29

正直なところ、他のポスターが述べたように、ウィキペディアにはこれに関する非常に優れた記事があるので、そちらをご覧ください。このタイプのエラーは非常に一般的であり、アクセス違反や一般保護違反など、他のこととも呼ばれます。

C、C ++、またはポインタを許可するその他の言語でも違いはありません。これらの種類のエラーは、通常、

  1. 適切に初期化される前に使用されます
  2. それらが指すメモリが再割り当てまたは削除された後に使用されます。
  3. インデックスが配列境界の外にあるインデックス配列で使用されます。これは通常、STL / Boostベースのコレクション(C ++ではない)ではなく、従来の配列またはC文字列でポインター計算を実行している場合のみです。

16

ウィキペディアによると:

セグメンテーション違反は、プログラムがアクセスを許可されていないメモリ位置にアクセスしようとしたとき、または許可されていない方法でメモリ位置にアクセスしようとしたときに発生します(たとえば、読み取り専用の場所への書き込みや、オペレーティングシステムの一部を上書きします)。


13

セグメンテーション違反は、ハードウェア障害、この場合はRAMメモリによっても引き起こされます。これはあまり一般的ではない原因ですが、コードにエラーが見つからない場合は、memtestが役立つ可能性があります。

この場合の解決策は、RAMを変更することです。

編集:

ここに参照があります:ハードウェアによるセグメンテーション違反


3
障害のあるRAMの簡単なテストでは、クラッシュするプログラムをループで繰り返し実行します。プログラムに内部非決定性がない場合、つまり、同じ入力に対して常に同じ出力が生成される場合、または少なくとも想定されている場合ですが、特定の入力については、クラッシュする場合もありますが、常にではない場合もあります。不良RAMの心配を始めます。
zwol 2017年

8

セグメンテーションフォールトは、プロセス(プログラムの実行中のインスタンス)が、他のプロセスで使用されている読み取り専用メモリアドレスまたはメモリ範囲にアクセスしようとしたり、存在しない(無効な)メモリアドレスにアクセスしようとしたときに発生します。 ダングリングリファレンス(ポインタ)の問題とは、メモリから既に内容が削除されているオブジェクトまたは変数にアクセスしようとすることを意味します。例:

int *arr = new int[20];
delete arr;
cout<<arr[1];  //dangling problem occurs here

4
配列を削除する正しい方法は、delete [] arrです。
ダミアン

8

ウィキペディアのSegmentation_faultページには、原因と理由を指摘しただけの非常に優れた説明があります。詳細については、wikiをご覧ください。

コンピューティングでは、セグメンテーション違反(多くの場合、segfaultに短縮されます)またはアクセス違反は、メモリ保護機能を備えたハードウェアによって発生する障害であり、メモリアクセス違反についてオペレーティングシステム(OS)に通知します。

セグメンテーション違反の一般的な原因は次のとおりです。

  • NULLポインタの逆参照–これはメモリ管理ハードウェアによって特別なケースです
  • 存在しないメモリアドレス(プロセスのアドレス空間外)にアクセスしようとしています
  • プログラムにアクセス権がないメモリにアクセスしようとしています(プロセスコンテキストのカーネル構造など)
  • 読み取り専用メモリ(コードセグメントなど)に書き込もうとしています

これらは順番に、無効なメモリアクセスを引き起こすプログラミングエラーによって引き起こされることがよくあります。

  • 初期化されていないポインタ(ランダムなメモリアドレスを指すワイルドポインタ)への逆参照または割り当て

  • 解放されたポインタの参照解除または割り当て(解放された、割り当て解除された、または削除されたメモリを指すダングリングポインタ)

  • バッファオーバーフロー。

  • スタックオーバーフロー。

  • 正しくコンパイルされないプログラムを実行しようとしています。(一部のコンパイラーは、コンパイル時エラーが存在しても実行可能ファイルを出力します。)


6

簡単に言うと、セグメンテーションフォールトとは、オペレーティングシステムがプログラムに信号を送信して、不正なメモリアクセスを検出し、メモリの破損を防ぐためにプログラムを途中で終了させて​​いることです。


3

「セグメンテーション違反」とは、アクセスできないメモリにアクセスしようとしたことを意味します。

最初の問題は、mainの引数にあります。メイン関数はでなければならずint main(int argc, char *argv[])、argv [1]にアクセスする前にargcが少なくとも2であることを確認する必要があります。

また、floatをprintfに渡す(ところで、printfに渡すとdoubleに変換される)ため、%f形式指定子を使用する必要があります。%s書式指定子は文字列( '\ 0'で終了する文字配列)用です。


2

セグメンテーション違反またはアクセス違反は、プログラムが存在しないメモリ位置にアクセスしようとした場合、または許可されていない方法でメモリ位置にアクセスしようとした場合に発生します。

 /* "Array out of bounds" error 
   valid indices for array foo
   are 0, 1, ... 999 */
   int foo[1000];
   for (int i = 0; i <= 1000 ; i++) 
   foo[i] = i;

ここではi [1000]が存在しないため、segfaultが発生します。

セグメンテーション違反の原因:

it arise primarily due to errors in use of pointers for virtual memory addressing, particularly illegal access.

De-referencing NULL pointers  this is special-cased by memory management hardware.

Attempting to access a nonexistent memory address (outside processs address space).

Attempting to access memory the program does not have rights to (such as kernel structures in process context).

Attempting to write read-only memory (such as code segment).

2
まず、seg faultはアドレスが存在するか存在しないかとは関係ありません。それはあなたがそうすることが許されていない場所であなたがそれにアクセスしているということです。そしてあなたの特別な例では、その場所が存在することは標準によっても保証されています。規格では配列の場合を規定しているため、境界内で1の後ろに、適切に配置された配列上のポインターpointgの有効なアドレスがあることを指定する必要があります。
dhein

また、アドレスがなくてもこのアドレスにアクセスしようとすると、segがあります。障害。そして、私の例では、それは理解の観点からのみです。
Mohit Rohilla

2

回答には「セグメンテーションフォールト」のいくつかの良い説明がありますが、セグメンテーションフォールトではメモリ内容のダンプがよくあるため、セグメンテーションフォールト(コアダンプ)の「コアダンプ」部分とメモリは以下から来ます:

1955年頃から1975年頃まで-半導体メモリの前に-コンピュータメモリの支配的な技術は、銅線に張られた小さな磁気ドーナツを使用していました。ドーナツは「フェライトコア」と呼ばれ、メインメモリは「コアメモリ」または「コア」と呼ばれていました。

ここから撮影。


2

セグメンテーション違反の十分な定義があります。プログラミング中に遭遇したいくつかの例を引用します。これはばかげた間違いに見えるかもしれませんが、多くの時間を浪費します。

  1. printfで引数の型が一致しない場合、以下の場合にセグメンテーション違反が発生する可能性があります

    #include<stdio.h> int main(){
    int a = 5; printf("%s",a); return 0; }

出力: Segmentation Fault (SIGSEGV)

  1. ポインタにメモリを割り当てるのを忘れたが、それを使用しようとしたとき。

     #include<stdio.h> 
     typedef struct{
       int a;
     }myStruct;   
    int main(){
      myStruct *s;
      /* few lines of code */
      s->a = 5;
      return 0;
    }

出力: Segmentation Fault (SIGSEGV)


1

の単純な意味Segmentation faultは、自分が所有していないメモリにアクセスしようとしていることです。Segmentation fault読み取り専用のメモリ位置でタスクの読み取りや書き込みを行おうとしたり、メモリを解放しようとしたりすると発生します。つまり、これをある種のメモリ破損として説明できます。

以下では、プログラマーが犯した、につながる一般的な間違いについて説明しSegmentation faultます。

  • scanf()間違った方法で使用します(置くのを忘れました&)。
int num;
scanf("%d", num);// must use &num instead of num
  • 間違った方法でポインタを使用してください。
int *num; 
printf("%d",*num); //*num should be correct as num only
//Unless You can use *num but you have to point this pointer to valid memory address before accessing it.
  • 文字列リテラルの変更(ポインターは読み取り専用メモリーの書き込みまたは変更を試みます。)
char *str;  

//Stored in read only part of data segment
str = "GfG";      

//Problem:  trying to modify read only memory
*(str+1) = 'n';
  • すでに解放されているアドレスを介して到達してみてください。
// allocating memory to num 
int* num = malloc(8); 
*num = 100; 

// de-allocated the space allocated to num 
free(num); 

// num is already freed there for it cause segmentation fault
*num = 110; 
  • スタックオーバーフロー-:スタックのメモリ不足
  • 範囲外の配列へのアクセス
  • printf()およびscanf()' を使用する場合は、間違ったフォーマット指定子を使用してください
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.