调用 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() 时出现分段错误的主要内容,如果未能解决你的问题,请参考以下文章