]> git.saurik.com Git - apple/dyld.git/commitdiff
dyld-195.6.tar.gz mac-os-x-1073 mac-os-x-1074 mac-os-x-1075 v195.6
authorApple <opensource@apple.com>
Thu, 2 Feb 2012 16:15:52 +0000 (16:15 +0000)
committerApple <opensource@apple.com>
Thu, 2 Feb 2012 16:15:52 +0000 (16:15 +0000)
src/dyld.cpp
unit-tests/test-cases/concurrent-dlopen-initializers/Makefile [new file with mode: 0644]
unit-tests/test-cases/concurrent-dlopen-initializers/foo.c [new file with mode: 0644]
unit-tests/test-cases/concurrent-dlopen-initializers/main.c [new file with mode: 0644]

index d86e0b1717850cd5b37816474212680108331e20..31265a9b7bad6c984fd1d600658aeec4b90a78e4 100644 (file)
@@ -37,6 +37,7 @@
 #include <mach-o/loader.h> 
 #include <mach-o/ldsyms.h> 
 #include <libkern/OSByteOrder.h> 
+#include <libkern/OSAtomic.h>
 #include <mach/mach.h>
 #include <sys/sysctl.h>
 #include <sys/mman.h>
@@ -382,6 +383,29 @@ void warn(const char* format, ...)
 }
 
 
