退出时段错误(EXIT_FAILURE)但没有错误(EXIT_FAILURE,...)

时间:2013-12-18 21:14:20

标签: c gdb segmentation-fault sigsegv getopt

我在程序(source here)中使用getopt_long,并且在给出无效的长选项(--stack-overflow)时测试其行为时,我得到:

[marcoms@baguette16 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 marco@scannadinari.co.uk
btcwatch home page: <https://github.com/marcoms/btcwatch>
142         exit(EXIT_SUCCESS);
(gdb) 
[Inferior 1 (process 25752) exited normally]

此时,我真的很难过。什么可能导致段错误?当然,我可以使用error()而不是退出,但这令人难以置信的不满意。

1 个答案:

答案 0 :(得分:2)

问题是您的选项数组没有正确终止:

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

getopt_long(3)要求options数组以全零结尾,以便它知道数组的大小 - 注意你实际上从未将数组大小传递给getopt_long。所以正在发生的事情是它走过数组的末尾,寻找终结符,然后它开始读取内存越界,Valgrind正确地抱怨。未定义的行为结果。

修复很简单:

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

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