1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081 |
- /*
- * Copyright (c) 2007 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@
- */
- /***********************************************************************
- * objc-os.m
- * OS portability layer.
- **********************************************************************/
- #include "objc-private.h"
- #include "objc-loadmethod.h"
- #include "objc-cache.h"
- #if TARGET_OS_WIN32
- #include "objc-runtime-old.h"
- #include "objcrt.h"
- const fork_unsafe_lock_t fork_unsafe_lock;
- int monitor_init(monitor_t *c)
- {
- // fixme error checking
- HANDLE mutex = CreateMutex(NULL, TRUE, NULL);
- while (!c->mutex) {
- // fixme memory barrier here?
- if (0 == InterlockedCompareExchangePointer(&c->mutex, mutex, 0)) {
- // we win - finish construction
- c->waiters = CreateSemaphore(NULL, 0, 0x7fffffff, NULL);
- c->waitersDone = CreateEvent(NULL, FALSE, FALSE, NULL);
- InitializeCriticalSection(&c->waitCountLock);
- c->waitCount = 0;
- c->didBroadcast = 0;
- ReleaseMutex(c->mutex);
- return 0;
- }
- }
- // someone else allocated the mutex and constructed the monitor
- ReleaseMutex(mutex);
- CloseHandle(mutex);
- return 0;
- }
- void mutex_init(mutex_t *m)
- {
- while (!m->lock) {
- CRITICAL_SECTION *newlock = malloc(sizeof(CRITICAL_SECTION));
- InitializeCriticalSection(newlock);
- // fixme memory barrier here?
- if (0 == InterlockedCompareExchangePointer(&m->lock, newlock, 0)) {
- return;
- }
- // someone else installed their lock first
- DeleteCriticalSection(newlock);
- free(newlock);
- }
- }
- void recursive_mutex_init(recursive_mutex_t *m)
- {
- // fixme error checking
- HANDLE newmutex = CreateMutex(NULL, FALSE, NULL);
- while (!m->mutex) {
- // fixme memory barrier here?
- if (0 == InterlockedCompareExchangePointer(&m->mutex, newmutex, 0)) {
- // we win
- return;
- }
- }
-
- // someone else installed their lock first
- CloseHandle(newmutex);
- }
- WINBOOL APIENTRY DllMain( HMODULE hModule,
- DWORD ul_reason_for_call,
- LPVOID lpReserved
- )
- {
- switch (ul_reason_for_call) {
- case DLL_PROCESS_ATTACH:
- environ_init();
- tls_init();
- runtime_init();
- sel_init(3500); // old selector heuristic
- exception_init();
- break;
- case DLL_THREAD_ATTACH:
- break;
- case DLL_THREAD_DETACH:
- case DLL_PROCESS_DETACH:
- break;
- }
- return TRUE;
- }
- OBJC_EXPORT void *_objc_init_image(HMODULE image, const objc_sections *sects)
- {
- header_info *hi = malloc(sizeof(header_info));
- size_t count, i;
- hi->mhdr = (const headerType *)image;
- hi->info = sects->iiStart;
- hi->allClassesRealized = NO;
- hi->modules = sects->modStart ? (Module *)((void **)sects->modStart+1) : 0;
- hi->moduleCount = (Module *)sects->modEnd - hi->modules;
- hi->protocols = sects->protoStart ? (struct old_protocol **)((void **)sects->protoStart+1) : 0;
- hi->protocolCount = (struct old_protocol **)sects->protoEnd - hi->protocols;
- hi->imageinfo = NULL;
- hi->imageinfoBytes = 0;
- // hi->imageinfo = sects->iiStart ? (uint8_t *)((void **)sects->iiStart+1) : 0;;
- // hi->imageinfoBytes = (uint8_t *)sects->iiEnd - hi->imageinfo;
- hi->selrefs = sects->selrefsStart ? (SEL *)((void **)sects->selrefsStart+1) : 0;
- hi->selrefCount = (SEL *)sects->selrefsEnd - hi->selrefs;
- hi->clsrefs = sects->clsrefsStart ? (Class *)((void **)sects->clsrefsStart+1) : 0;
- hi->clsrefCount = (Class *)sects->clsrefsEnd - hi->clsrefs;
- count = 0;
- for (i = 0; i < hi->moduleCount; i++) {
- if (hi->modules[i]) count++;
- }
- hi->mod_count = 0;
- hi->mod_ptr = 0;
- if (count > 0) {
- hi->mod_ptr = malloc(count * sizeof(struct objc_module));
- for (i = 0; i < hi->moduleCount; i++) {
- if (hi->modules[i]) memcpy(&hi->mod_ptr[hi->mod_count++], hi->modules[i], sizeof(struct objc_module));
- }
- }
-
- hi->moduleName = malloc(MAX_PATH * sizeof(TCHAR));
- GetModuleFileName((HMODULE)(hi->mhdr), hi->moduleName, MAX_PATH * sizeof(TCHAR));
- appendHeader(hi);
- if (PrintImages) {
- _objc_inform("IMAGES: loading image for %s%s%s%s\n",
- hi->fname,
- headerIsBundle(hi) ? " (bundle)" : "",
- hi->info->isReplacement() ? " (replacement)":"",
- hi->info->hasCategoryClassProperties() ? " (has class properties)":"");
- }
- // Count classes. Size various table based on the total.
- int total = 0;
- int unoptimizedTotal = 0;
- {
- if (_getObjc2ClassList(hi, &count)) {
- total += (int)count;
- if (!hi->getInSharedCache()) unoptimizedTotal += count;
- }
- }
- _read_images(&hi, 1, total, unoptimizedTotal);
- return hi;
- }
- OBJC_EXPORT void _objc_load_image(HMODULE image, header_info *hinfo)
- {
- prepare_load_methods(hinfo);
- call_load_methods();
- }
- OBJC_EXPORT void _objc_unload_image(HMODULE image, header_info *hinfo)
- {
- _objc_fatal("image unload not supported");
- }
- // TARGET_OS_WIN32
- #elif TARGET_OS_MAC
- #include "objc-file-old.h"
- #include "objc-file.h"
- /***********************************************************************
- * libobjc must never run static destructors.
- * Cover libc's __cxa_atexit with our own definition that runs nothing.
- * rdar://21734598 ER: Compiler option to suppress C++ static destructors
- **********************************************************************/
- extern "C" int __cxa_atexit();
- extern "C" int __cxa_atexit() { return 0; }
- /***********************************************************************
- * bad_magic.
- * Return YES if the header has invalid Mach-o magic.
- **********************************************************************/
- bool bad_magic(const headerType *mhdr)
- {
- return (mhdr->magic != MH_MAGIC && mhdr->magic != MH_MAGIC_64 &&
- mhdr->magic != MH_CIGAM && mhdr->magic != MH_CIGAM_64);
- }
- static header_info * addHeader(const headerType *mhdr, const char *path, int &totalClasses, int &unoptimizedTotalClasses)
- {
- header_info *hi;
- if (bad_magic(mhdr)) return NULL;
- bool inSharedCache = false;
- // Look for hinfo from the dyld shared cache.
- hi = preoptimizedHinfoForHeader(mhdr);
- if (hi) {
- // Found an hinfo in the dyld shared cache.
- // Weed out duplicates.
- if (hi->isLoaded()) {
- return NULL;
- }
- inSharedCache = true;
- // Initialize fields not set by the shared cache
- // hi->next is set by appendHeader
- hi->setLoaded(true);
- if (PrintPreopt) {
- _objc_inform("PREOPTIMIZATION: honoring preoptimized header info at %p for %s", hi, hi->fname());
- }
- #if !__OBJC2__
- _objc_fatal("shouldn't be here");
- #endif
- #if DEBUG
- // Verify image_info
- size_t info_size = 0;
- const objc_image_info *image_info = _getObjcImageInfo(mhdr,&info_size);
- ASSERT(image_info == hi->info());
- #endif
- }
- else
- {
- // Didn't find an hinfo in the dyld shared cache.
- // Locate the __OBJC segment
- size_t info_size = 0;
- unsigned long seg_size;
- const objc_image_info *image_info = _getObjcImageInfo(mhdr,&info_size);
- const uint8_t *objc_segment = getsegmentdata(mhdr,SEG_OBJC,&seg_size);
- if (!objc_segment && !image_info) return NULL;
- // Allocate a header_info entry.
- // Note we also allocate space for a single header_info_rw in the
- // rw_data[] inside header_info.
- hi = (header_info *)calloc(sizeof(header_info) + sizeof(header_info_rw), 1);
- // Set up the new header_info entry.
- hi->setmhdr(mhdr);
- #if !__OBJC2__
- // mhdr must already be set
- hi->mod_count = 0;
- hi->mod_ptr = _getObjcModules(hi, &hi->mod_count);
- #endif
- // Install a placeholder image_info if absent to simplify code elsewhere
- static const objc_image_info emptyInfo = {0, 0};
- hi->setinfo(image_info ?: &emptyInfo);
- hi->setLoaded(true);
- hi->setAllClassesRealized(NO);
- }
- #if __OBJC2__
- {
- size_t count = 0;
- if (_getObjc2ClassList(hi, &count)) {
- totalClasses += (int)count;
- if (!inSharedCache) unoptimizedTotalClasses += count;
- }
- }
- #endif
- appendHeader(hi);
-
- return hi;
- }
- /***********************************************************************
- * linksToLibrary
- * Returns true if the image links directly to a dylib whose install name
- * is exactly the given name.
- **********************************************************************/
- bool
- linksToLibrary(const header_info *hi, const char *name)
- {
- const struct dylib_command *cmd;
- unsigned long i;
-
- cmd = (const struct dylib_command *) (hi->mhdr() + 1);
- for (i = 0; i < hi->mhdr()->ncmds; i++) {
- if (cmd->cmd == LC_LOAD_DYLIB || cmd->cmd == LC_LOAD_UPWARD_DYLIB ||
- cmd->cmd == LC_LOAD_WEAK_DYLIB || cmd->cmd == LC_REEXPORT_DYLIB)
- {
- const char *dylib = cmd->dylib.name.offset + (const char *)cmd;
- if (0 == strcmp(dylib, name)) return true;
- }
- cmd = (const struct dylib_command *)((char *)cmd + cmd->cmdsize);
- }
- return false;
- }
- #if SUPPORT_GC_COMPAT
- /***********************************************************************
- * shouldRejectGCApp
- * Return YES if the executable requires GC.
- **********************************************************************/
- static bool shouldRejectGCApp(const header_info *hi)
- {
- ASSERT(hi->mhdr()->filetype == MH_EXECUTE);
- if (!hi->info()->supportsGC()) {
- // App does not use GC. Don't reject it.
- return NO;
- }
-
- // Exception: Trivial AppleScriptObjC apps can run without GC.
- // 1. executable defines no classes
- // 2. executable references NSBundle only
- // 3. executable links to AppleScriptObjC.framework
- // Note that objc_appRequiresGC() also knows about this.
- size_t classcount = 0;
- size_t refcount = 0;
- #if __OBJC2__
- _getObjc2ClassList(hi, &classcount);
- _getObjc2ClassRefs(hi, &refcount);
- #else
- if (hi->mod_count == 0 || (hi->mod_count == 1 && !hi->mod_ptr[0].symtab)) classcount = 0;
- else classcount = 1;
- _getObjcClassRefs(hi, &refcount);
- #endif
- if (classcount == 0 && refcount == 1 &&
- linksToLibrary(hi, "/System/Library/Frameworks"
- "/AppleScriptObjC.framework/Versions/A"
- "/AppleScriptObjC"))
- {
- // It's AppleScriptObjC. Don't reject it.
- return NO;
- }
- else {
- // GC and not trivial AppleScriptObjC. Reject it.
- return YES;
- }
- }
- /***********************************************************************
- * rejectGCImage
- * Halt if an image requires GC.
- * Testing of the main executable should use rejectGCApp() instead.
- **********************************************************************/
- static bool shouldRejectGCImage(const headerType *mhdr)
- {
- ASSERT(mhdr->filetype != MH_EXECUTE);
- objc_image_info *image_info;
- size_t size;
-
- #if !__OBJC2__
- unsigned long seg_size;
- // 32-bit: __OBJC seg but no image_info means no GC support
- if (!getsegmentdata(mhdr, "__OBJC", &seg_size)) {
- // Not objc, therefore not GC. Don't reject it.
- return NO;
- }
- image_info = _getObjcImageInfo(mhdr, &size);
- if (!image_info) {
- // No image_info, therefore not GC. Don't reject it.
- return NO;
- }
- #else
- // 64-bit: no image_info means no objc at all
- image_info = _getObjcImageInfo(mhdr, &size);
- if (!image_info) {
- // Not objc, therefore not GC. Don't reject it.
- return NO;
- }
- #endif
- return image_info->requiresGC();
- }
- // SUPPORT_GC_COMPAT
- #endif
- // Swift currently adds 4 callbacks.
- static GlobalSmallVector<objc_func_loadImage, 4> loadImageFuncs;
- void objc_addLoadImageFunc(objc_func_loadImage _Nonnull func) {
- // Not supported on the old runtime. Not that the old runtime is supported anyway.
- #if __OBJC2__
- mutex_locker_t lock(runtimeLock);
-
- // Call it with all the existing images first.
- for (auto header = FirstHeader; header; header = header->getNext()) {
- func((struct mach_header *)header->mhdr());
- }
-
- // Add it to the vector for future loads.
- loadImageFuncs.append(func);
- #endif
- }
- /***********************************************************************
- * map_images_nolock
- * Process the given images which are being mapped in by dyld.
- * All class registration and fixups are performed (or deferred pending
- * discovery of missing superclasses etc), and +load methods are called.
- *
- * info[] is in bottom-up order i.e. libobjc will be earlier in the
- * array than any library that links to libobjc.
- *
- * Locking: loadMethodLock(old) or runtimeLock(new) acquired by map_images.
- **********************************************************************/
- #if __OBJC2__
- #include "objc-file.h"
- #else
- #include "objc-file-old.h"
- #endif
- void
- map_images_nolock(unsigned mhCount, const char * const mhPaths[],
- const struct mach_header * const mhdrs[])
- {
- static bool firstTime = YES;
- header_info *hList[mhCount];
- uint32_t hCount;
- size_t selrefCount = 0;
- // Perform first-time initialization if necessary.
- // This function is called before ordinary library initializers.
- // fixme defer initialization until an objc-using image is found?
- if (firstTime) {
- preopt_init();
- }
- if (PrintImages) {
- _objc_inform("IMAGES: processing %u newly-mapped images...\n", mhCount);
- }
- // Find all images with Objective-C metadata.
- hCount = 0;
- // Count classes. Size various table based on the total.
- int totalClasses = 0;
- int unoptimizedTotalClasses = 0;
- {
- uint32_t i = mhCount;
- while (i--) {
- const headerType *mhdr = (const headerType *)mhdrs[i];
- auto hi = addHeader(mhdr, mhPaths[i], totalClasses, unoptimizedTotalClasses);
- if (!hi) {
- // no objc data in this entry
- continue;
- }
-
- if (mhdr->filetype == MH_EXECUTE) {
- // Size some data structures based on main executable's size
- #if __OBJC2__
- size_t count;
- _getObjc2SelectorRefs(hi, &count);
- selrefCount += count;
- _getObjc2MessageRefs(hi, &count);
- selrefCount += count;
- #else
- _getObjcSelectorRefs(hi, &selrefCount);
- #endif
-
- #if SUPPORT_GC_COMPAT
- // Halt if this is a GC app.
- if (shouldRejectGCApp(hi)) {
- _objc_fatal_with_reason
- (OBJC_EXIT_REASON_GC_NOT_SUPPORTED,
- OS_REASON_FLAG_CONSISTENT_FAILURE,
- "Objective-C garbage collection "
- "is no longer supported.");
- }
- #endif
- }
-
- hList[hCount++] = hi;
-
- if (PrintImages) {
- _objc_inform("IMAGES: loading image for %s%s%s%s%s\n",
- hi->fname(),
- mhdr->filetype == MH_BUNDLE ? " (bundle)" : "",
- hi->info()->isReplacement() ? " (replacement)" : "",
- hi->info()->hasCategoryClassProperties() ? " (has class properties)" : "",
- hi->info()->optimizedByDyld()?" (preoptimized)":"");
- }
- }
- }
- // Perform one-time runtime initialization that must be deferred until
- // the executable itself is found. This needs to be done before
- // further initialization.
- // (The executable may not be present in this infoList if the
- // executable does not contain Objective-C code but Objective-C
- // is dynamically loaded later.
- if (firstTime) {
- sel_init(selrefCount);
- arr_init();
- #if SUPPORT_GC_COMPAT
- // Reject any GC images linked to the main executable.
- // We already rejected the app itself above.
- // Images loaded after launch will be rejected by dyld.
- for (uint32_t i = 0; i < hCount; i++) {
- auto hi = hList[i];
- auto mh = hi->mhdr();
- if (mh->filetype != MH_EXECUTE && shouldRejectGCImage(mh)) {
- _objc_fatal_with_reason
- (OBJC_EXIT_REASON_GC_NOT_SUPPORTED,
- OS_REASON_FLAG_CONSISTENT_FAILURE,
- "%s requires Objective-C garbage collection "
- "which is no longer supported.", hi->fname());
- }
- }
- #endif
- #if TARGET_OS_OSX
- // Disable +initialize fork safety if the app is too old (< 10.13).
- // Disable +initialize fork safety if the app has a
- // __DATA,__objc_fork_ok section.
- if (dyld_get_program_sdk_version() < DYLD_MACOSX_VERSION_10_13) {
- DisableInitializeForkSafety = true;
- if (PrintInitializing) {
- _objc_inform("INITIALIZE: disabling +initialize fork "
- "safety enforcement because the app is "
- "too old (SDK version " SDK_FORMAT ")",
- FORMAT_SDK(dyld_get_program_sdk_version()));
- }
- }
- for (uint32_t i = 0; i < hCount; i++) {
- auto hi = hList[i];
- auto mh = hi->mhdr();
- if (mh->filetype != MH_EXECUTE) continue;
- unsigned long size;
- if (getsectiondata(hi->mhdr(), "__DATA", "__objc_fork_ok", &size)) {
- DisableInitializeForkSafety = true;
- if (PrintInitializing) {
- _objc_inform("INITIALIZE: disabling +initialize fork "
- "safety enforcement because the app has "
- "a __DATA,__objc_fork_ok section");
- }
- }
- break; // assume only one MH_EXECUTE image
- }
- #endif
- }
- if (hCount > 0) {
- _read_images(hList, hCount, totalClasses, unoptimizedTotalClasses);
- }
- firstTime = NO;
-
- // Call image load funcs after everything is set up.
- for (auto func : loadImageFuncs) {
- for (uint32_t i = 0; i < mhCount; i++) {
- func(mhdrs[i]);
- }
- }
- }
- /***********************************************************************
- * unmap_image_nolock
- * Process the given image which is about to be unmapped by dyld.
- * mh is mach_header instead of headerType because that's what
- * dyld_priv.h says even for 64-bit.
- *
- * Locking: loadMethodLock(both) and runtimeLock(new) acquired by unmap_image.
- **********************************************************************/
- void
- unmap_image_nolock(const struct mach_header *mh)
- {
- if (PrintImages) {
- _objc_inform("IMAGES: processing 1 newly-unmapped image...\n");
- }
- header_info *hi;
-
- // Find the runtime's header_info struct for the image
- for (hi = FirstHeader; hi != NULL; hi = hi->getNext()) {
- if (hi->mhdr() == (const headerType *)mh) {
- break;
- }
- }
- if (!hi) return;
- if (PrintImages) {
- _objc_inform("IMAGES: unloading image for %s%s%s\n",
- hi->fname(),
- hi->mhdr()->filetype == MH_BUNDLE ? " (bundle)" : "",
- hi->info()->isReplacement() ? " (replacement)" : "");
- }
- _unload_image(hi);
- // Remove header_info from header list
- removeHeader(hi);
- free(hi);
- }
- /***********************************************************************
- * static_init
- * Run C++ static constructor functions.
- * libc calls _objc_init() before dyld would call our static constructors,
- * so we have to do it ourselves.
- **********************************************************************/
- static void static_init()
- {
- size_t count;
- auto inits = getLibobjcInitializers(&_mh_dylib_header, &count);
- for (size_t i = 0; i < count; i++) {
- inits[i]();
- }
- }
- /***********************************************************************
- * _objc_atfork_prepare
- * _objc_atfork_parent
- * _objc_atfork_child
- * Allow ObjC to be used between fork() and exec().
- * libc requires this because it has fork-safe functions that use os_objects.
- *
- * _objc_atfork_prepare() acquires all locks.
- * _objc_atfork_parent() releases the locks again.
- * _objc_atfork_child() forcibly resets the locks.
- **********************************************************************/
- // Declare lock ordering.
- #if LOCKDEBUG
- __attribute__((constructor))
- static void defineLockOrder()
- {
- // Every lock precedes crashlog_lock
- // on the assumption that fatal errors could be anywhere.
- lockdebug_lock_precedes_lock(&loadMethodLock, &crashlog_lock);
- lockdebug_lock_precedes_lock(&classInitLock, &crashlog_lock);
- #if __OBJC2__
- lockdebug_lock_precedes_lock(&runtimeLock, &crashlog_lock);
- lockdebug_lock_precedes_lock(&DemangleCacheLock, &crashlog_lock);
- #else
- lockdebug_lock_precedes_lock(&classLock, &crashlog_lock);
- lockdebug_lock_precedes_lock(&methodListLock, &crashlog_lock);
- lockdebug_lock_precedes_lock(&NXUniqueStringLock, &crashlog_lock);
- lockdebug_lock_precedes_lock(&impLock, &crashlog_lock);
- #endif
- lockdebug_lock_precedes_lock(&selLock, &crashlog_lock);
- #if CONFIG_USE_CACHE_LOCK
- lockdebug_lock_precedes_lock(&cacheUpdateLock, &crashlog_lock);
- #endif
- lockdebug_lock_precedes_lock(&objcMsgLogLock, &crashlog_lock);
- lockdebug_lock_precedes_lock(&AltHandlerDebugLock, &crashlog_lock);
- lockdebug_lock_precedes_lock(&AssociationsManagerLock, &crashlog_lock);
- SideTableLocksPrecedeLock(&crashlog_lock);
- PropertyLocks.precedeLock(&crashlog_lock);
- StructLocks.precedeLock(&crashlog_lock);
- CppObjectLocks.precedeLock(&crashlog_lock);
- // loadMethodLock precedes everything
- // because it is held while +load methods run
- lockdebug_lock_precedes_lock(&loadMethodLock, &classInitLock);
- #if __OBJC2__
- lockdebug_lock_precedes_lock(&loadMethodLock, &runtimeLock);
- lockdebug_lock_precedes_lock(&loadMethodLock, &DemangleCacheLock);
- #else
- lockdebug_lock_precedes_lock(&loadMethodLock, &methodListLock);
- lockdebug_lock_precedes_lock(&loadMethodLock, &classLock);
- lockdebug_lock_precedes_lock(&loadMethodLock, &NXUniqueStringLock);
- lockdebug_lock_precedes_lock(&loadMethodLock, &impLock);
- #endif
- lockdebug_lock_precedes_lock(&loadMethodLock, &selLock);
- #if CONFIG_USE_CACHE_LOCK
- lockdebug_lock_precedes_lock(&loadMethodLock, &cacheUpdateLock);
- #endif
- lockdebug_lock_precedes_lock(&loadMethodLock, &objcMsgLogLock);
- lockdebug_lock_precedes_lock(&loadMethodLock, &AltHandlerDebugLock);
- lockdebug_lock_precedes_lock(&loadMethodLock, &AssociationsManagerLock);
- SideTableLocksSucceedLock(&loadMethodLock);
- PropertyLocks.succeedLock(&loadMethodLock);
- StructLocks.succeedLock(&loadMethodLock);
- CppObjectLocks.succeedLock(&loadMethodLock);
- // PropertyLocks and CppObjectLocks and AssociationManagerLock
- // precede everything because they are held while objc_retain()
- // or C++ copy are called.
- // (StructLocks do not precede everything because it calls memmove only.)
- auto PropertyAndCppObjectAndAssocLocksPrecedeLock = [&](const void *lock) {
- PropertyLocks.precedeLock(lock);
- CppObjectLocks.precedeLock(lock);
- lockdebug_lock_precedes_lock(&AssociationsManagerLock, lock);
- };
- #if __OBJC2__
- PropertyAndCppObjectAndAssocLocksPrecedeLock(&runtimeLock);
- PropertyAndCppObjectAndAssocLocksPrecedeLock(&DemangleCacheLock);
- #else
- PropertyAndCppObjectAndAssocLocksPrecedeLock(&methodListLock);
- PropertyAndCppObjectAndAssocLocksPrecedeLock(&classLock);
- PropertyAndCppObjectAndAssocLocksPrecedeLock(&NXUniqueStringLock);
- PropertyAndCppObjectAndAssocLocksPrecedeLock(&impLock);
- #endif
- PropertyAndCppObjectAndAssocLocksPrecedeLock(&classInitLock);
- PropertyAndCppObjectAndAssocLocksPrecedeLock(&selLock);
- #if CONFIG_USE_CACHE_LOCK
- PropertyAndCppObjectAndAssocLocksPrecedeLock(&cacheUpdateLock);
- #endif
- PropertyAndCppObjectAndAssocLocksPrecedeLock(&objcMsgLogLock);
- PropertyAndCppObjectAndAssocLocksPrecedeLock(&AltHandlerDebugLock);
- SideTableLocksSucceedLocks(PropertyLocks);
- SideTableLocksSucceedLocks(CppObjectLocks);
- SideTableLocksSucceedLock(&AssociationsManagerLock);
- PropertyLocks.precedeLock(&AssociationsManagerLock);
- CppObjectLocks.precedeLock(&AssociationsManagerLock);
-
- #if __OBJC2__
- lockdebug_lock_precedes_lock(&classInitLock, &runtimeLock);
- #endif
- #if __OBJC2__
- // Runtime operations may occur inside SideTable locks
- // (such as storeWeak calling getMethodImplementation)
- SideTableLocksPrecedeLock(&runtimeLock);
- SideTableLocksPrecedeLock(&classInitLock);
- // Some operations may occur inside runtimeLock.
- lockdebug_lock_precedes_lock(&runtimeLock, &selLock);
- #if CONFIG_USE_CACHE_LOCK
- lockdebug_lock_precedes_lock(&runtimeLock, &cacheUpdateLock);
- #endif
- lockdebug_lock_precedes_lock(&runtimeLock, &DemangleCacheLock);
- #else
- // Runtime operations may occur inside SideTable locks
- // (such as storeWeak calling getMethodImplementation)
- SideTableLocksPrecedeLock(&methodListLock);
- SideTableLocksPrecedeLock(&classInitLock);
- // Method lookup and fixup.
- lockdebug_lock_precedes_lock(&methodListLock, &classLock);
- lockdebug_lock_precedes_lock(&methodListLock, &selLock);
- #if CONFIG_USE_CACHE_LOCK
- lockdebug_lock_precedes_lock(&methodListLock, &cacheUpdateLock);
- #endif
- lockdebug_lock_precedes_lock(&methodListLock, &impLock);
- lockdebug_lock_precedes_lock(&classLock, &selLock);
- lockdebug_lock_precedes_lock(&classLock, &cacheUpdateLock);
- #endif
- // Striped locks use address order internally.
- SideTableDefineLockOrder();
- PropertyLocks.defineLockOrder();
- StructLocks.defineLockOrder();
- CppObjectLocks.defineLockOrder();
- }
- // LOCKDEBUG
- #endif
- static bool ForkIsMultithreaded;
- void _objc_atfork_prepare()
- {
- // Save threaded-ness for the child's use.
- ForkIsMultithreaded = pthread_is_threaded_np();
- lockdebug_assert_no_locks_locked();
- lockdebug_setInForkPrepare(true);
- loadMethodLock.lock();
- PropertyLocks.lockAll();
- CppObjectLocks.lockAll();
- AssociationsManagerLock.lock();
- SideTableLockAll();
- classInitLock.enter();
- #if __OBJC2__
- runtimeLock.lock();
- DemangleCacheLock.lock();
- #else
- methodListLock.lock();
- classLock.lock();
- NXUniqueStringLock.lock();
- impLock.lock();
- #endif
- selLock.lock();
- #if CONFIG_USE_CACHE_LOCK
- cacheUpdateLock.lock();
- #endif
- objcMsgLogLock.lock();
- AltHandlerDebugLock.lock();
- StructLocks.lockAll();
- crashlog_lock.lock();
- lockdebug_assert_all_locks_locked();
- lockdebug_setInForkPrepare(false);
- }
- void _objc_atfork_parent()
- {
- lockdebug_assert_all_locks_locked();
- CppObjectLocks.unlockAll();
- StructLocks.unlockAll();
- PropertyLocks.unlockAll();
- AssociationsManagerLock.unlock();
- AltHandlerDebugLock.unlock();
- objcMsgLogLock.unlock();
- crashlog_lock.unlock();
- loadMethodLock.unlock();
- #if CONFIG_USE_CACHE_LOCK
- cacheUpdateLock.unlock();
- #endif
- selLock.unlock();
- SideTableUnlockAll();
- #if __OBJC2__
- DemangleCacheLock.unlock();
- runtimeLock.unlock();
- #else
- impLock.unlock();
- NXUniqueStringLock.unlock();
- methodListLock.unlock();
- classLock.unlock();
- #endif
- classInitLock.leave();
- lockdebug_assert_no_locks_locked();
- }
- void _objc_atfork_child()
- {
- // Turn on +initialize fork safety enforcement if applicable.
- if (ForkIsMultithreaded && !DisableInitializeForkSafety) {
- MultithreadedForkChild = true;
- }
- lockdebug_assert_all_locks_locked();
- CppObjectLocks.forceResetAll();
- StructLocks.forceResetAll();
- PropertyLocks.forceResetAll();
- AssociationsManagerLock.forceReset();
- AltHandlerDebugLock.forceReset();
- objcMsgLogLock.forceReset();
- crashlog_lock.forceReset();
- loadMethodLock.forceReset();
- #if CONFIG_USE_CACHE_LOCK
- cacheUpdateLock.forceReset();
- #endif
- selLock.forceReset();
- SideTableForceResetAll();
- #if __OBJC2__
- DemangleCacheLock.forceReset();
- runtimeLock.forceReset();
- #else
- impLock.forceReset();
- NXUniqueStringLock.forceReset();
- methodListLock.forceReset();
- classLock.forceReset();
- #endif
- classInitLock.forceReset();
- lockdebug_assert_no_locks_locked();
- }
- /***********************************************************************
- * _objc_init
- * Bootstrap initialization. Registers our image notifier with dyld.
- * Called by libSystem BEFORE library initialization time
- **********************************************************************/
- void _objc_init(void)
- {
- static bool initialized = false;
- if (initialized) return;
- initialized = true;
-
- // fixme defer initialization until an objc-using image is found?
- environ_init();
- tls_init();
- static_init();
- runtime_init();
- exception_init();
- cache_init();
- _imp_implementationWithBlock_init();
- _dyld_objc_notify_register(&map_images, load_images, unmap_image);
- }
- /***********************************************************************
- * _headerForAddress.
- * addr can be a class or a category
- **********************************************************************/
- static const header_info *_headerForAddress(void *addr)
- {
- #if __OBJC2__
- const char *segnames[] = { "__DATA", "__DATA_CONST", "__DATA_DIRTY" };
- #else
- const char *segnames[] = { "__OBJC" };
- #endif
- header_info *hi;
- for (hi = FirstHeader; hi != NULL; hi = hi->getNext()) {
- for (size_t i = 0; i < sizeof(segnames)/sizeof(segnames[0]); i++) {
- unsigned long seg_size;
- uint8_t *seg = getsegmentdata(hi->mhdr(), segnames[i], &seg_size);
- if (!seg) continue;
-
- // Is the class in this header?
- if ((uint8_t *)addr >= seg && (uint8_t *)addr < seg + seg_size) {
- return hi;
- }
- }
- }
- // Not found
- return 0;
- }
- /***********************************************************************
- * _headerForClass
- * Return the image header containing this class, or NULL.
- * Returns NULL on runtime-constructed classes, and the NSCF classes.
- **********************************************************************/
- const header_info *_headerForClass(Class cls)
- {
- return _headerForAddress(cls);
- }
- /**********************************************************************
- * secure_open
- * Securely open a file from a world-writable directory (like /tmp)
- * If the file does not exist, it will be atomically created with mode 0600
- * If the file exists, it must be, and remain after opening:
- * 1. a regular file (in particular, not a symlink)
- * 2. owned by euid
- * 3. permissions 0600
- * 4. link count == 1
- * Returns a file descriptor or -1. Errno may or may not be set on error.
- **********************************************************************/
- int secure_open(const char *filename, int flags, uid_t euid)
- {
- struct stat fs, ls;
- int fd = -1;
- bool truncate = NO;
- bool create = NO;
- if (flags & O_TRUNC) {
- // Don't truncate the file until after it is open and verified.
- truncate = YES;
- flags &= ~O_TRUNC;
- }
- if (flags & O_CREAT) {
- // Don't create except when we're ready for it
- create = YES;
- flags &= ~O_CREAT;
- flags &= ~O_EXCL;
- }
- if (lstat(filename, &ls) < 0) {
- if (errno == ENOENT && create) {
- // No such file - create it
- fd = open(filename, flags | O_CREAT | O_EXCL, 0600);
- if (fd >= 0) {
- // File was created successfully.
- // New file does not need to be truncated.
- return fd;
- } else {
- // File creation failed.
- return -1;
- }
- } else {
- // lstat failed, or user doesn't want to create the file
- return -1;
- }
- } else {
- // lstat succeeded - verify attributes and open
- if (S_ISREG(ls.st_mode) && // regular file?
- ls.st_nlink == 1 && // link count == 1?
- ls.st_uid == euid && // owned by euid?
- (ls.st_mode & ALLPERMS) == (S_IRUSR | S_IWUSR)) // mode 0600?
- {
- // Attributes look ok - open it and check attributes again
- fd = open(filename, flags, 0000);
- if (fd >= 0) {
- // File is open - double-check attributes
- if (0 == fstat(fd, &fs) &&
- fs.st_nlink == ls.st_nlink && // link count == 1?
- fs.st_uid == ls.st_uid && // owned by euid?
- fs.st_mode == ls.st_mode && // regular file, 0600?
- fs.st_ino == ls.st_ino && // same inode as before?
- fs.st_dev == ls.st_dev) // same device as before?
- {
- // File is open and OK
- if (truncate) ftruncate(fd, 0);
- return fd;
- } else {
- // Opened file looks funny - close it
- close(fd);
- return -1;
- }
- } else {
- // File didn't open
- return -1;
- }
- } else {
- // Unopened file looks funny - don't open it
- return -1;
- }
- }
- }
- #if TARGET_OS_IPHONE
- const char *__crashreporter_info__ = NULL;
- const char *CRSetCrashLogMessage(const char *msg)
- {
- __crashreporter_info__ = msg;
- return msg;
- }
- const char *CRGetCrashLogMessage(void)
- {
- return __crashreporter_info__;
- }
- #endif
- // TARGET_OS_MAC
- #else
- #error unknown OS
- #endif
|