misc/188425: Frequent segfault with multithreaded fork

Alex Crichton acrichton at mozilla.com
Thu Apr 10 15:10:02 UTC 2014


>Number:         188425
>Category:       misc
>Synopsis:       Frequent segfault with multithreaded fork
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Thu Apr 10 15:10:01 UTC 2014
>Closed-Date:
>Last-Modified:
>Originator:     Alex Crichton
>Release:        10.0-RELEASE-p1
>Organization:
Mozilla
>Environment:
FreeBSD freebsd-vm 10.0-RELEASE-p1 FreeBSD 10.0-RELEASE-p1 #0: Tue Apr  8 06:45:06 UTC 2014     root at amd64-builder.daemonology.net:/usr/obj/usr/src/sys/GENERIC  amd64

>Description:
Recently we've found that FreeBSD is segfaulting or hanging frequently when dealing with what we suspect is a multithreaded forking situation. I've written a small program (attached) which exhibits the bug. This program will segfault or trip an assertion in libthr frequently, but not always.


>How-To-Repeat:
1. Download attached bug.c
2. clang -o bug bug.c -lthr
3. Run the program repeatedly until it segfaults, normally requiring less than 500 runs.

When running the program, I've been using this script:

  for i in {1..1000}; do; echo $i; ./bug || break; done
>Fix:


Patch attached with submission follows:

#include <assert.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

static pthread_mutex_t lock;
static pthread_cond_t cond;
static volatile int cnt = 0;

static void test() {
  int p = fork();
  assert(p >= 0);
  if (p == 0) {
    _exit(0);
  }
  int a = 1;
  assert(waitpid(p, &a, 0) == p);
  assert(WEXITSTATUS(a) == 0);
}

static void *child(void *arg) {
  test();

  assert(pthread_mutex_lock(&lock) == 0);
  cnt -= 1;
  if (cnt == 0) {
    assert(pthread_cond_signal(&cond) == 0);
  }
  assert(pthread_mutex_unlock(&lock) == 0);
  return arg;
}

int main() {
  assert(pthread_mutex_init(&lock, NULL) == 0);
  assert(pthread_cond_init(&cond, NULL) == 0);

  pthread_t c1, c2;
  cnt = 2;
  assert(pthread_create(&c1, NULL, child, NULL) == 0);
  assert(pthread_create(&c2, NULL, child, NULL) == 0);

  assert(pthread_mutex_lock(&lock) == 0);
  while (cnt != 0) {
    assert(pthread_cond_wait(&cond, &lock) == 0);
  }
  assert(pthread_mutex_unlock(&lock) == 0);

  pthread_join(c1, NULL);
  pthread_join(c2, NULL);
}


>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list