+// <rdar://problem/8867781> control access to sAllImages through a lock 
+// because global dyld lock is not held during initialization phase of dlopen()
+static long sAllImagesLock = 0;
+
+static void allImagesLock()
+{
+    //dyld::log("allImagesLock()\n");
+       while ( ! OSAtomicCompareAndSwapPtrBarrier((void*)0, (void*)1, (void**)&sAllImagesLock) ) {
+        // spin
+    }
+}
+
+static void allImagesUnlock()
+{
+    //dyld::log("allImagesUnlock()\n");
+       while ( ! OSAtomicCompareAndSwapPtrBarrier((void*)1, (void*)0, (void**)&sAllImagesLock) ) {
+        // spin
+   }
+}
+
+
+
+
 // utility class to assure files are closed when an exception is thrown
 class FileOpener {
 public:
@@ -627,18 +651,20 @@ static void notifyBatchPartial(dyld_image_states state, bool orLater, dyld_image
        std::vector<dyld_image_state_change_handler>* handlers = stateToHandlers(state, sBatchHandlers);
        if ( handlers != NULL ) {
                // don't use a vector because it will use malloc/free and we want notifcation to be low cost
-               ImageLoader* images[sAllImages.size()+1];
-               ImageLoader** end = images;
-               for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
-                       dyld_image_states imageState = (*it)->getState();
-                       if ( (imageState == state) || (orLater && (imageState > state)) )
-                               *end++ = *it;
-               }
+        allImagesLock();
+        ImageLoader* images[sAllImages.size()+1];
+        ImageLoader** end = images;
+        for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
+            dyld_image_states imageState = (*it)->getState();
+            if ( (imageState == state) || (orLater && (imageState > state)) )
+                *end++ = *it;
+        }
                if ( sBundleBeingLoaded != NULL ) {
                        dyld_image_states imageState = sBundleBeingLoaded->getState();
                        if ( (imageState == state) || (orLater && (imageState > state)) )
                                *end++ = sBundleBeingLoaded;
                }
+        const char* dontLoadReason = NULL;
                unsigned int count = end-images;
                if ( end != images ) {
                        // sort bottom up
@@ -662,8 +688,7 @@ static void notifyBatchPartial(dyld_image_states state, bool orLater, dyld_image
                                if ( (result != NULL) && (state == dyld_image_state_dependents_mapped) ) {
                                        //fprintf(stderr, "  images rejected by handler=%p\n", onlyHandler);
                                        // make copy of thrown string so that later catch clauses can free it
-                                       const char* str = strdup(result);
-                                       throw str;
+                                       dontLoadReason = strdup(result);
                                }
                        }
                        else {
@@ -673,12 +698,15 @@ static void notifyBatchPartial(dyld_image_states state, bool orLater, dyld_image
                                        if ( (result != NULL) && (state == dyld_image_state_dependents_mapped) ) {
                                                //fprintf(stderr, "  images rejected by handler=%p\n", *it);
                                                // make copy of thrown string so that later catch clauses can free it
-                                               const char* str = strdup(result);
-                                               throw str;
+                                               dontLoadReason = strdup(result);
+                                               break;
                                        }
                                }
                        }
                }
+        allImagesUnlock();
+        if ( dontLoadReason != NULL )
+            throw dontLoadReason;
        }
 #if CORESYMBOLICATION_SUPPORT
        if ( state == dyld_image_state_rebased ) {
@@ -758,7 +786,9 @@ static void setRunInitialzersOldWay()
 static void addImage(ImageLoader* image)
 {
        // add to master list
-       sAllImages.push_back(image);
+    allImagesLock();
+        sAllImages.push_back(image);
+    allImagesUnlock();
        
        // update mapped ranges
        uintptr_t lastSegStart = 0;
@@ -832,12 +862,14 @@ void removeImage(ImageLoader* image)
        removedMappedRanges(image);
 
        // remove from master list
-       for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
-               if ( *it == image ) {
-                       sAllImages.erase(it);
-                       break;
-               }
-       }
+    allImagesLock();
+        for (std::vector<ImageLoader*>::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) {
+            if ( *it == image ) {
+                sAllImages.erase(it);
+                break;
+            }
+        }
+    allImagesUnlock();
        
        // flush find-by-address cache (do this after removed from master list, so there is no chance it can come back)
        if ( sLastImageByAddressCache == image )
@@ -1559,12 +1591,12 @@ static void checkSharedRegionDisable()
 
 bool validImage(const ImageLoader* possibleImage)
 {
-       const unsigned int imageCount = sAllImages.size();
-       for(unsigned int i=0; i < imageCount; ++i) {
-               if ( possibleImage == sAllImages[i] ) {
-                       return true;
-               }
-       }
+    const unsigned int imageCount = sAllImages.size();
+    for(unsigned int i=0; i < imageCount; ++i) {
+        if ( possibleImage == sAllImages[i] ) {
+            return true;
+        }
+    }
        return false;
 }
 
diff --git a/unit-tests/test-cases/concurrent-dlopen-initializers/Makefile b/unit-tests/test-cases/concurrent-dlopen-initializers/Makefile
new file mode 100644 (file)
index 0000000..4a7020a
--- /dev/null
@@ -0,0 +1,42 @@
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+all-check: all check
+
+check:
+       ./main
+
+all: main 
+
+main : main.c foo.c
+       ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo1.dylib
+       ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo2.dylib
+       ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo3.dylib
+       ${CC} ${CCFLAGS} foo.c -dynamiclib -o libfoo4.dylib
+       ${CC} ${CCFLAGS} -I${TESTROOT}/include -o main main.c
+
+clean:
+       ${RM} ${RMFLAGS} *~ main libfoo1.dylib libfoo2.dylib libfoo3.dylib libfoo4.dylib
+
diff --git a/unit-tests/test-cases/concurrent-dlopen-initializers/foo.c b/unit-tests/test-cases/concurrent-dlopen-initializers/foo.c
new file mode 100644 (file)
index 0000000..3f2cbaf
--- /dev/null
@@ -0,0 +1,4 @@
+
+void foo() {}
+void bar() {}
+void baz() {}
diff --git a/unit-tests/test-cases/concurrent-dlopen-initializers/main.c b/unit-tests/test-cases/concurrent-dlopen-initializers/main.c
new file mode 100644 (file)
index 0000000..d5199c9
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2010 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+#include <stdio.h>  // fprintf(), NULL
+#include <stdlib.h> // exit(), EXIT_SUCCESS
+#include <string.h>
+#include <unistd.h>
+#include <mach-o/dyld_priv.h>
+
+#include <dlfcn.h>
+#include <pthread.h>
+
+#include "test.h" // PASS(), FAIL(), XPASS(), XFAIL()
+
+
+static void* work(void* libName)
+{
+       for (int i=0; i < 500; ++i) {
+               void* handle = dlopen((char*)libName, 0);
+               if ( handle == NULL ) {
+                       FAIL("dlopen failed: %s", dlerror());
+                       exit(0);
+               }
+               dlclose(handle);        
+       }
+       
+       return NULL;
+}
+
+static const char* batchMappedHandler(enum dyld_image_states state, uint32_t infoCount, const struct dyld_image_info info[])
+{
+       usleep(10000);
+       return NULL;
+}
+
+
+int main()
+{
+       // tell dyld we want to know when images are mapped
+       dyld_register_image_state_change_handler(dyld_image_state_initialized, false, batchMappedHandler);
+
+       // other thread dlopens and closes libfoo.dylib 500 times
+       pthread_t t1;
+       if ( pthread_create(&t1, NULL, work, "libfoo1.dylib") != 0 ) {
+               FAIL("pthread_create failed");
+               exit(0);
+       }
+       
+       pthread_t t2;
+       if ( pthread_create(&t2, NULL, work, "libfoo2.dylib") != 0 ) {
+               FAIL("pthread_create failed");
+               exit(0);
+       }
+               
+       pthread_t t3;
+       if ( pthread_create(&t3, NULL, work, "libfoo3.dylib") != 0 ) {
+               FAIL("pthread_create failed");
+               exit(0);
+       }
+
+       pthread_t t4;
+       if ( pthread_create(&t4, NULL, work, "libfoo4.dylib") != 0 ) {
+               FAIL("pthread_create failed");
+               exit(0);
+       }
+
+       void* result;
+       pthread_join(t1, &result);
+       pthread_join(t2, &result);
+       pthread_join(t3, &result);
+       pthread_join(t4, &result);
+       
+       PASS("concurrent-dlopen-initializers");
+       return 0;
+}