Loading...
// BUILD: $CC foo.c -bundle -o $BUILD_DIR/foo.bundle // BUILD: $CC bar.c -bundle -o $BUILD_DIR/bar.bundle // BUILD: $CC main.c -o $BUILD_DIR/dyld_fork_test2.exe -DRUN_DIR="$RUN_DIR" // RUN: ./dyld_fork_test2.exe #include <stdio.h> #include <dlfcn.h> #include <mach-o/dyld_priv.h> #include <pthread.h> #include "test_support.h" // Check for deadlock between dlopen and atfork_prepare // dlopen takes locks in the following order: // API, loader, notifier // atfork_prepare (at time of writing) did: // loader, notifier, API // which leads to deadlock as those are not the same order bool isParent = true; static void* work1(void* mh) { // fork and exec child pid_t sChildPid = fork(); if ( sChildPid < 0 ) { FAIL("Didn't fork"); } if ( sChildPid == 0 ) { // child side isParent = false; } return 0; } pthread_t workerThread1; bool runNotifier; static void notifyThread0(const struct mach_header* mh, intptr_t vmaddr_slide) { if (!runNotifier) return; runNotifier = false; // We are in a notifier in a dlopen, so the API and notifier locks are held. // Spawn a thread to do a fork, which will take the available locks, ie, maybe the loader lock workerThread1; if ( pthread_create(&workerThread1, NULL, &work1, NULL) != 0 ) { FAIL("pthread_create"); } // Wait for a short time, to make sure the fork took any available locks sleep(1); // Do another dlopen, which will deadlock as the fork thread has some locks void* h = dlopen(RUN_DIR "/bar.bundle", 0); if ( h == NULL ) FAIL("Failed to dlopen bar.bundle because: %s\n", dlerror()); } int main(int argc, const char* argv[], const char* envp[], const char* apple[]) { runNotifier = false; _dyld_register_func_for_add_image(¬ifyThread0); // Do a dlopen to trigger the notifier again runNotifier = true; void* h = dlopen(RUN_DIR "/foo.bundle", 0); if ( h == NULL ) FAIL("Failed to dlopen foo.bundle because: %s\n", dlerror()); void* dummy; pthread_join(workerThread1, &dummy); if (isParent) { // dlopen to make sure we can use the locks after fork() void* handle = dlopen("/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation", RTLD_LAZY); if ( handle == NULL ) FAIL("Could not dlopen CoreFoundation because: %s", dlerror()); PASS("Success"); } return 0; } |