2013-12-18 58 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为时已晚。 –

相关问题