2 * Copyright (c) 2007 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 /***********************************************************************
26 * OS portability layer.
27 **********************************************************************/
29 #include "objc-private.h"
30 #include "objc-loadmethod.h"
31 #include "objc-cache.h"
35 #include "objc-runtime-old.h"
38 const fork_unsafe_lock_t fork_unsafe_lock;
40 int monitor_init(monitor_t *c)
42 // fixme error checking
43 HANDLE mutex = CreateMutex(NULL, TRUE, NULL);
45 // fixme memory barrier here?
46 if (0 == InterlockedCompareExchangePointer(&c->mutex, mutex, 0)) {
47 // we win - finish construction
48 c->waiters = CreateSemaphore(NULL, 0, 0x7fffffff, NULL);
49 c->waitersDone = CreateEvent(NULL, FALSE, FALSE, NULL);
50 InitializeCriticalSection(&c->waitCountLock);
53 ReleaseMutex(c->mutex);
58 // someone else allocated the mutex and constructed the monitor
64 void mutex_init(mutex_t *m)
67 CRITICAL_SECTION *newlock = malloc(sizeof(CRITICAL_SECTION));
68 InitializeCriticalSection(newlock);
69 // fixme memory barrier here?
70 if (0 == InterlockedCompareExchangePointer(&m->lock, newlock, 0)) {
73 // someone else installed their lock first
74 DeleteCriticalSection(newlock);
80 void recursive_mutex_init(recursive_mutex_t *m)
82 // fixme error checking
83 HANDLE newmutex = CreateMutex(NULL, FALSE, NULL);
85 // fixme memory barrier here?
86 if (0 == InterlockedCompareExchangePointer(&m->mutex, newmutex, 0)) {
92 // someone else installed their lock first
93 CloseHandle(newmutex);
97 WINBOOL APIENTRY DllMain( HMODULE hModule,
98 DWORD ul_reason_for_call,
102 switch (ul_reason_for_call) {
103 case DLL_PROCESS_ATTACH:
107 sel_init(3500); // old selector heuristic
111 case DLL_THREAD_ATTACH:
114 case DLL_THREAD_DETACH:
115 case DLL_PROCESS_DETACH:
121 OBJC_EXPORT void *_objc_init_image(HMODULE image, const objc_sections *sects)
123 header_info *hi = malloc(sizeof(header_info));
126 hi->mhdr = (const headerType *)image;
127 hi->info = sects->iiStart;
128 hi->allClassesRealized = NO;
129 hi->modules = sects->modStart ? (Module *)((void **)sects->modStart+1) : 0;
130 hi->moduleCount = (Module *)sects->modEnd - hi->modules;
131 hi->protocols = sects->protoStart ? (struct old_protocol **)((void **)sects->protoStart+1) : 0;
132 hi->protocolCount = (struct old_protocol **)sects->protoEnd - hi->protocols;
133 hi->imageinfo = NULL;
134 hi->imageinfoBytes = 0;
135 // hi->imageinfo = sects->iiStart ? (uint8_t *)((void **)sects->iiStart+1) : 0;;
136 // hi->imageinfoBytes = (uint8_t *)sects->iiEnd - hi->imageinfo;
137 hi->selrefs = sects->selrefsStart ? (SEL *)((void **)sects->selrefsStart+1) : 0;
138 hi->selrefCount = (SEL *)sects->selrefsEnd - hi->selrefs;
139 hi->clsrefs = sects->clsrefsStart ? (Class *)((void **)sects->clsrefsStart+1) : 0;
140 hi->clsrefCount = (Class *)sects->clsrefsEnd - hi->clsrefs;
143 for (i = 0; i < hi->moduleCount; i++) {
144 if (hi->modules[i]) count++;
149 hi->mod_ptr = malloc(count * sizeof(struct objc_module));
150 for (i = 0; i < hi->moduleCount; i++) {
151 if (hi->modules[i]) memcpy(&hi->mod_ptr[hi->mod_count++], hi->modules[i], sizeof(struct objc_module));
155 hi->moduleName = malloc(MAX_PATH * sizeof(TCHAR));
156 GetModuleFileName((HMODULE)(hi->mhdr), hi->moduleName, MAX_PATH * sizeof(TCHAR));
161 _objc_inform("IMAGES: loading image for %s%s%s%s\n",
163 headerIsBundle(hi) ? " (bundle)" : "",
164 hi->info->isReplacement() ? " (replacement)":"",
165 hi->info->hasCategoryClassProperties() ? " (has class properties)":"");
168 // Count classes. Size various table based on the total.
170 int unoptimizedTotal = 0;
172 if (_getObjc2ClassList(hi, &count)) {
174 if (!hi->getInSharedCache()) unoptimizedTotal += count;
178 _read_images(&hi, 1, total, unoptimizedTotal);
183 OBJC_EXPORT void _objc_load_image(HMODULE image, header_info *hinfo)
185 prepare_load_methods(hinfo);
189 OBJC_EXPORT void _objc_unload_image(HMODULE image, header_info *hinfo)
191 _objc_fatal("image unload not supported");
198 #include "objc-file-old.h"
199 #include "objc-file.h"
202 /***********************************************************************
203 * libobjc must never run static destructors.
204 * Cover libc's __cxa_atexit with our own definition that runs nothing.
205 * rdar://21734598 ER: Compiler option to suppress C++ static destructors
206 **********************************************************************/
207 extern "C" int __cxa_atexit();
208 extern "C" int __cxa_atexit() { return 0; }
211 /***********************************************************************
213 * Return YES if the header has invalid Mach-o magic.
214 **********************************************************************/
215 bool bad_magic(const headerType *mhdr)
217 return (mhdr->magic != MH_MAGIC && mhdr->magic != MH_MAGIC_64 &&
218 mhdr->magic != MH_CIGAM && mhdr->magic != MH_CIGAM_64);
222 static header_info * addHeader(const headerType *mhdr, const char *path, int &totalClasses, int &unoptimizedTotalClasses)
226 if (bad_magic(mhdr)) return NULL;
228 bool inSharedCache = false;
230 // Look for hinfo from the dyld shared cache.
231 hi = preoptimizedHinfoForHeader(mhdr);
233 // Found an hinfo in the dyld shared cache.
235 // Weed out duplicates.
236 if (hi->isLoaded()) {
240 inSharedCache = true;
242 // Initialize fields not set by the shared cache
243 // hi->next is set by appendHeader
247 _objc_inform("PREOPTIMIZATION: honoring preoptimized header info at %p for %s", hi, hi->fname());
251 _objc_fatal("shouldn't be here");
255 size_t info_size = 0;
256 const objc_image_info *image_info = _getObjcImageInfo(mhdr,&info_size);
257 ASSERT(image_info == hi->info());
262 // Didn't find an hinfo in the dyld shared cache.
264 // Locate the __OBJC segment
265 size_t info_size = 0;
266 unsigned long seg_size;
267 const objc_image_info *image_info = _getObjcImageInfo(mhdr,&info_size);
268 const uint8_t *objc_segment = getsegmentdata(mhdr,SEG_OBJC,&seg_size);
269 if (!objc_segment && !image_info) return NULL;
271 // Allocate a header_info entry.
272 // Note we also allocate space for a single header_info_rw in the
273 // rw_data[] inside header_info.
274 hi = (header_info *)calloc(sizeof(header_info) + sizeof(header_info_rw), 1);
276 // Set up the new header_info entry.
279 // mhdr must already be set
281 hi->mod_ptr = _getObjcModules(hi, &hi->mod_count);
283 // Install a placeholder image_info if absent to simplify code elsewhere
284 static const objc_image_info emptyInfo = {0, 0};
285 hi->setinfo(image_info ?: &emptyInfo);
288 hi->setAllClassesRealized(NO);
294 if (_getObjc2ClassList(hi, &count)) {
295 totalClasses += (int)count;
296 if (!inSharedCache) unoptimizedTotalClasses += count;
307 /***********************************************************************
309 * Returns true if the image links directly to a dylib whose install name
310 * is exactly the given name.
311 **********************************************************************/
313 linksToLibrary(const header_info *hi, const char *name)
315 const struct dylib_command *cmd;
318 cmd = (const struct dylib_command *) (hi->mhdr() + 1);
319 for (i = 0; i < hi->mhdr()->ncmds; i++) {
320 if (cmd->cmd == LC_LOAD_DYLIB || cmd->cmd == LC_LOAD_UPWARD_DYLIB ||
321 cmd->cmd == LC_LOAD_WEAK_DYLIB || cmd->cmd == LC_REEXPORT_DYLIB)
323 const char *dylib = cmd->dylib.name.offset + (const char *)cmd;
324 if (0 == strcmp(dylib, name)) return true;
326 cmd = (const struct dylib_command *)((char *)cmd + cmd->cmdsize);
333 #if SUPPORT_GC_COMPAT
335 /***********************************************************************
337 * Return YES if the executable requires GC.
338 **********************************************************************/
339 static bool shouldRejectGCApp(const header_info *hi)
341 ASSERT(hi->mhdr()->filetype == MH_EXECUTE);
343 if (!hi->info()->supportsGC()) {
344 // App does not use GC. Don't reject it.
348 // Exception: Trivial AppleScriptObjC apps can run without GC.
349 // 1. executable defines no classes
350 // 2. executable references NSBundle only
351 // 3. executable links to AppleScriptObjC.framework
352 // Note that objc_appRequiresGC() also knows about this.
353 size_t classcount = 0;
356 _getObjc2ClassList(hi, &classcount);
357 _getObjc2ClassRefs(hi, &refcount);
359 if (hi->mod_count == 0 || (hi->mod_count == 1 && !hi->mod_ptr[0].symtab)) classcount = 0;
361 _getObjcClassRefs(hi, &refcount);
363 if (classcount == 0 && refcount == 1 &&
364 linksToLibrary(hi, "/System/Library/Frameworks"
365 "/AppleScriptObjC.framework/Versions/A"
368 // It's AppleScriptObjC. Don't reject it.
372 // GC and not trivial AppleScriptObjC. Reject it.
378 /***********************************************************************
380 * Halt if an image requires GC.
381 * Testing of the main executable should use rejectGCApp() instead.
382 **********************************************************************/
383 static bool shouldRejectGCImage(const headerType *mhdr)
385 ASSERT(mhdr->filetype != MH_EXECUTE);
387 objc_image_info *image_info;
391 unsigned long seg_size;
392 // 32-bit: __OBJC seg but no image_info means no GC support
393 if (!getsegmentdata(mhdr, "__OBJC", &seg_size)) {
394 // Not objc, therefore not GC. Don't reject it.
397 image_info = _getObjcImageInfo(mhdr, &size);
399 // No image_info, therefore not GC. Don't reject it.
403 // 64-bit: no image_info means no objc at all
404 image_info = _getObjcImageInfo(mhdr, &size);
406 // Not objc, therefore not GC. Don't reject it.
411 return image_info->requiresGC();
418 // Swift currently adds 4 callbacks.
419 static GlobalSmallVector<objc_func_loadImage, 4> loadImageFuncs;
421 void objc_addLoadImageFunc(objc_func_loadImage _Nonnull func) {
422 // Not supported on the old runtime. Not that the old runtime is supported anyway.
424 mutex_locker_t lock(runtimeLock);
426 // Call it with all the existing images first.
427 for (auto header = FirstHeader; header; header = header->getNext()) {
428 func((struct mach_header *)header->mhdr());
431 // Add it to the vector for future loads.
432 loadImageFuncs.append(func);
437 /***********************************************************************
439 * Process the given images which are being mapped in by dyld.
440 * All class registration and fixups are performed (or deferred pending
441 * discovery of missing superclasses etc), and +load methods are called.
443 * info[] is in bottom-up order i.e. libobjc will be earlier in the
444 * array than any library that links to libobjc.
446 * Locking: loadMethodLock(old) or runtimeLock(new) acquired by map_images.
447 **********************************************************************/
449 #include "objc-file.h"
451 #include "objc-file-old.h"
455 map_images_nolock(unsigned mhCount, const char * const mhPaths[],
456 const struct mach_header * const mhdrs[])
458 static bool firstTime = YES;
459 header_info *hList[mhCount];
461 size_t selrefCount = 0;
463 // Perform first-time initialization if necessary.
464 // This function is called before ordinary library initializers.
465 // fixme defer initialization until an objc-using image is found?
471 _objc_inform("IMAGES: processing %u newly-mapped images...\n", mhCount);
475 // Find all images with Objective-C metadata.
478 // Count classes. Size various table based on the total.
479 int totalClasses = 0;
480 int unoptimizedTotalClasses = 0;
482 uint32_t i = mhCount;
484 const headerType *mhdr = (const headerType *)mhdrs[i];
486 auto hi = addHeader(mhdr, mhPaths[i], totalClasses, unoptimizedTotalClasses);
488 // no objc data in this entry
492 if (mhdr->filetype == MH_EXECUTE) {
493 // Size some data structures based on main executable's size
496 _getObjc2SelectorRefs(hi, &count);
497 selrefCount += count;
498 _getObjc2MessageRefs(hi, &count);
499 selrefCount += count;
501 _getObjcSelectorRefs(hi, &selrefCount);
504 #if SUPPORT_GC_COMPAT
505 // Halt if this is a GC app.
506 if (shouldRejectGCApp(hi)) {
507 _objc_fatal_with_reason
508 (OBJC_EXIT_REASON_GC_NOT_SUPPORTED,
509 OS_REASON_FLAG_CONSISTENT_FAILURE,
510 "Objective-C garbage collection "
511 "is no longer supported.");
516 hList[hCount++] = hi;
519 _objc_inform("IMAGES: loading image for %s%s%s%s%s\n",
521 mhdr->filetype == MH_BUNDLE ? " (bundle)" : "",
522 hi->info()->isReplacement() ? " (replacement)" : "",
523 hi->info()->hasCategoryClassProperties() ? " (has class properties)" : "",
524 hi->info()->optimizedByDyld()?" (preoptimized)":"");
529 // Perform one-time runtime initialization that must be deferred until
530 // the executable itself is found. This needs to be done before
531 // further initialization.
532 // (The executable may not be present in this infoList if the
533 // executable does not contain Objective-C code but Objective-C
534 // is dynamically loaded later.
536 sel_init(selrefCount);
539 #if SUPPORT_GC_COMPAT
540 // Reject any GC images linked to the main executable.
541 // We already rejected the app itself above.
542 // Images loaded after launch will be rejected by dyld.
544 for (uint32_t i = 0; i < hCount; i++) {
546 auto mh = hi->mhdr();
547 if (mh->filetype != MH_EXECUTE && shouldRejectGCImage(mh)) {
548 _objc_fatal_with_reason
549 (OBJC_EXIT_REASON_GC_NOT_SUPPORTED,
550 OS_REASON_FLAG_CONSISTENT_FAILURE,
551 "%s requires Objective-C garbage collection "
552 "which is no longer supported.", hi->fname());
558 // Disable +initialize fork safety if the app is too old (< 10.13).
559 // Disable +initialize fork safety if the app has a
560 // __DATA,__objc_fork_ok section.
562 if (dyld_get_program_sdk_version() < DYLD_MACOSX_VERSION_10_13) {
563 DisableInitializeForkSafety = true;
564 if (PrintInitializing) {
565 _objc_inform("INITIALIZE: disabling +initialize fork "
566 "safety enforcement because the app is "
567 "too old (SDK version " SDK_FORMAT ")",
568 FORMAT_SDK(dyld_get_program_sdk_version()));
572 for (uint32_t i = 0; i < hCount; i++) {
574 auto mh = hi->mhdr();
575 if (mh->filetype != MH_EXECUTE) continue;
577 if (getsectiondata(hi->mhdr(), "__DATA", "__objc_fork_ok", &size)) {
578 DisableInitializeForkSafety = true;
579 if (PrintInitializing) {
580 _objc_inform("INITIALIZE: disabling +initialize fork "
581 "safety enforcement because the app has "
582 "a __DATA,__objc_fork_ok section");
585 break; // assume only one MH_EXECUTE image
592 _read_images(hList, hCount, totalClasses, unoptimizedTotalClasses);
597 // Call image load funcs after everything is set up.
598 for (auto func : loadImageFuncs) {
599 for (uint32_t i = 0; i < mhCount; i++) {
606 /***********************************************************************
608 * Process the given image which is about to be unmapped by dyld.
609 * mh is mach_header instead of headerType because that's what
610 * dyld_priv.h says even for 64-bit.
612 * Locking: loadMethodLock(both) and runtimeLock(new) acquired by unmap_image.
613 **********************************************************************/
615 unmap_image_nolock(const struct mach_header *mh)
618 _objc_inform("IMAGES: processing 1 newly-unmapped image...\n");
623 // Find the runtime's header_info struct for the image
624 for (hi = FirstHeader; hi != NULL; hi = hi->getNext()) {
625 if (hi->mhdr() == (const headerType *)mh) {
633 _objc_inform("IMAGES: unloading image for %s%s%s\n",
635 hi->mhdr()->filetype == MH_BUNDLE ? " (bundle)" : "",
636 hi->info()->isReplacement() ? " (replacement)" : "");
641 // Remove header_info from header list
647 /***********************************************************************
649 * Run C++ static constructor functions.
650 * libc calls _objc_init() before dyld would call our static constructors,
651 * so we have to do it ourselves.
652 **********************************************************************/
653 static void static_init()
656 auto inits = getLibobjcInitializers(&_mh_dylib_header, &count);
657 for (size_t i = 0; i < count; i++) {
663 /***********************************************************************
664 * _objc_atfork_prepare
665 * _objc_atfork_parent
667 * Allow ObjC to be used between fork() and exec().
668 * libc requires this because it has fork-safe functions that use os_objects.
670 * _objc_atfork_prepare() acquires all locks.
671 * _objc_atfork_parent() releases the locks again.
672 * _objc_atfork_child() forcibly resets the locks.
673 **********************************************************************/
675 // Declare lock ordering.
677 __attribute__((constructor))
678 static void defineLockOrder()
680 // Every lock precedes crashlog_lock
681 // on the assumption that fatal errors could be anywhere.
682 lockdebug_lock_precedes_lock(&loadMethodLock, &crashlog_lock);
683 lockdebug_lock_precedes_lock(&classInitLock, &crashlog_lock);
685 lockdebug_lock_precedes_lock(&runtimeLock, &crashlog_lock);
686 lockdebug_lock_precedes_lock(&DemangleCacheLock, &crashlog_lock);
688 lockdebug_lock_precedes_lock(&classLock, &crashlog_lock);
689 lockdebug_lock_precedes_lock(&methodListLock, &crashlog_lock);
690 lockdebug_lock_precedes_lock(&NXUniqueStringLock, &crashlog_lock);
691 lockdebug_lock_precedes_lock(&impLock, &crashlog_lock);
693 lockdebug_lock_precedes_lock(&selLock, &crashlog_lock);
694 #if CONFIG_USE_CACHE_LOCK
695 lockdebug_lock_precedes_lock(&cacheUpdateLock, &crashlog_lock);
697 lockdebug_lock_precedes_lock(&objcMsgLogLock, &crashlog_lock);
698 lockdebug_lock_precedes_lock(&AltHandlerDebugLock, &crashlog_lock);
699 lockdebug_lock_precedes_lock(&AssociationsManagerLock, &crashlog_lock);
700 SideTableLocksPrecedeLock(&crashlog_lock);
701 PropertyLocks.precedeLock(&crashlog_lock);
702 StructLocks.precedeLock(&crashlog_lock);
703 CppObjectLocks.precedeLock(&crashlog_lock);
705 // loadMethodLock precedes everything
706 // because it is held while +load methods run
707 lockdebug_lock_precedes_lock(&loadMethodLock, &classInitLock);
709 lockdebug_lock_precedes_lock(&loadMethodLock, &runtimeLock);
710 lockdebug_lock_precedes_lock(&loadMethodLock, &DemangleCacheLock);
712 lockdebug_lock_precedes_lock(&loadMethodLock, &methodListLock);
713 lockdebug_lock_precedes_lock(&loadMethodLock, &classLock);
714 lockdebug_lock_precedes_lock(&loadMethodLock, &NXUniqueStringLock);
715 lockdebug_lock_precedes_lock(&loadMethodLock, &impLock);
717 lockdebug_lock_precedes_lock(&loadMethodLock, &selLock);
718 #if CONFIG_USE_CACHE_LOCK
719 lockdebug_lock_precedes_lock(&loadMethodLock, &cacheUpdateLock);
721 lockdebug_lock_precedes_lock(&loadMethodLock, &objcMsgLogLock);
722 lockdebug_lock_precedes_lock(&loadMethodLock, &AltHandlerDebugLock);
723 lockdebug_lock_precedes_lock(&loadMethodLock, &AssociationsManagerLock);
724 SideTableLocksSucceedLock(&loadMethodLock);
725 PropertyLocks.succeedLock(&loadMethodLock);
726 StructLocks.succeedLock(&loadMethodLock);
727 CppObjectLocks.succeedLock(&loadMethodLock);
729 // PropertyLocks and CppObjectLocks and AssociationManagerLock
730 // precede everything because they are held while objc_retain()
731 // or C++ copy are called.
732 // (StructLocks do not precede everything because it calls memmove only.)
733 auto PropertyAndCppObjectAndAssocLocksPrecedeLock = [&](const void *lock) {
734 PropertyLocks.precedeLock(lock);
735 CppObjectLocks.precedeLock(lock);
736 lockdebug_lock_precedes_lock(&AssociationsManagerLock, lock);
739 PropertyAndCppObjectAndAssocLocksPrecedeLock(&runtimeLock);
740 PropertyAndCppObjectAndAssocLocksPrecedeLock(&DemangleCacheLock);
742 PropertyAndCppObjectAndAssocLocksPrecedeLock(&methodListLock);
743 PropertyAndCppObjectAndAssocLocksPrecedeLock(&classLock);
744 PropertyAndCppObjectAndAssocLocksPrecedeLock(&NXUniqueStringLock);
745 PropertyAndCppObjectAndAssocLocksPrecedeLock(&impLock);
747 PropertyAndCppObjectAndAssocLocksPrecedeLock(&classInitLock);
748 PropertyAndCppObjectAndAssocLocksPrecedeLock(&selLock);
749 #if CONFIG_USE_CACHE_LOCK
750 PropertyAndCppObjectAndAssocLocksPrecedeLock(&cacheUpdateLock);
752 PropertyAndCppObjectAndAssocLocksPrecedeLock(&objcMsgLogLock);
753 PropertyAndCppObjectAndAssocLocksPrecedeLock(&AltHandlerDebugLock);
755 SideTableLocksSucceedLocks(PropertyLocks);
756 SideTableLocksSucceedLocks(CppObjectLocks);
757 SideTableLocksSucceedLock(&AssociationsManagerLock);
759 PropertyLocks.precedeLock(&AssociationsManagerLock);
760 CppObjectLocks.precedeLock(&AssociationsManagerLock);
763 lockdebug_lock_precedes_lock(&classInitLock, &runtimeLock);
767 // Runtime operations may occur inside SideTable locks
768 // (such as storeWeak calling getMethodImplementation)
769 SideTableLocksPrecedeLock(&runtimeLock);
770 SideTableLocksPrecedeLock(&classInitLock);
771 // Some operations may occur inside runtimeLock.
772 lockdebug_lock_precedes_lock(&runtimeLock, &selLock);
773 #if CONFIG_USE_CACHE_LOCK
774 lockdebug_lock_precedes_lock(&runtimeLock, &cacheUpdateLock);
776 lockdebug_lock_precedes_lock(&runtimeLock, &DemangleCacheLock);
778 // Runtime operations may occur inside SideTable locks
779 // (such as storeWeak calling getMethodImplementation)
780 SideTableLocksPrecedeLock(&methodListLock);
781 SideTableLocksPrecedeLock(&classInitLock);
782 // Method lookup and fixup.
783 lockdebug_lock_precedes_lock(&methodListLock, &classLock);
784 lockdebug_lock_precedes_lock(&methodListLock, &selLock);
785 #if CONFIG_USE_CACHE_LOCK
786 lockdebug_lock_precedes_lock(&methodListLock, &cacheUpdateLock);
788 lockdebug_lock_precedes_lock(&methodListLock, &impLock);
789 lockdebug_lock_precedes_lock(&classLock, &selLock);
790 lockdebug_lock_precedes_lock(&classLock, &cacheUpdateLock);
793 // Striped locks use address order internally.
794 SideTableDefineLockOrder();
795 PropertyLocks.defineLockOrder();
796 StructLocks.defineLockOrder();
797 CppObjectLocks.defineLockOrder();
802 static bool ForkIsMultithreaded;
803 void _objc_atfork_prepare()
805 // Save threaded-ness for the child's use.
806 ForkIsMultithreaded = pthread_is_threaded_np();
808 lockdebug_assert_no_locks_locked();
809 lockdebug_setInForkPrepare(true);
811 loadMethodLock.lock();
812 PropertyLocks.lockAll();
813 CppObjectLocks.lockAll();
814 AssociationsManagerLock.lock();
816 classInitLock.enter();
819 DemangleCacheLock.lock();
821 methodListLock.lock();
823 NXUniqueStringLock.lock();
827 #if CONFIG_USE_CACHE_LOCK
828 cacheUpdateLock.lock();
830 objcMsgLogLock.lock();
831 AltHandlerDebugLock.lock();
832 StructLocks.lockAll();
833 crashlog_lock.lock();
835 lockdebug_assert_all_locks_locked();
836 lockdebug_setInForkPrepare(false);
839 void _objc_atfork_parent()
841 lockdebug_assert_all_locks_locked();
843 CppObjectLocks.unlockAll();
844 StructLocks.unlockAll();
845 PropertyLocks.unlockAll();
846 AssociationsManagerLock.unlock();
847 AltHandlerDebugLock.unlock();
848 objcMsgLogLock.unlock();
849 crashlog_lock.unlock();
850 loadMethodLock.unlock();
851 #if CONFIG_USE_CACHE_LOCK
852 cacheUpdateLock.unlock();
855 SideTableUnlockAll();
857 DemangleCacheLock.unlock();
858 runtimeLock.unlock();
861 NXUniqueStringLock.unlock();
862 methodListLock.unlock();
865 classInitLock.leave();
867 lockdebug_assert_no_locks_locked();
870 void _objc_atfork_child()
872 // Turn on +initialize fork safety enforcement if applicable.
873 if (ForkIsMultithreaded && !DisableInitializeForkSafety) {
874 MultithreadedForkChild = true;
877 lockdebug_assert_all_locks_locked();
879 CppObjectLocks.forceResetAll();
880 StructLocks.forceResetAll();
881 PropertyLocks.forceResetAll();
882 AssociationsManagerLock.forceReset();
883 AltHandlerDebugLock.forceReset();
884 objcMsgLogLock.forceReset();
885 crashlog_lock.forceReset();
886 loadMethodLock.forceReset();
887 #if CONFIG_USE_CACHE_LOCK
888 cacheUpdateLock.forceReset();
890 selLock.forceReset();
891 SideTableForceResetAll();
893 DemangleCacheLock.forceReset();
894 runtimeLock.forceReset();
896 impLock.forceReset();
897 NXUniqueStringLock.forceReset();
898 methodListLock.forceReset();
899 classLock.forceReset();
901 classInitLock.forceReset();
903 lockdebug_assert_no_locks_locked();
907 /***********************************************************************
909 * Bootstrap initialization. Registers our image notifier with dyld.
910 * Called by libSystem BEFORE library initialization time
911 **********************************************************************/
913 void _objc_init(void)
915 static bool initialized = false;
916 if (initialized) return;
919 // fixme defer initialization until an objc-using image is found?
926 _imp_implementationWithBlock_init();
928 _dyld_objc_notify_register(&map_images, load_images, unmap_image);
931 didCallDyldNotifyRegister = true;
936 /***********************************************************************
938 * addr can be a class or a category
939 **********************************************************************/
940 static const header_info *_headerForAddress(void *addr)
943 const char *segnames[] = { "__DATA", "__DATA_CONST", "__DATA_DIRTY" };
945 const char *segnames[] = { "__OBJC" };
949 for (hi = FirstHeader; hi != NULL; hi = hi->getNext()) {
950 for (size_t i = 0; i < sizeof(segnames)/sizeof(segnames[0]); i++) {
951 unsigned long seg_size;
952 uint8_t *seg = getsegmentdata(hi->mhdr(), segnames[i], &seg_size);
955 // Is the class in this header?
956 if ((uint8_t *)addr >= seg && (uint8_t *)addr < seg + seg_size) {
967 /***********************************************************************
969 * Return the image header containing this class, or NULL.
970 * Returns NULL on runtime-constructed classes, and the NSCF classes.
971 **********************************************************************/
972 const header_info *_headerForClass(Class cls)
974 return _headerForAddress(cls);
978 /**********************************************************************
980 * Securely open a file from a world-writable directory (like /tmp)
981 * If the file does not exist, it will be atomically created with mode 0600
982 * If the file exists, it must be, and remain after opening:
983 * 1. a regular file (in particular, not a symlink)
985 * 3. permissions 0600
987 * Returns a file descriptor or -1. Errno may or may not be set on error.
988 **********************************************************************/
989 int secure_open(const char *filename, int flags, uid_t euid)
996 if (flags & O_TRUNC) {
997 // Don't truncate the file until after it is open and verified.
1001 if (flags & O_CREAT) {
1002 // Don't create except when we're ready for it
1008 if (lstat(filename, &ls) < 0) {
1009 if (errno == ENOENT && create) {
1010 // No such file - create it
1011 fd = open(filename, flags | O_CREAT | O_EXCL, 0600);
1013 // File was created successfully.
1014 // New file does not need to be truncated.
1017 // File creation failed.
1021 // lstat failed, or user doesn't want to create the file
1025 // lstat succeeded - verify attributes and open
1026 if (S_ISREG(ls.st_mode) && // regular file?
1027 ls.st_nlink == 1 && // link count == 1?
1028 ls.st_uid == euid && // owned by euid?
1029 (ls.st_mode & ALLPERMS) == (S_IRUSR | S_IWUSR)) // mode 0600?
1031 // Attributes look ok - open it and check attributes again
1032 fd = open(filename, flags, 0000);
1034 // File is open - double-check attributes
1035 if (0 == fstat(fd, &fs) &&
1036 fs.st_nlink == ls.st_nlink && // link count == 1?
1037 fs.st_uid == ls.st_uid && // owned by euid?
1038 fs.st_mode == ls.st_mode && // regular file, 0600?
1039 fs.st_ino == ls.st_ino && // same inode as before?
1040 fs.st_dev == ls.st_dev) // same device as before?
1042 // File is open and OK
1043 if (truncate) ftruncate(fd, 0);
1046 // Opened file looks funny - close it
1055 // Unopened file looks funny - don't open it
1062 #if TARGET_OS_IPHONE
1064 const char *__crashreporter_info__ = NULL;
1066 const char *CRSetCrashLogMessage(const char *msg)
1068 __crashreporter_info__ = msg;
1071 const char *CRGetCrashLogMessage(void)
1073 return __crashreporter_info__;