diff options
author | Stefan Sperling <stsp@openbsd.org> | 2013-11-21 18:47:42 +0100 |
---|---|---|
committer | Tanu Kaskinen <tanu.kaskinen@linux.intel.com> | 2013-11-22 17:31:11 +0200 |
commit | d8e2b3a78c6c60ffec9a115a0e35a3cb4c68598f (patch) | |
tree | be2de26e622f80c94b4bc3c15454f0453b4c0452 | |
parent | 303cff04eb8c091fb0c7665440797fc56f07d570 (diff) |
Fix undefined behaviour in pulseaudio --start.
Don't call pthread_join() to join a thread from a different
process than the thread was created in. Doing so can lead to
undefined behaviour.
On OpenBSD, the symptom was a pulseaudio process with a single
thread waiting forever for other threads to join. Since that
process also held the autospawn lock, starting new pulseaudio
processes with --start kept failing. The problem was analyzed
with help from Philip Guenther.
This patch adds a pa_thread_free_nojoin() function which can
be used to free resources for a thread without a join, as
suggested by Tanu Kaskinen.
See https://bugs.freedesktop.org/show_bug.cgi?id=71738
-rw-r--r-- | src/pulsecore/lock-autospawn.c | 9 | ||||
-rw-r--r-- | src/pulsecore/thread-posix.c | 7 | ||||
-rw-r--r-- | src/pulsecore/thread.h | 1 |
3 files changed, 16 insertions, 1 deletions
diff --git a/src/pulsecore/lock-autospawn.c b/src/pulsecore/lock-autospawn.c index 72806f831..82518dbac 100644 --- a/src/pulsecore/lock-autospawn.c +++ b/src/pulsecore/lock-autospawn.c @@ -114,8 +114,15 @@ static void unref(bool after_fork) { if (n_ref > 0) return; + /* Join threads only in the process the new thread was created in + * to avoid undefined behaviour. + * POSIX.1-2008 XSH 2.9.2 Thread IDs: "applications should only assume + * that thread IDs are usable and unique within a single process." */ if (thread) { - pa_thread_free(thread); + if (after_fork) + pa_thread_free_nojoin(thread); + else + pa_thread_free(thread); thread = NULL; } diff --git a/src/pulsecore/thread-posix.c b/src/pulsecore/thread-posix.c index b422ab098..5c19b43f5 100644 --- a/src/pulsecore/thread-posix.c +++ b/src/pulsecore/thread-posix.c @@ -127,6 +127,13 @@ void pa_thread_free(pa_thread *t) { pa_xfree(t); } +void pa_thread_free_nojoin(pa_thread *t) { + pa_assert(t); + + pa_xfree(t->name); + pa_xfree(t); +} + int pa_thread_join(pa_thread *t) { pa_assert(t); pa_assert(t->thread_func); diff --git a/src/pulsecore/thread.h b/src/pulsecore/thread.h index 9cabb8995..a6e5f4240 100644 --- a/src/pulsecore/thread.h +++ b/src/pulsecore/thread.h @@ -39,6 +39,7 @@ typedef void (*pa_thread_func_t) (void *userdata); pa_thread* pa_thread_new(const char *name, pa_thread_func_t thread_func, void *userdata); void pa_thread_free(pa_thread *t); +void pa_thread_free_nojoin(pa_thread *t); int pa_thread_join(pa_thread *t); int pa_thread_is_running(pa_thread *t); pa_thread *pa_thread_self(void); |