在linux上,只有ulimit -s设置为unlimited时,我的程序才会崩溃。
segfaults的位置在Libmicrohttpd的连接回调中,因此回溯非常深(大约设置了10个函数)。
我在此回调中首先调用的功能是崩溃的地方,即使只是printf也是如此。这是来自coredump的stacktrace:
#0 0x000000341fa44089 in vfprintf () from /lib64/libc.so.6
#1 0x000000341fa4ef58 in fprintf () from /lib64/libc.so.6
#2 0x000000000044488d in answer_to_connection (cls=0x7fffc57b0170, connection=0x2b59bc0008c0, url=0x2b59bc000a84 "/remote.html", method=0x2b59bc000a80 "GET", version=0x2b59bc000a9f "HTTP/1.0", upload_data=0x0, upload_data_size=0x2b59b94247b8, con_cls=0x2b59bc000918) at network.c:149
#3 0x00000000004f7f9f in call_connection_handler (connection=connection@entry=0x2b59bc0008c0) at../../../src/microhttpd/connection.c:2284
#4 0x00000000004f92f8 in MHD_connection_handle_idle (connection=connection@entry=0x2b59bc0008c0) at ../../../src/microhttpd/connection.c:3361
#5 0x00000000004fae81 in call_handlers (con=con@entry=0x2b59bc0008c0, read_ready=<optimized out>, write_ready=<optimized out>, force_close=<optimized out>) at ../../../src/microhttpd/daemon.c:1113
#6 0x00000000004fd93b in thread_main_handle_connection (data=0x2b59bc0008c0) at ../../../src/microhttpd/daemon.c:1965
#7 0x0000003420607aa1 in start_thread () from /lib64/libpthread.so.0
#8 0x000000341fae8bcd in clone () from /lib64/libc.so.6
如果我将ulimit -s设置为8192,则一切正常。
我习惯于必须增加堆栈大小的错误。
但是,为什么它会在较小的堆栈上工作,而在无限的情况下失败?
编辑:
它绝对与线程有关。简单的例子:
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
void function(char arg){
char buffer[666666];
if(arg > 0){
memset(buffer, arg, 6666);
fprintf(stderr, "DONE %p\n", &buffer);
function(arg - 1);
}
}
void *thread(void *arg){
int a;
fprintf(stderr, "THREAD %p\n", &a);
function(6);
return NULL;
}
int main(){
int i;
pthread_t p;
fprintf(stderr, "MAIN %p\n", &i);
pthread_create(&p, NULL, thread, NULL);
pthread_join(p, NULL);
}
使用ulimit -s 8192:
$ ./test
MAIN 0x7ffd73f9cc5c
THREAD 0x7fa4d12bfeac
DONE 0x7fa4d121d250
DONE 0x7fa4d117a600
DONE 0x7fa4d10d79b0
DONE 0x7fa4d1034d60
DONE 0x7fa4d0f92110
DONE 0x7fa4d0eef4c0
使用ulimit -s unlimited
$ ./test
MAIN 0x7ffd1438d4dc
THREAD 0x2ab91aef6eac
DONE 0x2ab91ae54250
DONE 0x2ab91adb1600
DONE 0x2ab91ad0e9b0
Segmentation fault (core dumped)
最佳答案
正如Mark Plotnick解释的那样,问题出在线程的默认堆栈大小上。拥有 ulimit -s无限制可使堆栈大小达到 2MB ,按今天的标准来说很小。
在 __pthread_initialize_minimal_internal()中更仔细地研究pthread代码
/* Determine the default allowed stack size. This is the size used
in case the user does not specify one. */
struct rlimit limit;
if (__getrlimit (RLIMIT_STACK, &limit) != 0
|| limit.rlim_cur == RLIM_INFINITY)
/* The system limit is not usable. Use an architecture-specific
default. */
limit.rlim_cur = ARCH_STACK_DEFAULT_SIZE;
else if (limit.rlim_cur < PTHREAD_STACK_MIN)
/* The system limit is unusably small.
Use the minimal size acceptable. */
limit.rlim_cur = PTHREAD_STACK_MIN;
/* Make sure it meets the minimum size that allocate_stack
(allocatestack.c) will demand, which depends on the page size. */
const uintptr_t pagesz = GLRO(dl_pagesize);
const size_t minstack = pagesz + __static_tls_size + MINIMAL_REST_STACK;
if (limit.rlim_cur < minstack)
limit.rlim_cur = minstack;
/* Round the resource limit up to page size. */
limit.rlim_cur = ALIGN_UP (limit.rlim_cur, pagesz);
lll_lock (__default_pthread_attr_lock, LLL_PRIVATE);
__default_pthread_attr.stacksize = limit.rlim_cur;
__default_pthread_attr.guardsize = GLRO (dl_pagesize);
lll_unlock (__default_pthread_attr_lock, LLL_PRIVATE);
pthread_create(3)的手册页仅提及Linux/x86-32的默认堆栈大小,但以下是glibc 2.3.3及更高版本中其他体系结构的值( ARCH_STACK_DEFAULT_SIZE ):
我已经向手册页提交了补丁,以包含此信息。再次感谢您在调查此问题方面的帮助。