【问题标题】:Why segfaults occur with string.h functions?为什么 string.h 函数会出现段错误?
【发布时间】:2017-09-01 06:41:33
【问题描述】:

在我同事的 PC 中使用相同的命令,我的程序可以正常运行。 但在我的电脑中,程序因段错误而崩溃;

核心的GDB回溯如下:

#0 strrchr () at ../sysdeps/x86_64/strrchr.S:32
32     ../sysdeps/x86_64/strrchr.S: no such file or directory
(gdb) bt
#0 strrchr () at ../sysdeps/x86_64/strrchr.S:32
#1 0x00007f10961236d7 in dirname (path=0x324a47a0 <error: Cannot access memory at address 0x324a47a0>) at dirname.c:31

我已经在使用 -g -ggdb 选项编译可执行文件。

奇怪的是.. 使用 valgrind 程序在我的 PC 上也能正常工作。

我该如何解决这个问题?我观察到这些错误只发生在 strrchr、strcmp、strlen、... string.h 函数中。

+Edit:gdb回溯表明程序在此处崩溃:

char* base_dir = dirname(get_abs_name(test_dir));

get_abs_name 定义为

char* get_abs_name(char* dir) {
    char abs_path[PATH_MAX];
    char* c = malloc(PATH_MAX*sizeof(char));
    realpath(dir, abs_path);
    strcpy(c, abs_path);
    return c;
}

+Edit2: 'dir' 是某个文件的路径,比如'../program/blabla.jpg'。

使用 valgrind,

printf("%s\n", dir)

通常打印“/home/frozenca/path_to_program”。 我猜不出为什么没有 valgrind 程序会崩溃..

【问题讨论】:

  • 您的程序中有错误。很可能是一些缓冲区溢出。发布代码以获得有用的答案。
  • 所以您希望我们在不查看代码的情况下修复您的代码。好。 .
  • 请研究minimal reproducible example 的概念并阅读How to Ask
  • 错误出现在strchr/strcmp/strlen/etc。不是因为这些函数有错误,而是因为您自己的代码以您不应该的方式(直接或间接)调用这些函数。您需要检查 realpath() 是否成功 - 因为您没有在这里检查错误,也许还有其他重要的地方您忘记检查并捕获真正的错误。您还需要检查函数的 dir 参数,以验证它是否包含您认为它应该包含的内容(并向我们展示它包含的内容)。
  • @spectras 我正要编辑我的评论以包含该信息:) 所以基本上该函数是realpath 的包装,并且无用(而且有问题)。

标签: c


【解决方案1】:

没有Minimal, Complete, and Verifiable example,我们无法确定。您的代码看起来大部分是正确的(尽管很复杂),只是您不检查错误。

char* get_abs_name(char* dir) {
    char abs_path[PATH_MAX];
    char* c = malloc(PATH_MAX*sizeof(char));  /* this may return NULL */
    realpath(dir, abs_path);                  /* this may return NULL */
    strcpy(c, abs_path);
    return c;
}

现在,这怎么会导致您看到的错误?好吧,如果malloc 返回 NULL,您将在strcpy 中立即崩溃。但是如果realpath 失败:

  • abs_path 的内容仍未定义。
  • 所以strcpy(c, abs_path) 将复制未定义的内容。如果abs_path[0] 恰好是\0,这可能导致它只复制一个字节。但也可能导致大量堆损坏。这取决于不相关的条件,例如程序是如何编译的,以及是否附加了一些调试工具,例如 valgrind

TL;DR:养成检查每个可能失败的功能的习惯。

char* get_abs_name(char* dir) {
    char abs_path[PATH_MAX];
    char* c = malloc(PATH_MAX*sizeof(char));
    if (!c) { return NULL; }
    if (!realpath(dir, abs_path)) {
        free(c);
        return NULL;
    }
    strcpy(c, abs_path);
    return c;
}

或者,在这里,假设是 GNU 系统或 POSIX.1-2008 系统,您可以大大简化它:

char * get_abs_name(const char * dir) {
    return realpath(dir, NULL);
}

但请注意,无论哪种方式,在您的主程序中,您还必须检查 get_abs_name() 没有返回 NULL,否则 dirname() 将崩溃。

【讨论】:

    【解决方案2】:

    完全删除你的函数,改用realpath(dir, NULL)的返回值。

    【讨论】:

      【解决方案3】:

      转换类型

      char* c = malloc(PATH_MAX*sizeof(char));
      

      谢谢!

      【讨论】:

        猜你喜欢
        • 2011-05-18
        • 2011-04-23
        • 2013-01-29
        • 2013-02-11
        相关资源
        最近更新 更多