From: Apple Date: Thu, 2 Feb 2012 16:15:52 +0000 (+0000) Subject: dyld-195.6.tar.gz X-Git-Tag: mac-os-x-1073^0 X-Git-Url: https://git.saurik.com/apple/dyld.git/commitdiff_plain/ee50caae846913bb8e5e48b51a2dd974b8f7a0e1 dyld-195.6.tar.gz --- diff --git a/src/dyld.cpp b/src/dyld.cpp index d86e0b1..31265a9 100644 --- a/src/dyld.cpp +++ b/src/dyld.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -382,6 +383,29 @@ void warn(const char* format, ...) } +// 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* 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::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::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::iterator it=sAllImages.begin(); it != sAllImages.end(); it++) { - if ( *it == image ) { - sAllImages.erase(it); - break; - } - } + allImagesLock(); + for (std::vector::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 index 0000000..4a7020a --- /dev/null +++ b/unit-tests/test-cases/concurrent-dlopen-initializers/Makefile @@ -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 index 0000000..3f2cbaf --- /dev/null +++ b/unit-tests/test-cases/concurrent-dlopen-initializers/foo.c @@ -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 index 0000000..d5199c9 --- /dev/null +++ b/unit-tests/test-cases/concurrent-dlopen-initializers/main.c @@ -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 // fprintf(), NULL +#include // exit(), EXIT_SUCCESS +#include +#include +#include + +#include +#include + +#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; +}