diff --git a/libc/bionic/pthread_atfork.cpp b/libc/bionic/pthread_atfork.cpp index 2200a6c36..84e511c2e 100644 --- a/libc/bionic/pthread_atfork.cpp +++ b/libc/bionic/pthread_atfork.cpp @@ -130,13 +130,15 @@ void __bionic_atfork_run_prepare() { } void __bionic_atfork_run_child() { + g_atfork_list_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; + + pthread_mutex_lock(&g_atfork_list_mutex); g_atfork_list.walk_forward([](atfork_t* it) { if (it->child != nullptr) { it->child(); } }); - - g_atfork_list_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; + pthread_mutex_unlock(&g_atfork_list_mutex); } void __bionic_atfork_run_parent() { diff --git a/tests/pthread_dlfcn_test.cpp b/tests/pthread_dlfcn_test.cpp index 64423dada..1c733feff 100644 --- a/tests/pthread_dlfcn_test.cpp +++ b/tests/pthread_dlfcn_test.cpp @@ -37,6 +37,11 @@ static void AtForkChild2() { g_atfork_child_calls = (g_atfork_child_calls * 10) static void AtForkChild3() { g_atfork_child_calls = (g_atfork_child_calls * 10) + 3; } static void AtForkChild4() { g_atfork_child_calls = (g_atfork_child_calls * 10) + 4; } +static void* g_atfork_test_handle = nullptr; +static void AtForkPrepare() {} +static void AtForkParent() {} +static void AtForkChild() { dlclose(g_atfork_test_handle); g_atfork_test_handle = dlopen("libtest_pthread_atfork.so", RTLD_NOW | RTLD_LOCAL); } + TEST(pthread, pthread_atfork_with_dlclose) { ASSERT_EQ(0, pthread_atfork(AtForkPrepare1, AtForkParent1, AtForkChild1)); @@ -82,3 +87,28 @@ TEST(pthread, pthread_atfork_with_dlclose) { AssertChildExited(pid, 0); } + +TEST(pthread, pthread_atfork_child_with_dlclose) { + + g_atfork_test_handle = dlopen("libtest_pthread_atfork.so", RTLD_NOW | RTLD_LOCAL); + ASSERT_TRUE(g_atfork_test_handle != nullptr) << dlerror(); + typedef int (*fn_t)(void (*)(void), void (*)(void), void (*)(void)); + fn_t fn = reinterpret_cast(dlsym(g_atfork_test_handle, "proxy_pthread_atfork")); + ASSERT_TRUE(fn != nullptr) << dlerror(); + // the library registers 2 additional atfork handlers in a constructor + + ASSERT_EQ(0, pthread_atfork(AtForkPrepare, AtForkParent, AtForkChild)); + + pid_t pid = fork(); + + ASSERT_NE(-1, pid) << strerror(errno); + + if (pid == 0) { + _exit(0); + } + + AssertChildExited(pid, 0); + + EXPECT_EQ(0, dlclose(g_atfork_test_handle)); + g_atfork_test_handle = nullptr; +}