调用 globfree() 时出现分段错误

Posted

技术标签:

【中文标题】调用 globfree() 时出现分段错误【英文标题】:Segmentation fault while calling globfree() 【发布时间】:2019-11-13 04:44:35 【问题描述】:

[使用 arm-hisiv300-linux-gcc 编译基于 Linux 的 Target board]

我在调用这个函数时遇到了分段错误。

uint32_t dir_disp(void)

    uint32_t        err;
    uint32_t        i;
    size_t          cnt;
    char            *str;
    char            **p;

    glob_t          glob_results;   

    err = glob("/home/2019-11-12/H*", GLOB_MARK, 0, &glob_results);

    p = glob_results.gl_pathv;
    cnt = glob_results.gl_pathc;

    for (i=0; i<cnt; i++)
    
        printf("[DEBUG] dir_disp: %s\n",p[i]);
    

    globfree(&glob_results);
    return 0;

上述函数仅在线程函数中调用一次,仅当匹配模式“/home/2019-11-12/H*”的项目超过~100个时才会发生分段错误

在以下情况下不会发生分段错误:

与模式匹配的项目少于~100 或将for循环中的printf注释掉 或注释掉 globfree() 或在没有线程的另一个程序中调用该函数

[编辑]

抱歉,我忘了说只有在打印了所有与模式匹配的项目后才会出现段错误。

我检查了glob() 的 ret val,发现它为零。不改变原来的问题。

【问题讨论】:

在出现段错误的情况下,err 中的内容是什么? (为什么你的代码不检查它?) 错误为零,我现在检查。 函数:glob() 返回int,而不是uint32_t @user3629249 感谢您指出这一点,错误应该是 int 签名的。但在这种情况下,这两种情况都是一样的。 你应该检查 glob 函数的 ret,因为如果 ret 不为 0,使用 glob_results 是未定义的行为。 【参考方案1】:

根据 Linux 手册页,glob() 是 not MT-safe,所以它是 "not safe to call in a multithreaded program"。

可能值得注意的是,Posix 确实要求 glob() 是 MT 安全的,因此此属性特定于 glibc 中的 Gnu 实现,并且可能与 Gnu 扩展有关,例如波浪号扩展选项。尽管如此,您应该注意警告。

根据您报告的症状,可能的问题是堆栈溢出,可能与在glob 实现中使用alloca 或VLA 有关。 (不过,我没有检查源代码;我没有特别证据表明实际使用了这些功能。)多线程代码中的默认堆栈大小往往非常小,在非 MT 环境中运行良好的代码很容易超过默认线程的堆栈大小。您可以在创建调用 glob 的线程时尝试增加堆栈大小。

【讨论】:

具体来说是MT-Unsafe race:utent env sig:ALRM timer locale。这是否意味着它仅在那些特定的方面是不安全的,如果你的程序避免了这些情况,那么调用多线程程序就可以了吗? @joseph:是的,就是这个意思。而且,正如我所说,这些问题可能仅由该功能的某些用途触发,尽管这在任何地方都没有记录。所以这不一定是不使用glob 的理由,但它确实表明需要谨慎。我认为堆栈溢出更可能是罪魁祸首。 @rici 感谢队友,一旦我在 pthread 中分配了更多堆栈,段错误就消失了。【参考方案2】:

以下建议的代码:

    干净编译 执行所需的功能

注意glob()的第一个参数是如何写的

现在,建议的代码:

#include <stdint.h>
#include <glob.h>
#include <stdio.h>


uint32_t dir_disp(void)

    int             err;
    size_t          cnt;
    char            **p;

    glob_t          glob_results;   

    err = glob("/home/richard/*", GLOB_MARK, 0, &glob_results);

    printf( "err: %d\n", err );

    p = glob_results.gl_pathv;
    cnt = glob_results.gl_pathc;

    for (size_t i=0; i<cnt; i++)
    
        printf("[DEBUG] dir_disp: %s\n",p[i]);
    

    globfree(&glob_results);
    return 0;



int main( void )

    uint32_t result = dir_disp();
    printf( "result: %d\n", result );

上述代码的运行结果:

err: 0
[DEBUG] dir_disp: /home/richard/Desktop/
[DEBUG] dir_disp: /home/richard/Documents/
[DEBUG] dir_disp: /home/richard/Downloads/
[DEBUG] dir_disp: /home/richard/Music/
[DEBUG] dir_disp: /home/richard/OpenMPI/
[DEBUG] dir_disp: /home/richard/Pictures/
[DEBUG] dir_disp: /home/richard/Public/
[DEBUG] dir_disp: /home/richard/Templates/
[DEBUG] dir_disp: /home/richard/Videos/
[DEBUG] dir_disp: /home/richard/examples.desktop
result: 0

还有很多其他目录,但它们与此答案无关

【讨论】:

对不起,伙计,但我确实提到如果不在线程中,代码工作正常。 好吧,dir_disp() 的签名对线程无效。线程的正确退出是通过:pthread_exit( NULL ); 和启动线程的函数需要调用pthread_create() 来启动线程,然后调用pthread_join( NULL ); 来等待线程完成。编程时,细节决定了工作和崩溃。一个线程有它自己的栈。也许您需要修改线程的堆栈分配 dir_disp() 不是线程函数,而是从线程中运行的函数调用的。 那么您需要发布minimal reproducible example,以便我们全面了解正在发生的事情。然后我们可以帮助您调试它。

以上是关于调用 globfree() 时出现分段错误的主要内容,如果未能解决你的问题,请参考以下文章

将结构插入地图时出现分段错误

删除时出现分段错误

在调用函数中取消引用指针时出现分段错误

分配时出现分段错误[重复]

调用 c 函数时出现分段错误

从 C 调用汇编函数时出现分段错误错误