Skip to content

Commit

Permalink
Fix a use-after-free bug for detached threads (#420)
Browse files Browse the repository at this point in the history
* Fix a use-after-free bug for detached threads

the issue was pointed out by @alexcrichton in
#405

* Rename map_base_lazy_free_queue as it only keeps a single item

Also, align the comment style with musl.
  • Loading branch information
yamt authored Jun 21, 2023
1 parent 5862047 commit 7018e24
Showing 1 changed file with 30 additions and 1 deletion.
31 changes: 30 additions & 1 deletion libc-top-half/musl/src/thread/pthread_create.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,17 @@ void __tl_sync(pthread_t td)
if (tl_lock_waiters) __wake(&__thread_list_lock, 1, 0);
}

#ifndef __wasilibc_unmodified_upstream
static void *map_base_deferred_free;

static void process_map_base_deferred_free()
{
/* called with __tl_lock held */
free(map_base_deferred_free);
map_base_deferred_free = NULL;
}
#endif

#ifdef __wasilibc_unmodified_upstream
_Noreturn void __pthread_exit(void *result)
#else
Expand Down Expand Up @@ -182,7 +193,17 @@ static void __pthread_exit(void *result)
}
#else
if (state==DT_DETACHED && self->map_base) {
free(self->map_base);
/* As we use malloc/free which is considerably more complex
* than mmap/munmap to call and can even require a valid
* thread context, it's difficult to implement __unmapself.
*
* Here we take an alternative approach which simply defers
* the deallocation. An obvious downside of this approach is
* that it keeps the stack longer. (possibly forever.)
* To avoid wasting too much memory, we only defer a single
* item at most. */
process_map_base_deferred_free();
map_base_deferred_free = self->map_base;
// Can't use `exit()` here, because it is too high level
return;
}
Expand Down Expand Up @@ -424,6 +445,14 @@ int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict att
if (map == MAP_FAILED) goto fail;
}
#else
/* Process the deferred free request if any before
* allocationg a new one. Hopefully it enables a reuse of the memory.
*
* Note: We can't perform a simple "handoff" becasue allocation
* sizes might be different. (eg. the stack size might differ) */
__tl_lock();
process_map_base_deferred_free();
__tl_unlock();
map = malloc(size);
if (!map) goto fail;
#endif
Expand Down

0 comments on commit 7018e24

Please sign in to comment.