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