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
495 // If dyld3 optimized the main executable, then there shouldn't
496 // be any selrefs needed in the dynamic map so we can just init
498 if ( !hi->hasPreoptimizedSelectors() ) {
500 _getObjc2SelectorRefs(hi, &count);
501 selrefCount += count;
502 _getObjc2MessageRefs(hi, &count);
503 selrefCount += count;
506 _getObjcSelectorRefs(hi, &selrefCount);
509 #if SUPPORT_GC_COMPAT
510 // Halt if this is a GC app.
511 if (shouldRejectGCApp(hi)) {
512 _objc_fatal_with_reason
513 (OBJC_EXIT_REASON_GC_NOT_SUPPORTED,
514 OS_REASON_FLAG_CONSISTENT_FAILURE,
515 "Objective-C garbage collection "
516 "is no longer supported.");
521 hList[hCount++] = hi;
524 _objc_inform("IMAGES: loading image for %s%s%s%s%s\n",
526 mhdr->filetype == MH_BUNDLE ? " (bundle)" : "",
527 hi->info()->isReplacement() ? " (replacement)" : "",
528 hi->info()->hasCategoryClassProperties() ? " (has class properties)" : "",
529 hi->info()->optimizedByDyld()?" (preoptimized)":"");
534 // Perform one-time runtime initialization that must be deferred until
535 // the executable itself is found. This needs to be done before
536 // further initialization.
537 // (The executable may not be present in this infoList if the
538 // executable does not contain Objective-C code but Objective-C
539 // is dynamically loaded later.
541 sel_init(selrefCount);
544 #if SUPPORT_GC_COMPAT
545 // Reject any GC images linked to the main executable.
546 // We already rejected the app itself above.
547 // Images loaded after launch will be rejected by dyld.
549 for (uint32_t i = 0; i < hCount; i++) {
551 auto mh = hi->mhdr();
552 if (mh->filetype != MH_EXECUTE && shouldRejectGCImage(mh)) {
553 _objc_fatal_with_reason
554 (OBJC_EXIT_REASON_GC_NOT_SUPPORTED,
555 OS_REASON_FLAG_CONSISTENT_FAILURE,
556 "%s requires Objective-C garbage collection "
557 "which is no longer supported.", hi->fname());
563 // Disable +initialize fork safety if the app is too old (< 10.13).
564 // Disable +initialize fork safety if the app has a
565 // __DATA,__objc_fork_ok section.
567 if (dyld_get_program_sdk_version() < DYLD_MACOSX_VERSION_10_13) {
568 DisableInitializeForkSafety = true;
569 if (PrintInitializing) {
570 _objc_inform("INITIALIZE: disabling +initialize fork "
571 "safety enforcement because the app is "
572 "too old (SDK version " SDK_FORMAT ")",
573 FORMAT_SDK(dyld_get_program_sdk_version()));
577 for (uint32_t i = 0; i < hCount; i++) {
579 auto mh = hi->mhdr();
580 if (mh->filetype != MH_EXECUTE) continue;
582 if (getsectiondata(hi->mhdr(), "__DATA", "__objc_fork_ok", &size)) {
583 DisableInitializeForkSafety = true;
584 if (PrintInitializing) {
585 _objc_inform("INITIALIZE: disabling +initialize fork "
586 "safety enforcement because the app has "
587 "a __DATA,__objc_fork_ok section");
590 break; // assume only one MH_EXECUTE image
597 _read_images(hList, hCount, totalClasses, unoptimizedTotalClasses);
602 // Call image load funcs after everything is set up.
603 for (auto func : loadImageFuncs) {
604 for (uint32_t i = 0; i < mhCount; i++) {
611 /***********************************************************************
613 * Process the given image which is about to be unmapped by dyld.
614 * mh is mach_header instead of headerType because that's what
615 * dyld_priv.h says even for 64-bit.
617 * Locking: loadMethodLock(both) and runtimeLock(new) acquired by unmap_image.
618 **********************************************************************/
620 unmap_image_nolock(const struct mach_header *mh)
623 _objc_inform("IMAGES: processing 1 newly-unmapped image...\n");
628 // Find the runtime's header_info struct for the image
629 for (hi = FirstHeader; hi != NULL; hi = hi->getNext()) {
630 if (hi->mhdr() == (const headerType *)mh) {
638 _objc_inform("IMAGES: unloading image for %s%s%s\n",
640 hi->mhdr()->filetype == MH_BUNDLE ? " (bundle)" : "",
641 hi->info()->isReplacement() ? " (replacement)" : "");
646 // Remove header_info from header list
652 /***********************************************************************
654 * Run C++ static constructor functions.
655 * libc calls _objc_init() before dyld would call our static constructors,
656 * so we have to do it ourselves.
657 **********************************************************************/
658 static void static_init()
661 auto inits = getLibobjcInitializers(&_mh_dylib_header, &count);
662 for (size_t i = 0; i < count; i++) {
668 /***********************************************************************
669 * _objc_atfork_prepare
670 * _objc_atfork_parent
672 * Allow ObjC to be used between fork() and exec().
673 * libc requires this because it has fork-safe functions that use os_objects.
675 * _objc_atfork_prepare() acquires all locks.
676 * _objc_atfork_parent() releases the locks again.
677 * _objc_atfork_child() forcibly resets the locks.
678 **********************************************************************/
680 // Declare lock ordering.
682 __attribute__((constructor))
683 static void defineLockOrder()
685 // Every lock precedes crashlog_lock
686 // on the assumption that fatal errors could be anywhere.
687 lockdebug_lock_precedes_lock(&loadMethodLock, &crashlog_lock);
688 lockdebug_lock_precedes_lock(&classInitLock, &crashlog_lock);
690 lockdebug_lock_precedes_lock(&runtimeLock, &crashlog_lock);
691 lockdebug_lock_precedes_lock(&DemangleCacheLock, &crashlog_lock);
693 lockdebug_lock_precedes_lock(&classLock, &crashlog_lock);
694 lockdebug_lock_precedes_lock(&methodListLock, &crashlog_lock);
695 lockdebug_lock_precedes_lock(&NXUniqueStringLock, &crashlog_lock);
696 lockdebug_lock_precedes_lock(&impLock, &crashlog_lock);
698 lockdebug_lock_precedes_lock(&selLock, &crashlog_lock);
699 #if CONFIG_USE_CACHE_LOCK
700 lockdebug_lock_precedes_lock(&cacheUpdateLock, &crashlog_lock);
702 lockdebug_lock_precedes_lock(&objcMsgLogLock, &crashlog_lock);
703 lockdebug_lock_precedes_lock(&AltHandlerDebugLock, &crashlog_lock);
704 lockdebug_lock_precedes_lock(&AssociationsManagerLock, &crashlog_lock);
705 SideTableLocksPrecedeLock(&crashlog_lock);
706 PropertyLocks.precedeLock(&crashlog_lock);
707 StructLocks.precedeLock(&crashlog_lock);
708 CppObjectLocks.precedeLock(&crashlog_lock);
710 // loadMethodLock precedes everything
711 // because it is held while +load methods run
712 lockdebug_lock_precedes_lock(&loadMethodLock, &classInitLock);
714 lockdebug_lock_precedes_lock(&loadMethodLock, &runtimeLock);
715 lockdebug_lock_precedes_lock(&loadMethodLock, &DemangleCacheLock);
717 lockdebug_lock_precedes_lock(&loadMethodLock, &methodListLock);
718 lockdebug_lock_precedes_lock(&loadMethodLock, &classLock);
719 lockdebug_lock_precedes_lock(&loadMethodLock, &NXUniqueStringLock);
720 lockdebug_lock_precedes_lock(&loadMethodLock, &impLock);
722 lockdebug_lock_precedes_lock(&loadMethodLock, &selLock);
723 #if CONFIG_USE_CACHE_LOCK
724 lockdebug_lock_precedes_lock(&loadMethodLock, &cacheUpdateLock);
726 lockdebug_lock_precedes_lock(&loadMethodLock, &objcMsgLogLock);
727 lockdebug_lock_precedes_lock(&loadMethodLock, &AltHandlerDebugLock);
728 lockdebug_lock_precedes_lock(&loadMethodLock, &AssociationsManagerLock);
729 SideTableLocksSucceedLock(&loadMethodLock);
730 PropertyLocks.succeedLock(&loadMethodLock);
731 StructLocks.succeedLock(&loadMethodLock);
732 CppObjectLocks.succeedLock(&loadMethodLock);
734 // PropertyLocks and CppObjectLocks and AssociationManagerLock
735 // precede everything because they are held while objc_retain()
736 // or C++ copy are called.
737 // (StructLocks do not precede everything because it calls memmove only.)
738 auto PropertyAndCppObjectAndAssocLocksPrecedeLock = [&](const void *lock) {
739 PropertyLocks.precedeLock(lock);
740 CppObjectLocks.precedeLock(lock);
741 lockdebug_lock_precedes_lock(&AssociationsManagerLock, lock);
744 PropertyAndCppObjectAndAssocLocksPrecedeLock(&runtimeLock);
745 PropertyAndCppObjectAndAssocLocksPrecedeLock(&DemangleCacheLock);
747 PropertyAndCppObjectAndAssocLocksPrecedeLock(&methodListLock);
748 PropertyAndCppObjectAndAssocLocksPrecedeLock(&classLock);
749 PropertyAndCppObjectAndAssocLocksPrecedeLock(&NXUniqueStringLock);
750 PropertyAndCppObjectAndAssocLocksPrecedeLock(&impLock);
752 PropertyAndCppObjectAndAssocLocksPrecedeLock(&classInitLock);
753 PropertyAndCppObjectAndAssocLocksPrecedeLock(&selLock);
754 #if CONFIG_USE_CACHE_LOCK
755 PropertyAndCppObjectAndAssocLocksPrecedeLock(&cacheUpdateLock);
757 PropertyAndCppObjectAndAssocLocksPrecedeLock(&objcMsgLogLock);
758 PropertyAndCppObjectAndAssocLocksPrecedeLock(&AltHandlerDebugLock);
760 SideTableLocksSucceedLocks(PropertyLocks);
761 SideTableLocksSucceedLocks(CppObjectLocks);
762 SideTableLocksSucceedLock(&AssociationsManagerLock);
764 PropertyLocks.precedeLock(&AssociationsManagerLock);
765 CppObjectLocks.precedeLock(&AssociationsManagerLock);
768 lockdebug_lock_precedes_lock(&classInitLock, &runtimeLock);
772 // Runtime operations may occur inside SideTable locks
773 // (such as storeWeak calling getMethodImplementation)
774 SideTableLocksPrecedeLock(&runtimeLock);
775 SideTableLocksPrecedeLock(&classInitLock);
776 // Some operations may occur inside runtimeLock.
777 lockdebug_lock_precedes_lock(&runtimeLock, &selLock);
778 #if CONFIG_USE_CACHE_LOCK
779 lockdebug_lock_precedes_lock(&runtimeLock, &cacheUpdateLock);
781 lockdebug_lock_precedes_lock(&runtimeLock, &DemangleCacheLock);
783 // Runtime operations may occur inside SideTable locks
784 // (such as storeWeak calling getMethodImplementation)
785 SideTableLocksPrecedeLock(&methodListLock);
786 SideTableLocksPrecedeLock(&classInitLock);
787 // Method lookup and fixup.
788 lockdebug_lock_precedes_lock(&methodListLock, &classLock);
789 lockdebug_lock_precedes_lock(&methodListLock, &selLock);
790 #if CONFIG_USE_CACHE_LOCK
791 lockdebug_lock_precedes_lock(&methodListLock, &cacheUpdateLock);
793 lockdebug_lock_precedes_lock(&methodListLock, &impLock);
794 lockdebug_lock_precedes_lock(&classLock, &selLock);
795 lockdebug_lock_precedes_lock(&classLock, &cacheUpdateLock);
798 // Striped locks use address order internally.
799 SideTableDefineLockOrder();
800 PropertyLocks.defineLockOrder();
801 StructLocks.defineLockOrder();
802 CppObjectLocks.defineLockOrder();
807 static bool ForkIsMultithreaded;
808 void _objc_atfork_prepare()
810 // Save threaded-ness for the child's use.
811 ForkIsMultithreaded = pthread_is_threaded_np();
813 lockdebug_assert_no_locks_locked();
814 lockdebug_setInForkPrepare(true);
816 loadMethodLock.lock();
817 PropertyLocks.lockAll();
818 CppObjectLocks.lockAll();
819 AssociationsManagerLock.lock();
821 classInitLock.enter();
824 DemangleCacheLock.lock();
826 methodListLock.lock();
828 NXUniqueStringLock.lock();
832 #if CONFIG_USE_CACHE_LOCK
833 cacheUpdateLock.lock();
835 objcMsgLogLock.lock();
836 AltHandlerDebugLock.lock();
837 StructLocks.lockAll();
838 crashlog_lock.lock();
840 lockdebug_assert_all_locks_locked();
841 lockdebug_setInForkPrepare(false);
844 void _objc_atfork_parent()
846 lockdebug_assert_all_locks_locked();
848 CppObjectLocks.unlockAll();
849 StructLocks.unlockAll();
850 PropertyLocks.unlockAll();
851 AssociationsManagerLock.unlock();
852 AltHandlerDebugLock.unlock();
853 objcMsgLogLock.unlock();
854 crashlog_lock.unlock();
855 loadMethodLock.unlock();
856 #if CONFIG_USE_CACHE_LOCK
857 cacheUpdateLock.unlock();
860 SideTableUnlockAll();
862 DemangleCacheLock.unlock();
863 runtimeLock.unlock();
866 NXUniqueStringLock.unlock();
867 methodListLock.unlock();
870 classInitLock.leave();
872 lockdebug_assert_no_locks_locked();
875 void _objc_atfork_child()
877 // Turn on +initialize fork safety enforcement if applicable.
878 if (ForkIsMultithreaded && !DisableInitializeForkSafety) {
879 MultithreadedForkChild = true;
882 lockdebug_assert_all_locks_locked();
884 CppObjectLocks.forceResetAll();
885 StructLocks.forceResetAll();
886 PropertyLocks.forceResetAll();
887 AssociationsManagerLock.forceReset();
888 AltHandlerDebugLock.forceReset();
889 objcMsgLogLock.forceReset();
890 crashlog_lock.forceReset();
891 loadMethodLock.forceReset();
892 #if CONFIG_USE_CACHE_LOCK
893 cacheUpdateLock.forceReset();
895 selLock.forceReset();
896 SideTableForceResetAll();
898 DemangleCacheLock.forceReset();
899 runtimeLock.forceReset();
901 impLock.forceReset();
902 NXUniqueStringLock.forceReset();
903 methodListLock.forceReset();
904 classLock.forceReset();
906 classInitLock.forceReset();
908 lockdebug_assert_no_locks_locked();
912 /***********************************************************************
914 * Bootstrap initialization. Registers our image notifier with dyld.
915 * Called by libSystem BEFORE library initialization time
916 **********************************************************************/
918 void _objc_init(void)
920 static bool initialized = false;
921 if (initialized) return;
924 // fixme defer initialization until an objc-using image is found?
931 _imp_implementationWithBlock_init();
933 _dyld_objc_notify_register(&map_images, load_images, unmap_image);
936 didCallDyldNotifyRegister = true;
941 /***********************************************************************
943 * addr can be a class or a category
944 **********************************************************************/
945 static const header_info *_headerForAddress(void *addr)
948 const char *segnames[] = { "__DATA", "__DATA_CONST", "__DATA_DIRTY" };
950 const char *segnames[] = { "__OBJC" };
954 for (hi = FirstHeader; hi != NULL; hi = hi->getNext()) {
955 for (size_t i = 0; i < sizeof(segnames)/sizeof(segnames[0]); i++) {
956 unsigned long seg_size;
957 uint8_t *seg = getsegmentdata(hi->mhdr(), segnames[i], &seg_size);
960 // Is the class in this header?
961 if ((uint8_t *)addr >= seg && (uint8_t *)addr < seg + seg_size) {
972 /***********************************************************************
974 * Return the image header containing this class, or NULL.
975 * Returns NULL on runtime-constructed classes, and the NSCF classes.
976 **********************************************************************/
977 const header_info *_headerForClass(Class cls)
979 return _headerForAddress(cls);
983 /**********************************************************************
985 * Securely open a file from a world-writable directory (like /tmp)
986 * If the file does not exist, it will be atomically created with mode 0600
987 * If the file exists, it must be, and remain after opening:
988 * 1. a regular file (in particular, not a symlink)
990 * 3. permissions 0600
992 * Returns a file descriptor or -1. Errno may or may not be set on error.
993 **********************************************************************/
994 int secure_open(const char *filename, int flags, uid_t euid)
1001 if (flags & O_TRUNC) {
1002 // Don't truncate the file until after it is open and verified.
1006 if (flags & O_CREAT) {
1007 // Don't create except when we're ready for it
1013 if (lstat(filename, &ls) < 0) {
1014 if (errno == ENOENT && create) {
1015 // No such file - create it
1016 fd = open(filename, flags | O_CREAT | O_EXCL, 0600);
1018 // File was created successfully.
1019 // New file does not need to be truncated.
1022 // File creation failed.
1026 // lstat failed, or user doesn't want to create the file
1030 // lstat succeeded - verify attributes and open
1031 if (S_ISREG(ls.st_mode) && // regular file?
1032 ls.st_nlink == 1 && // link count == 1?
1033 ls.st_uid == euid && // owned by euid?
1034 (ls.st_mode & ALLPERMS) == (S_IRUSR | S_IWUSR)) // mode 0600?
1036 // Attributes look ok - open it and check attributes again
1037 fd = open(filename, flags, 0000);
1039 // File is open - double-check attributes
1040 if (0 == fstat(fd, &fs) &&
1041 fs.st_nlink == ls.st_nlink && // link count == 1?
1042 fs.st_uid == ls.st_uid && // owned by euid?
1043 fs.st_mode == ls.st_mode && // regular file, 0600?
1044 fs.st_ino == ls.st_ino && // same inode as before?
1045 fs.st_dev == ls.st_dev) // same device as before?
1047 // File is open and OK
1048 if (truncate) ftruncate(fd, 0);
1051 // Opened file looks funny - close it
1060 // Unopened file looks funny - don't open it
1067 #if TARGET_OS_IPHONE
1069 const char *__crashreporter_info__ = NULL;
1071 const char *CRSetCrashLogMessage(const char *msg)
1073 __crashreporter_info__ = msg;
1076 const char *CRGetCrashLogMessage(void)
1078 return __crashreporter_info__;