gdbを使用したデバッグのエラー(segment fault)

4094 ワード

https://blog.csdn.net/Deutschester/article/details/6739861
テキストの位置 http://www.unknownroad.com/rtfm/gdbtut/gdbsegfault.html
 
 
私たちはgdbを使って、なぜ次のプログラム(ファイルはsegfault.c)が間違った問題を解決するつもりです。次のプログラムはユーザーからテキストの文字列を読み込んで画面に表示します。しかし、次のような現在のプログラムは予定通り実行されません。
 
  • #include
  • #include
  •  
  • int main(int argc, char **argv)
  • {
  • char *buf;
  •  
  • buf = malloc(1<<31);
  •  
  • fgets(buf, 1024, stdin);
  • printf("%s
    ", buf);
  •  
  • return 1;
  • }
  •  
     第一歩はデバッグフラグを付けてこのコードをコンパイルします。以下の通りです。
    ~(皰gcc-g segfault.c
    そして実行:
    ~〹a.out
    ハローワールド
    Segmentation fault
     
    これは私たちが期待しているものではない。強大なgdbを起動する時です。
    ~# gdb a.out
    GNU gdb 5.0
    Copyright 2000 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.
    There is absolutely no warranty for GDB.  Type "show warranty" for details.
    This GDB was configured as "i686-pc-linux-gnu"...
    (gdb) 
    
     
    私たちは直接運転して、何があったのか見てみます。
    (gdb) run
    Starting program: /home/dgawd/cpsc/363/a.out 
    test string
    
    Program received signal SIGSEGV, Segmentation fault.
    0x4007fc13 in _IO_getline_info () from /lib/libc.so.6
    
      SIGSEGV 。 , backtrace(= bt) : 
    (gdb) backtrace
    #0  0x4007fc13 in _IO_getline_info () from /lib/libc.so.6
    #1  0x4007fb6c in _IO_getline () from /lib/libc.so.6
    #2  0x4007ef51 in fgets () from /lib/libc.so.6
    #3  0x80484b2 in main (argc=1, argv=0xbffffaf4) at segfault.c:10
    #4  0x40037f5c in __libc_start_main () from /lib/libc.so.6
    
     
    ここでは私たち自身のコードのみに関心を持っています。したがって、私たちは3番スタックフレームに切り替えて、プログラムがどこで崩れているかを確認します。
    (gdb) frame 3
    #3  0x80484b2 in main (argc=1, argv=0xbffffaf4) at segfault.c:10
    10        fgets(buf, 1024, stdin)
    
     
    えっと、fgetsを呼び出して崩壊しました。一般的に、私たちは、例えばfgetsのようなライブラリ関数が正確に動作すると仮定しています。この問題の原因は,その中の一つのパラメータの問題に違いない。「stdin」はグローバル変数であることを知らないかもしれません。stdioライブラリによって作成されました。したがって,このパラメータが正しいと仮定した。残りは「buf」しかないです。そして、bufの現在の値を確認します。
    (gdb) print buf
    $1 = 0x0
    
    buf 0x0, NULL 。 —— buf 8 。 8 。 kill :
    (gdb) kill
    Kill the program being debugged? (y or n) y
    
    ( : quit gdb, 。 kill )  8 :
    (gdb) break segfault.c:8
    Breakpoint 1 at 0x8048486: file segfault.c, line 8.
    
     
    プログラムを再実行:
    (gdb) run
    Starting program: /home/dgawd/cpsc/363/a.out 
    
    Breakpoint 1, main (argc=1, argv=0xbffffaf4) at segfault.c:8
    8         buf = malloc(1<<31);
    
      malloc buf 。 buf , (garbage), :
    (gdb) print buf
    $2 = 0xbffffaa8 " ?\177\003@t`\001@\001"
    
     
    私たちはstep over(ワンステップ実行)malloを呼び出してから再度bufの値を確認します。
    (gdb) next
    10        fgets(buf, 1024, stdin);
    (gdb) print buf
    $3 = 0x0
    
     
    Mallocを呼び出した後、bufはNULLであることが分かります。mallocのマニュアルページを見ると、必要なメモリが割り当てられない時に、malloがNULLに戻ります。だから私たちのmallocが失敗したのは間違いないです。コードに戻ってもう一度見ましょう。
    7 :   buf = malloc(1<<31);
    
    , 1<<31( 1 31 , ) 429497295,  4GB (gigabytes). —— 256MB( , , )。 malloc 。 , fgets 1024 。 , 。 1<<31 1024( 1<<9), : 
    ~# a.out
    Hello World!
    Hello World!
    
    
    このようにして、gdbをどのように使って段を調整するかを知ることができます。これはとても役に立ちます。この例はまた、常にmallocの戻り値をチェックする非常に重要な基準を示している。すばらしい一日を持っています。(実は、一日間違えて気持ちが悪くなりました。でも、これからはあまり気持ちが悪くないはずです。これからは毎日がいいでしょう。)