総括段エラー(Segmentation fault)


段エラー(Segmenation fault)
原文の出所:http://oss.lzu.edu.cn/blog/article.php?tid_700.
私はただレイアウトを少し楽にします.いい文章です.初級編とはいえ、助けは確かに大きいです.
1)システムの保護を受けたメモリアドレスにデータを書き込みます.
一部のメモリはカーネルの占有あるいはその他のプログラムが使用しています.システムが正常に動作することを保証するために、システムの保護を受けます.#include <stdio.h>要点
main()
{
int i=0;
scanf('%d',i)/*shoud have used&i*/
printf("%d",i)
return 0;
)
コンパイルと実行してください.どのように見ても大丈夫ですよ.データを読んで出力してくれるのではないですか?
falcon@falcon:~/temp$gcc-g-o segerr.cプラス-gオプションでデバッグ情報を表示します.
falcon@falcon:~/temp$gdb./segerr
GNU gdb 6.4-debian
Copyright 2005 Free Software Foundation、Inc.
GDB is free software,covered by the GNU General Public License,and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type「show copying」to see the conditions.
The re is absolutielyのwarranty for GDB.Type“show warranty”for details.
This GDB was configred as「i 486-linux-gnu」…Using host libthread_db library"/lib/tls/i 686/cmov/libthreadudb.so.1"
(gdb)l、Cはl(list)でソースコードを表示します.
1萼include<stdio.h>
2
3 int
4 main()
5{
6 int i=0
7
8 scanf("%d",i)/*shuld have used&i*/
9 printf("%d",i);
10 return 0;
(gdb)b 8、Cはb(break)でブレークポイントを設定します.
Breakpoint 1 at 0×80483 b 7:file segerr.c,line 8.
(gdb)p_i、Cはp(print)で変数iの値を印刷します.[いいえ、ここiの値は0です.]
$1=0
(gdb)r,Cはr(run)で動作し、ブレークポイントで動作します.
Starting program:/home/falcon/temp/segerr
Breakpoint 1,main()at segerr.8
8 scanf("%d",i)/*shuld have used&i*/�C[アドレス0に値を書こうとしました]
(gdb)n,Cはn(next)で次のステップを実行します.
10
Program received signal SIGS EGV,Segmentation fault.
0 xb 7 e 9 a 1 ca in IOuvfscanf()from/lib/tls/i 686/cmov/libc.so.6
(gdb)c.Cは上でSIGSEGVを受信しました.その後、cで実行します.
Continuing.
Program terminated with signal SIGS EGV、Segmentation fault.
The programのlonger exists.
(gdb)quit、C退出gdb
やっぱり
私達は「不注意」で&iをiに書きました.
私達はちょうどiを0に初期化しました.これはメモリアドレス0に値を保存しようとしているのではないですか?
[追加:
man 7 signalでSIGS EGVの情報を見ることができます.
falcon@falcon:~/temp$man 7 signal grep SEGV
Reformating signal(7)、please wait…
SIGS EGV 11 Core Invalid memory reference
例2:#include <stdio.h>
int
main()
{
char *p;
p=NULL
*p=‘x’
printf("%c"、**p);
return 0;
)
この例もメモリアドレス0にものを書こうとしています.
ここで私達はgdbを通して、段の間違ったところの行を確認します.
falcon@falcon:~/temp$gcc-g-o segerr.c
falcon@falcon:~/temp$gdb./segerr
GNU gdb 6.4-debian
Copyright 2005 Free Software Foundation、Inc.
GDB is free software,covered by the GNU General Public License,and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type「show copying」to see the conditions.
The re is absolutielyのwarranty for GDB.Type“show warranty”for details.
This GDB was configred as“i 486-linux-gnu”…Using host libthreadubrary“/lib/tls/i 686/cmov/libthread.so.1”.
(gdb)r-Cは直接運行しています.途中で投げ出したのを見て、自動的にエラーが発生した行を表示しました.これは一つの誤りを見つける方法です.
Starting program:/home/falcon/temp/segerr
Program received signal SIGS EGV,Segmentation fault.
0×08516 in main()at segerr.10
10*p=‘x’
(gdb)
2)メモリオフライン(配列オフライン、変数タイプ不一致など)#include <stdio.h>要点
main()
{
char test[1];
printf("%c",test[100000]
return 0;
)
ここは比較的に極端な例ですが、時には出現する可能性があります.明らかな配列越境の問題です.
あるいはこの住所はまったく存在しません.
例4:#include <stdio.h>要点
main()
{
int b=10
printf("%s",b);
return 0;
)
私たちは一つの整数を文字列で出力しようとしますが、これは何の問題ですか?
ダイナミックリンクライブラリのデバッグにまだ慣れていないので
私はprintfのソースコードを見つけただけです.ここです.
宣言部分:int pos =0 ,cnt_printed_chars =0 ,i ;
unsigned char *chptr ;
va_list ap ;
/* %s :*/
case 's':
chptr =va_arg (ap ,unsigned char *);
i =0 ;
while (chptr [i ])
{...
cnt_printed_chars ++;
putchar (chptr [i ++]);
}
コードを詳しく分析していませんので、大体の原因は住所が境界を越える原因かもしれません.でも、確かではないですよ.
プリンツ関数のデバッグ方法を知っていたら、オフラインの本当の原因を探してもらえますか?
vagaustartやvagauargなどの関数の中にありますか?それともここのprintfソースコードの分析を直接見てみてください.
間違ったところを見つけることができます.
http://www.wangchao.net.cn/bbsdetail_47325.html
同様に、例えば、sprintfなどのフォーマット制御の問題があります.
例えば、charタイプまたはintは%sによって出力または保存しようとします.
lor=「black」
ヽoo.ツ.ツ.ツ.ツ....................................................
char c='c';
int i=10
char buf[100];
printf("%s",c)//char型を文字列形式で出力しようとする
print('%s',i)//int型を文字列で出力しようとする
memset(buf、0、100)
sprintf(buf、「%s」、c)//char型を文字列形式に変換しようとします.
memset(buf、0、100)
sprintf(buf、“%s”,i)//int型を文字列に変換しようとする
3)その他
大体の原因は同じです.つまり間違いの定義です.
しかし、もっと多くのミスをしやすいところは自分で積み重ねていくべきです.
たとえば:
<1>ポインタを定義したら初期化して、NULLかどうか判断してください.
<2>配列を使用するときは初期化されますか?配列の下付きが境界を越えるかどうか、配列要素が存在するかどうかなど
<3>変数処理時の変数のフォーマット制御が合理的かどうかなど
比較的良い例:
マルチスレッドプログラミングの例の中で、スレッド配列を定義しました.
𞃳define THREAD MAXUM
pth readaut thread[THREAD MAX]
Phreadcateで各スレッドを作成して、スレッドの終了をPhreadujunで待ちます.
始まったばかりです
スレッドの作成が成功した時、Phreadujoinは各スレッドの終了をスムーズに待つことができます.
しかし、スレッドの作成に失敗すると、存在しないスレッドをpthreadujoinで待つと、自然に存在しないメモリにアクセスすることができます.
その後
绝えずにデバッグと思考を通して、しかもネット上の资料の助けを得て、上记のエラーの原因と解决方法を探し当てました.
解決策は:
スレッドを作成する前に、スレッド配列を初期化します.
スレッドの終了を待つとき、スレッドが私たちの初期値かどうかを判断します.
もしそうでしたら、私たちのスレッドが作成されていないということですので、待つことができません.
上によく見られるいくつかのエラーが発生するところがあります.そうすると、それらに出会う時に避けられます.
しかし、人によっては、必ず油断することがあります.上の問題や他のよくある問題もあります.
大型のプログラムについては、どのように追跡してプログラムの中の間違った位置を見つけたらいいですか?
4.プログラムのセグメントエラーはどうやって発見されますか?
あるネット友達はこれに対して比較的に全面的な総括をして、彼に感謝する以外、私は住所をいじってきました.
文章の名前は「段エラーバグのデバッグ」です.
住所は:http://www.cublog.cn/u/5251/showart.php?id=173718
全面的というべきです.
私がよく使うデバッグ方法は以下の通りです.
1)プログラム内部のキーポイントで情報を出力し、そのようにセグメントエラーがコード内で可能な位置を追跡できます.
このようなデバッグ方法を使いやすくするために、条件でコマンドをコンパイルしてもいいです.また、printf関数として、printf関数を含んでいます.コンパイルするときは-DDEBUGパラメータを加えるとデバッグ情報が確認できます.逆に、このパラメータを加えずにデバッグすればいいです.
2)gdbでデバッグして、段の間違ったところで自動的に停止してエラーの行と行番号を表示します.
これはよく使われているはずです.gdbでデバッグしたいなら、コンパイルする時に-gパラメータを入れてデバッグ情報を表示してください.
これに対して、ユーザーは「段エラーバグのデバッグ」の文章で創造的にこのような方法を使って、プログラムを実行する時に動的にエラーが発生する可能性がある位置を把握することができます.
SIGS EGV信号を取り込むことにより、システムのgdb呼び出しをトリガしてデバッグ情報を出力する.
上に述べた条件を加えてコンパイルすれば、段間違えのデバッグができます.
3)もう一つのcatch segvコマンドがあります.
ヘルプ情報を見ると、見えます.