Segfault with ulimit

On linux, I have a program that crashes only if ulimit -s is set to unlimited. The place where it segfaults is in a connection callback in Libmicrohttpd, so the backtrace is pretty deep (around 10 functions tacked up). Whatever the function I call first in this callback is where it crashes, even if it is just printf. Here is a stacktrace from coredump :

#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

If I set ulimit -s to, say 8192, everything works. I am used to bugs where one has to increase stack size. But why would it work with a smaller stack, and fail with unlimited ?

EDIT :

It definitively has to do with threads. Simple example :

#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 %pn", &buffer);
    function(arg - 1);
  }
}

void *thread(void *arg){
  int a;

  fprintf(stderr, "THREAD %pn", &a);

  function(6);

  return NULL;
}

int main(){
  int i;
  pthread_t p;

  fprintf(stderr, "MAIN %pn", &i);

  pthread_create(&p, NULL, thread, NULL);

  pthread_join(p, NULL);
}

With ulimit -s 8192 :

$ ./test 
MAIN 0x7ffd73f9cc5c
THREAD 0x7fa4d12bfeac
DONE 0x7fa4d121d250
DONE 0x7fa4d117a600
DONE 0x7fa4d10d79b0
DONE 0x7fa4d1034d60
DONE 0x7fa4d0f92110
DONE 0x7fa4d0eef4c0

With ulimit -s unlimited

$ ./test 
MAIN 0x7ffd1438d4dc
THREAD 0x2ab91aef6eac
DONE 0x2ab91ae54250
DONE 0x2ab91adb1600
DONE 0x2ab91ad0e9b0
Segmentation fault (core dumped)

As Mark Plotnick explained, the problem comes from the default stack size for thread. Having ulimit -s unlimited gives you a stack size of 2MB , a small size by today's standards.

Looking more closely into pthread code, in __pthread_initialize_minimal_internal()

 /* 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);

The man-page of pthread_create(3) only mentions the default stack size for Linux/x86-32, but here are the values for other architectures in glibc 2.3.3 and up ( ARCH_STACK_DEFAULT_SIZE ):

  • Sparc-32 : 2MB
  • Sparc-64 : 4MB
  • PowerPC : 4MB
  • S/390 : 2MB
  • IA-64 : 32MB
  • i386 : 2MB
  • x86_64 : 2MB
  • I have submitted a patch to the man-page to include this information. Thank you again for your help in investigating this issue.

    链接地址: http://www.djcxy.com/p/80260.html

    上一篇: 一个虚拟地址空间中的进程线程如何进行内存管理?

    下一篇: Segfault与ulimit