使用getopt_long()进行段错误

时间:2017-06-21 13:23:11

标签: c segmentation-fault getopt getopt-long

对于学校项目我必须使用getopt_long()或getopt_long_only()。这是我的循环:

while ((get_opt_err = getopt_long(argc, argv, "p:x:y:n:c:f:h",
                    &help_opt, NULL)) != -1)

我在valgrind中报告了一个段错误:

==2971== Memcheck, a memory error detector
==2971== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==2971== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==2971== Command: ./zappy_server --h
==2971== 
==2971== Conditional jump or move depends on uninitialised value(s)
==2971==    at 0x4F0B23E: _getopt_internal_r (in /usr/lib/libc-2.25.so)
==2971==    by 0x4F0C240: _getopt_internal (in /usr/lib/libc-2.25.so)
==2971==    by 0x4F0C2BD: getopt_long (in /usr/lib/libc-2.25.so)
==2971==    by 0x400C3D: getopt_server_parsing (getopt_server_parsing.c:42)
==2971==    by 0x4008AC: main (main.c:46)
==2971== 
==2971== Use of uninitialised value of size 8
==2971==    at 0x4C2E8C9: __GI_strncmp (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2971==    by 0x4F0B252: _getopt_internal_r (in /usr/lib/libc-2.25.so)
==2971==    by 0x4F0C240: _getopt_internal (in /usr/lib/libc-2.25.so)
==2971==    by 0x4F0C2BD: getopt_long (in /usr/lib/libc-2.25.so)
==2971==    by 0x400C3D: getopt_server_parsing (getopt_server_parsing.c:42)
==2971==    by 0x4008AC: main (main.c:46)
==2971== 
==2971== Invalid read of size 1
==2971==    at 0x4C2E8C9: __GI_strncmp (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2971==    by 0x4F0B252: _getopt_internal_r (in /usr/lib/libc-2.25.so)
==2971==    by 0x4F0C240: _getopt_internal (in /usr/lib/libc-2.25.so)
==2971==    by 0x4F0C2BD: getopt_long (in /usr/lib/libc-2.25.so)
==2971==    by 0x400C3D: getopt_server_parsing (getopt_server_parsing.c:42)
==2971==    by 0x4008AC: main (main.c:46)
==2971==  Address 0x1170 is not stack'd, malloc'd or (recently) free'd
==2971== 
==2971== 
==2971== Process terminating with default action of signal 11 (SIGSEGV): dumping core
==2971==  Access not within mapped region at address 0x1170
==2971==    at 0x4C2E8C9: __GI_strncmp (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==2971==    by 0x4F0B252: _getopt_internal_r (in /usr/lib/libc-2.25.so)
==2971==    by 0x4F0C240: _getopt_internal (in /usr/lib/libc-2.25.so)
==2971==    by 0x4F0C2BD: getopt_long (in /usr/lib/libc-2.25.so)
==2971==    by 0x400C3D: getopt_server_parsing (getopt_server_parsing.c:42)
==2971==    by 0x4008AC: main (main.c:46)
==2971==  If you believe this happened as a result of a stack
==2971==  overflow in your program's main thread (unlikely but
==2971==  possible), you can try to increase the size of the
==2971==  main thread stack using the --main-stacksize= flag.
==2971==  The main thread stack size used in this run was 8388608.
==2971== 
==2971== HEAP SUMMARY:
==2971==     in use at exit: 29 bytes in 2 blocks
==2971==   total heap usage: 2 allocs, 0 frees, 29 bytes allocated
==2971== 
==2971== LEAK SUMMARY:
==2971==    definitely lost: 0 bytes in 0 blocks
==2971==    indirectly lost: 0 bytes in 0 blocks
==2971==      possibly lost: 0 bytes in 0 blocks
==2971==    still reachable: 29 bytes in 2 blocks
==2971==         suppressed: 0 bytes in 0 blocks
==2971== Rerun with --leak-check=full to see details of leaked memory
==2971== 
==2971== For counts of detected and suppressed errors, rerun with: -v
==2971== Use --track-origins=yes to see where uninitialised values come from
==2971== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)
[1]    2971 segmentation fault (core dumped)  valgrind ./zappy_server --h

你知道发生了什么吗?这是我第一次使用getopt api,我完全迷失了。这似乎是因为我的选择带有前缀 - 但我不知道为什么......

这是我的完整代码:

static void fill_help_opt(struct option *help_opt)
{
  help_opt->name = "help";
  help_opt->has_arg = 0;
  help_opt->flag = NULL;
  help_opt->val = 'h';
}

int         getopt_server_parsing(int argc, char **argv,
                          t_server_params *params)
{
    int         get_opt_err;
    t_opts_checkers opts_fcts[7];
    int         idx;
    struct option       help_opt;

    fill_opts_fcts(opts_fcts);
    fill_help_opt(&help_opt);
    get_opt_err = 0;
    while ((get_opt_err = getopt_long(argc, argv, "p:x:y:n:c:f:h",
                    &help_opt, NULL)) != -1)
    {
        idx = 0;
        while (idx < 7)
        {
            if (opts_fcts[idx].key == get_opt_err
                    && opts_fcts[idx].value(optarg, params, argv) != 0)
                return (1);
            ++idx;
        }
        if (get_opt_err == '?')
            return (1);
    }
    return (0);
}

我不想粘贴所有东西,因为我的学校可以找到这些代码并责怪我作弊......(因为复制/粘贴代码,即使它是我的代码)。

1 个答案:

答案 0 :(得分:2)

getopt_long的第三个参数不应该是单个struct option的地址,而是指向struct option数组的第一个元素的指针,其中最后一个应填充用零。

因为您没有传入数组,getopt_long会尝试读取过去help_opt,就好像它是一个数组一样。这会调用undefined behavior

help_opt更改为最后一个元素归零的数组。

struct option help_opt[] = {
    { "help", 0, NULL, 'h' },
    { NULL, 0, NULL, 0 }
};

...

while ((get_opt_err = getopt_long(argc, argv, "p:x:y:n:c:f:h",
                help_opt, NULL)) != -1)