2013-12-18 60 views
0

我在程序中使用getopt_longsource here),並且在測試其行爲時給出無效的long選項(--stack-overflow)和I得到:segfault退出(EXIT_FAILURE)但沒有錯誤(EXIT_FAILURE,...)

[[email protected] btcwatch]$ ./btcwatch --stack-overflow 
Segmentation fault (core dumped) 

爲背景,其在getopt_long()循環,即:

while((opt = getopt_long(argc, 
         argv, 
         OPTSTRING, 
         long_options, 
         &longopt_i)) != -1) 
{ 

    ... 

    default: 
     exit(EXIT_FAILURE); 
     break; 

相反的:

error(EXIT_FAILURE, 0, "unknown option !?"); 

(該exit()SIGSEGV代碼S)

瘋狂的事情是,default不應(且不,根據gdb),執行。

gdb表明,它立即崩潰的getopt_long()電話,

(gdb) start --stack-overflow  
Temporary breakpoint 1, main (argc=2, argv=0x7fffffffe598) at src/main.c:96 
96  btcdbg("main()"); 
(gdb) s 
btcdbg (fmt=0x403260 "main()") at src/btcutil.c:50 
50 } 
(gdb) 
main (argc=2, argv=0x7fffffffe598) at src/main.c:118 
118  const struct option long_options[] = { 
(gdb) 
211  api_err.err = false; 
(gdb) 
212  colour = false; 
(gdb) 
213  found_path = false; 
(gdb) 
214  fp = NULL; 
(gdb) 
215  n = 1.0; 
(gdb) 
216  newlp = NULL; 
(gdb) 
217  pn = argv[0]; 
(gdb) 
218  reverse = false; 
(gdb) 
219  verbose = false; 
(gdb) 
221  strcpy(currcy, "USD"); 
(gdb) 
223  setlocale(LC_ALL, ""); // sets the locale to the system's default 
(gdb) 
225  while((opt = getopt_long(
(gdb) 

Program received signal SIGSEGV, Segmentation fault. 
0x00007ffff7643e2c in __strncmp_sse2() from /usr/lib/libc.so.6 

但是,當它與error()代替exit()運行時,它繼續正常:

(gdb) start --stack-overflow 
Temporary breakpoint 1, main (argc=2, argv=0x7fffffffe598) at src/main.c:96 
96  btcdbg("main()"); 
(gdb) s 
btcdbg (fmt=0x4032a0 "main()") at src/btcutil.c:50 
50 } 
(gdb) 
main (argc=2, argv=0x7fffffffe598) at src/main.c:118 
118  const struct option long_options[] = { 
(gdb) 
211  api_err.err = false; 
(gdb) 
212  colour = false; 
(gdb) 
213  found_path = false; 
(gdb) 
214  fp = NULL; 
(gdb) 
215  n = 1.0; 
(gdb) 
216  newlp = NULL; 
(gdb) 
217  pn = argv[0]; 
(gdb) 
218  reverse = false; 
(gdb) 
219  verbose = false; 
(gdb) 
221  strcpy(currcy, "USD"); 
(gdb) 
223  setlocale(LC_ALL, ""); // sets the locale to the system's default 
(gdb) 
225  while((opt = getopt_long(
(gdb) 
/home/marcoms/code/btcwatch/./btcwatch: unrecognized option '--stack-overflow' 
232   btcdbg("got option '%c'", opt); 
(gdb) 
btcdbg (fmt=0x4032a8 "got option '%c'") at src/btcutil.c:50 
50 } 
(gdb) 
main (argc=2, argv=0x7fffffffe598) at src/main.c:233 
233   switch(opt) { 
(gdb) 
236     help(pn, optarg); 
(gdb) 
help (prog_nm=0x7fffffffe8d8 "/home/marcoms/code/btcwatch/./btcwatch", topic=0x0) at src/btcutil.c:69 
69  btcdbg("help()"); 
(gdb) 
btcdbg (fmt=0x403bfc "help()") at src/btcutil.c:50 
50 } 
(gdb) 
help (prog_nm=0x7fffffffe8d8 "/home/marcoms/code/btcwatch/./btcwatch", topic=0x0) at src/btcutil.c:71 
71  char currcies[][3 + 1] = { 
(gdb) 
101  char topics[][16] = { 
(gdb) 
117  if(!topic) { 
(gdb) 
118   bputs("Usage: "); bputs(prog_nm); bputs(" [OPTION]\n"); 
(gdb) 
Usage: /home/marcoms/code/btcwatch/./btcwatch [OPTION] 
119   bputs(
(gdb) 
Get and monitor Bitcoin trade information 

Options:  Long options: 
    -C    --compare    comare current price with stored price 
    -S    --store    store current price 
    -a    --all     equivalent to -pbs 
    -b    --buy     print buy price 
    -c CURRENCY --currency=CURRENCY set conversion currency 
    -n AMOUNT  --amount=AMOUNT  set the amount to convert 
    -o    --colour, --color  enable use of colour 
    -p    --ping     check for a successful JSON response 
    -r    --reverse    convert currency to Bitcoin 
    -s    --sell     print sell price 
    -v    --verbose    increase verbosity 

    -h [topic]  --help[=topic]   print this help, or help designated by topic 
             use --help=topics for available topics 
    -V    --version    print version number 

Report bugs to [email protected] 
btcwatch home page: <https://github.com/marcoms/btcwatch> 
142   exit(EXIT_SUCCESS); 
(gdb) 
[Inferior 1 (process 25752) exited normally] 

在這一點上,我真的很難過。什麼可能導致段錯誤?當然,我可以使用error()而不是退出,但這是令人難以置信的不滿意。

+1

請發表您的整個代碼,理想情況下[短的,自包含的,正確的,編譯示例](http://sscce.org/)。由於某些內存錯誤,您很可能會遇到某種類型的「未定義行爲」,但如果沒有查看所有代碼,則無法說明。你有沒有試過用[Valgrind](http://valgrind.org/)來運行它? –

+0

https://github.com/marcoms/btcwatch/blob/master/src/main.c#L118是相關部分。至少它的可編譯... http://pastebin.ca/2514429包含'valgrind'的輸出。 –

+1

對於我的問題的編輯,(我不能複習,由於代表)是不喜歡我的編碼風格的理由足以編輯?就我個人而言,我不知道如何能夠與自己生活在一起,將標籤與空格混合在一起...... –

回答

2

的問題是,你的選擇陣列無法正常終止:

const struct option long_options[] = { 
      // ... 
      // This is the last element 
      { 
        .name = "verbose", 
        .has_arg = no_argument, 
        .flag = NULL, 
        .val = 'v' 
      } 
    }; 

getopt_long(3)要求選擇陣列全零終止,以便它知道數組有多大 - 發現你從未真正將數組大小傳遞給getopt_long。所以發生的事情是它走過陣列的末端,尋找終結者,然後開始讀取越界之外的內容,Valgrind正確地抱怨。未定義的行爲結果。

修復的方法是簡單的:

const struct option long_options[] = { 
      // ... 
      { 
        .name = "verbose", 
        .has_arg = no_argument, 
        .flag = NULL, 
        .val = 'v' 
      }, 

      // Array terminator 
      {0, 0, 0, 0} 
}; 
+0

哇,我剛纔看到了:)現在,數組的最後一個元素必須填充零。你已經在'btcwatch'的評論中獲得了一席之地 - https://github.com/marcoms/btcwatch/commit/9097171363515cb817664eac174ec61d11f064ad#diff-803c5170888b8642f2a97e5e9423d399R210 –

+1

@marcoms:是的,它被埋在文檔中,所以它很容易錯過。無論何時將一個數組傳遞給一個函數,如果該函數不能使數組長度更長,則應該始終保持警惕 - 這通常表明某種不尋常的事情正在進行。就個人而言,如果'getopt_long'將數組長度作爲參數而不是使用標記,那麼我更喜歡它,但顯然現在改變API爲時已晚。 –

相關問題