我在glibc-2.27
中使用pthread.h
库,当我的进程调用pthread_create()
十八次或十八次以上(它应该是一个繁重的多线程应用程序(时,进程将中止,并显示错误消息:
*** stack smashing detected ***: <unknown> terminated
Aborted (core dumped)
作为调试程序的一部分,我做了一些strace
,我找到了原因。显然,所有对mmap()
作为pthread_create()
一部分的隐式调用看起来都是这样的:
mmap(NULL, 8392704, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK, -1, 0) = 0x7f6de43fa000
可以注意到MAP_STACK
标志,它表示:
将映射分配到适合进程或线程堆栈的地址。这个标志目前是一个no-op,但在glibc线程实现中使用,因此,如果某些体系结构需要对堆栈分配进行特殊处理,那么稍后可以透明地实现对glibc的支持。
(我的系统上的man mmap
-Ubuntu 18.04 LTS(
是否可以将pthread_create
调用配置为不执行此操作?或者可能使用brk
或其他东西来自动增加数据段?
谢谢你的帮助!
您的问题极不可能与此MAP_STACK
标志有任何关系。
您的应用程序中有一个导致堆栈损坏的错误。尝试在valgrind下运行应用程序,或者使用-fsanitize=address
构建应用程序。任何一种方法都可能精确定位错误的确切位置,您应该能够在此基础上找出错误所在。
是否可以配置pthread_create调用不执行此操作?
pthread_create()
需要为线程的堆栈分配空间,否则线程无法运行——即使使用空线程函数也是如此。这就是你看到的mmap
的用途。没有它是不可能的。
或者使用brk或其他方法自动增加数据段?
如果您有时间和技能编写自己的线程库,请尝试一下,让我们知道会发生什么。否则,不,pthread_create()
如何为新线程的堆栈保留空间的细节在我所知道的任何实现中都是不可配置的。
无论如何,这并不重要,因为mmap()
调用不是问题所在。如果系统调用发生了不可恢复的故障,那么这就是内核的故障,并且会导致内核死机,而不是应用程序崩溃。GNUC的堆栈粉碎检测发生在用户空间中。因此,它所应用的函数不会出现在strace输出中,该输出仅跟踪系统调用。
这可能有助于你更好地理解堆栈粉碎和GNU对它的防御。Dobb博士几年前就在这方面发表了一篇很好的文章,现在仍然值得一读。不过,最重要的是,当函数实现重写其堆栈帧中包含其返回地址的部分而行为不端时,就会发生堆栈粉碎。除非你有一些内联程序集,否则崩溃几乎肯定是由你自己的一个函数超过了它的一个局部变量的界限引起的。当函数试图返回时,会通过函数尾声中的工具检测到它。