]> git.saurik.com Git - apple/objc4.git/blob - runtime/objc-os.mm
objc4-781.tar.gz
[apple/objc4.git] / runtime / objc-os.mm
1 /*
2 * Copyright (c) 2007 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 /***********************************************************************
25 * objc-os.m
26 * OS portability layer.
27 **********************************************************************/
28
29 #include "objc-private.h"
30 #include "objc-loadmethod.h"
31 #include "objc-cache.h"
32
33 #if TARGET_OS_WIN32
34
35 #include "objc-runtime-old.h"
36 #include "objcrt.h"
37
38 const fork_unsafe_lock_t fork_unsafe_lock;
39
40 int monitor_init(monitor_t *c)
41 {
42 // fixme error checking
43 HANDLE mutex = CreateMutex(NULL, TRUE, NULL);
44 while (!c->mutex) {
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);
51 c->waitCount = 0;
52 c->didBroadcast = 0;
53 ReleaseMutex(c->mutex);
54 return 0;
55 }
56 }
57
58 // someone else allocated the mutex and constructed the monitor
59 ReleaseMutex(mutex);
60 CloseHandle(mutex);
61 return 0;
62 }
63
64 void mutex_init(mutex_t *m)
65 {
66 while (!m->lock) {
67 CRITICAL_SECTION *newlock = malloc(sizeof(CRITICAL_SECTION));
68 InitializeCriticalSection(newlock);
69 // fixme memory barrier here?
70 if (0 == InterlockedCompareExchangePointer(&m->lock, newlock, 0)) {
71 return;
72 }
73 // someone else installed their lock first
74 DeleteCriticalSection(newlock);
75 free(newlock);
76 }
77 }
78
79
80 void recursive_mutex_init(recursive_mutex_t *m)
81 {
82 // fixme error checking
83 HANDLE newmutex = CreateMutex(NULL, FALSE, NULL);
84 while (!m->mutex) {
85 // fixme memory barrier here?
86 if (0 == InterlockedCompareExchangePointer(&m->mutex, newmutex, 0)) {
87 // we win
88 return;
89 }
90 }
91
92 // someone else installed their lock first
93 CloseHandle(newmutex);
94 }
95
96
97 WINBOOL APIENTRY DllMain( HMODULE hModule,
98 DWORD ul_reason_for_call,
99 LPVOID lpReserved
100 )
101 {
102 switch (ul_reason_for_call) {
103 case DLL_PROCESS_ATTACH:
104 environ_init();
105 tls_init();
106 runtime_init();
107 sel_init(3500); // old selector heuristic
108 exception_init();
109 break;
110
111 case DLL_THREAD_ATTACH:
112 break;
113
114 case DLL_THREAD_DETACH:
115 case DLL_PROCESS_DETACH:
116 break;
117 }
118 return TRUE;
119 }
120
121 OBJC_EXPORT void *_objc_init_image(HMODULE image, const objc_sections *sects)
122 {
123 header_info *hi = malloc(sizeof(header_info));
124 size_t count, i;
125
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;
141
142 count = 0;
143 for (i = 0; i < hi->moduleCount; i++) {
144 if (hi->modules[i]) count++;
145 }
146 hi->mod_count = 0;
147 hi->mod_ptr = 0;
148 if (count > 0) {
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));
152 }
153 }
154
155 hi->moduleName = malloc(MAX_PATH * sizeof(TCHAR));
156 GetModuleFileName((HMODULE)(hi->mhdr), hi->moduleName, MAX_PATH * sizeof(TCHAR));
157
158 appendHeader(hi);
159
160 if (PrintImages) {
161 _objc_inform("IMAGES: loading image for %s%s%s%s\n",
162 hi->fname,
163 headerIsBundle(hi) ? " (bundle)" : "",
164 hi->info->isReplacement() ? " (replacement)":"",
165 hi->info->hasCategoryClassProperties() ? " (has class properties)":"");
166 }
167
168 // Count classes. Size various table based on the total.
169 int total = 0;
170 int unoptimizedTotal = 0;
171 {
172 if (_getObjc2ClassList(hi, &count)) {
173 total += (int)count;
174 if (!hi->getInSharedCache()) unoptimizedTotal += count;
175 }
176 }
177
178 _read_images(&hi, 1, total, unoptimizedTotal);
179
180 return hi;
181 }
182
183 OBJC_EXPORT void _objc_load_image(HMODULE image, header_info *hinfo)
184 {
185 prepare_load_methods(hinfo);
186 call_load_methods();
187 }
188
189 OBJC_EXPORT void _objc_unload_image(HMODULE image, header_info *hinfo)
190 {
191 _objc_fatal("image unload not supported");
192 }
193
194
195 // TARGET_OS_WIN32
196 #elif TARGET_OS_MAC
197
198 #include "objc-file-old.h"
199 #include "objc-file.h"
200
201
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; }
209
210
211 /***********************************************************************
212 * bad_magic.
213 * Return YES if the header has invalid Mach-o magic.
214 **********************************************************************/
215 bool bad_magic(const headerType *mhdr)
216 {
217 return (mhdr->magic != MH_MAGIC && mhdr->magic != MH_MAGIC_64 &&
218 mhdr->magic != MH_CIGAM && mhdr->magic != MH_CIGAM_64);
219 }
220
221
222 static header_info * addHeader(const headerType *mhdr, const char *path, int &totalClasses, int &unoptimizedTotalClasses)
223 {
224 header_info *hi;
225
226 if (bad_magic(mhdr)) return NULL;
227
228 bool inSharedCache = false;
229
230 // Look for hinfo from the dyld shared cache.
231 hi = preoptimizedHinfoForHeader(mhdr);
232 if (hi) {
233 // Found an hinfo in the dyld shared cache.
234
235 // Weed out duplicates.
236 if (hi->isLoaded()) {
237 return NULL;
238 }
239
240 inSharedCache = true;
241
242 // Initialize fields not set by the shared cache
243 // hi->next is set by appendHeader
244 hi->setLoaded(true);
245
246 if (PrintPreopt) {
247 _objc_inform("PREOPTIMIZATION: honoring preoptimized header info at %p for %s", hi, hi->fname());
248 }
249
250 #if !__OBJC2__
251 _objc_fatal("shouldn't be here");
252 #endif
253 #if DEBUG
254 // Verify image_info
255 size_t info_size = 0;
256 const objc_image_info *image_info = _getObjcImageInfo(mhdr,&info_size);
257 ASSERT(image_info == hi->info());
258 #endif
259 }
260 else
261 {
262 // Didn't find an hinfo in the dyld shared cache.
263
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;
270
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);
275
276 // Set up the new header_info entry.
277 hi->setmhdr(mhdr);
278 #if !__OBJC2__
279 // mhdr must already be set
280 hi->mod_count = 0;
281 hi->mod_ptr = _getObjcModules(hi, &hi->mod_count);
282 #endif
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);
286
287 hi->setLoaded(true);
288 hi->setAllClassesRealized(NO);
289 }
290
291 #if __OBJC2__
292 {
293 size_t count = 0;
294 if (_getObjc2ClassList(hi, &count)) {
295 totalClasses += (int)count;
296 if (!inSharedCache) unoptimizedTotalClasses += count;
297 }
298 }
299 #endif
300
301 appendHeader(hi);
302
303 return hi;
304 }
305
306
307 /***********************************************************************
308 * linksToLibrary
309 * Returns true if the image links directly to a dylib whose install name
310 * is exactly the given name.
311 **********************************************************************/
312 bool
313 linksToLibrary(const header_info *hi, const char *name)
314 {
315 const struct dylib_command *cmd;
316 unsigned long i;
317
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)
322 {
323 const char *dylib = cmd->dylib.name.offset + (const char *)cmd;
324 if (0 == strcmp(dylib, name)) return true;
325 }
326 cmd = (const struct dylib_command *)((char *)cmd + cmd->cmdsize);
327 }
328
329 return false;
330 }
331
332
333 #if SUPPORT_GC_COMPAT
334
335 /***********************************************************************
336 * shouldRejectGCApp
337 * Return YES if the executable requires GC.
338 **********************************************************************/
339 static bool shouldRejectGCApp(const header_info *hi)
340 {
341 ASSERT(hi->mhdr()->filetype == MH_EXECUTE);
342
343 if (!hi->info()->supportsGC()) {
344 // App does not use GC. Don't reject it.
345 return NO;
346 }
347
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;
354 size_t refcount = 0;
355 #if __OBJC2__
356 _getObjc2ClassList(hi, &classcount);
357 _getObjc2ClassRefs(hi, &refcount);
358 #else
359 if (hi->mod_count == 0 || (hi->mod_count == 1 && !hi->mod_ptr[0].symtab)) classcount = 0;
360 else classcount = 1;
361 _getObjcClassRefs(hi, &refcount);
362 #endif
363 if (classcount == 0 && refcount == 1 &&
364 linksToLibrary(hi, "/System/Library/Frameworks"
365 "/AppleScriptObjC.framework/Versions/A"
366 "/AppleScriptObjC"))
367 {
368 // It's AppleScriptObjC. Don't reject it.
369 return NO;
370 }
371 else {
372 // GC and not trivial AppleScriptObjC. Reject it.
373 return YES;
374 }
375 }
376
377
378 /***********************************************************************
379 * rejectGCImage
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)
384 {
385 ASSERT(mhdr->filetype != MH_EXECUTE);
386
387 objc_image_info *image_info;
388 size_t size;
389
390 #if !__OBJC2__
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.
395 return NO;
396 }
397 image_info = _getObjcImageInfo(mhdr, &size);
398 if (!image_info) {
399 // No image_info, therefore not GC. Don't reject it.
400 return NO;
401 }
402 #else
403 // 64-bit: no image_info means no objc at all
404 image_info = _getObjcImageInfo(mhdr, &size);
405 if (!image_info) {
406 // Not objc, therefore not GC. Don't reject it.
407 return NO;
408 }
409 #endif
410
411 return image_info->requiresGC();
412 }
413
414 // SUPPORT_GC_COMPAT
415 #endif
416
417
418 // Swift currently adds 4 callbacks.
419 static GlobalSmallVector<objc_func_loadImage, 4> loadImageFuncs;
420
421 void objc_addLoadImageFunc(objc_func_loadImage _Nonnull func) {
422 // Not supported on the old runtime. Not that the old runtime is supported anyway.
423 #if __OBJC2__
424 mutex_locker_t lock(runtimeLock);
425
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());
429 }
430
431 // Add it to the vector for future loads.
432 loadImageFuncs.append(func);
433 #endif
434 }
435
436
437 /***********************************************************************
438 * map_images_nolock
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.
442 *
443 * info[] is in bottom-up order i.e. libobjc will be earlier in the
444 * array than any library that links to libobjc.
445 *
446 * Locking: loadMethodLock(old) or runtimeLock(new) acquired by map_images.
447 **********************************************************************/
448 #if __OBJC2__
449 #include "objc-file.h"
450 #else
451 #include "objc-file-old.h"
452 #endif
453
454 void
455 map_images_nolock(unsigned mhCount, const char * const mhPaths[],
456 const struct mach_header * const mhdrs[])
457 {
458 static bool firstTime = YES;
459 header_info *hList[mhCount];
460 uint32_t hCount;
461 size_t selrefCount = 0;
462
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?
466 if (firstTime) {
467 preopt_init();
468 }
469
470 if (PrintImages) {
471 _objc_inform("IMAGES: processing %u newly-mapped images...\n", mhCount);
472 }
473
474
475 // Find all images with Objective-C metadata.
476 hCount = 0;
477
478 // Count classes. Size various table based on the total.
479 int totalClasses = 0;
480 int unoptimizedTotalClasses = 0;
481 {
482 uint32_t i = mhCount;
483 while (i--) {
484 const headerType *mhdr = (const headerType *)mhdrs[i];
485
486 auto hi = addHeader(mhdr, mhPaths[i], totalClasses, unoptimizedTotalClasses);
487 if (!hi) {
488 // no objc data in this entry
489 continue;
490 }
491
492 if (mhdr->filetype == MH_EXECUTE) {
493 // Size some data structures based on main executable's size
494 #if __OBJC2__
495 size_t count;
496 _getObjc2SelectorRefs(hi, &count);
497 selrefCount += count;
498 _getObjc2MessageRefs(hi, &count);
499 selrefCount += count;
500 #else
501 _getObjcSelectorRefs(hi, &selrefCount);
502 #endif
503
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.");
512 }
513 #endif
514 }
515
516 hList[hCount++] = hi;
517
518 if (PrintImages) {
519 _objc_inform("IMAGES: loading image for %s%s%s%s%s\n",
520 hi->fname(),
521 mhdr->filetype == MH_BUNDLE ? " (bundle)" : "",
522 hi->info()->isReplacement() ? " (replacement)" : "",
523 hi->info()->hasCategoryClassProperties() ? " (has class properties)" : "",
524 hi->info()->optimizedByDyld()?" (preoptimized)":"");
525 }
526 }
527 }
528
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.
535 if (firstTime) {
536 sel_init(selrefCount);
537 arr_init();
538
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.
543
544 for (uint32_t i = 0; i < hCount; i++) {
545 auto hi = hList[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());
553 }
554 }
555 #endif
556
557 #if TARGET_OS_OSX
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.
561
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()));
569 }
570 }
571
572 for (uint32_t i = 0; i < hCount; i++) {
573 auto hi = hList[i];
574 auto mh = hi->mhdr();
575 if (mh->filetype != MH_EXECUTE) continue;
576 unsigned long size;
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");
583 }
584 }
585 break; // assume only one MH_EXECUTE image
586 }
587 #endif
588
589 }
590
591 if (hCount > 0) {
592 _read_images(hList, hCount, totalClasses, unoptimizedTotalClasses);
593 }
594
595 firstTime = NO;
596
597 // Call image load funcs after everything is set up.
598 for (auto func : loadImageFuncs) {
599 for (uint32_t i = 0; i < mhCount; i++) {
600 func(mhdrs[i]);
601 }
602 }
603 }
604
605
606 /***********************************************************************
607 * unmap_image_nolock
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.
611 *
612 * Locking: loadMethodLock(both) and runtimeLock(new) acquired by unmap_image.
613 **********************************************************************/
614 void
615 unmap_image_nolock(const struct mach_header *mh)
616 {
617 if (PrintImages) {
618 _objc_inform("IMAGES: processing 1 newly-unmapped image...\n");
619 }
620
621 header_info *hi;
622
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) {
626 break;
627 }
628 }
629
630 if (!hi) return;
631
632 if (PrintImages) {
633 _objc_inform("IMAGES: unloading image for %s%s%s\n",
634 hi->fname(),
635 hi->mhdr()->filetype == MH_BUNDLE ? " (bundle)" : "",
636 hi->info()->isReplacement() ? " (replacement)" : "");
637 }
638
639 _unload_image(hi);
640
641 // Remove header_info from header list
642 removeHeader(hi);
643 free(hi);
644 }
645
646
647 /***********************************************************************
648 * static_init
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()
654 {
655 size_t count;
656 auto inits = getLibobjcInitializers(&_mh_dylib_header, &count);
657 for (size_t i = 0; i < count; i++) {
658 inits[i]();
659 }
660 }
661
662
663 /***********************************************************************
664 * _objc_atfork_prepare
665 * _objc_atfork_parent
666 * _objc_atfork_child
667 * Allow ObjC to be used between fork() and exec().
668 * libc requires this because it has fork-safe functions that use os_objects.
669 *
670 * _objc_atfork_prepare() acquires all locks.
671 * _objc_atfork_parent() releases the locks again.
672 * _objc_atfork_child() forcibly resets the locks.
673 **********************************************************************/
674
675 // Declare lock ordering.
676 #if LOCKDEBUG
677 __attribute__((constructor))
678 static void defineLockOrder()
679 {
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);
684 #if __OBJC2__
685 lockdebug_lock_precedes_lock(&runtimeLock, &crashlog_lock);
686 lockdebug_lock_precedes_lock(&DemangleCacheLock, &crashlog_lock);
687 #else
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);
692 #endif
693 lockdebug_lock_precedes_lock(&selLock, &crashlog_lock);
694 #if CONFIG_USE_CACHE_LOCK
695 lockdebug_lock_precedes_lock(&cacheUpdateLock, &crashlog_lock);
696 #endif
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);
704
705 // loadMethodLock precedes everything
706 // because it is held while +load methods run
707 lockdebug_lock_precedes_lock(&loadMethodLock, &classInitLock);
708 #if __OBJC2__
709 lockdebug_lock_precedes_lock(&loadMethodLock, &runtimeLock);
710 lockdebug_lock_precedes_lock(&loadMethodLock, &DemangleCacheLock);
711 #else
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);
716 #endif
717 lockdebug_lock_precedes_lock(&loadMethodLock, &selLock);
718 #if CONFIG_USE_CACHE_LOCK
719 lockdebug_lock_precedes_lock(&loadMethodLock, &cacheUpdateLock);
720 #endif
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);
728
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);
737 };
738 #if __OBJC2__
739 PropertyAndCppObjectAndAssocLocksPrecedeLock(&runtimeLock);
740 PropertyAndCppObjectAndAssocLocksPrecedeLock(&DemangleCacheLock);
741 #else
742 PropertyAndCppObjectAndAssocLocksPrecedeLock(&methodListLock);
743 PropertyAndCppObjectAndAssocLocksPrecedeLock(&classLock);
744 PropertyAndCppObjectAndAssocLocksPrecedeLock(&NXUniqueStringLock);
745 PropertyAndCppObjectAndAssocLocksPrecedeLock(&impLock);
746 #endif
747 PropertyAndCppObjectAndAssocLocksPrecedeLock(&classInitLock);
748 PropertyAndCppObjectAndAssocLocksPrecedeLock(&selLock);
749 #if CONFIG_USE_CACHE_LOCK
750 PropertyAndCppObjectAndAssocLocksPrecedeLock(&cacheUpdateLock);
751 #endif
752 PropertyAndCppObjectAndAssocLocksPrecedeLock(&objcMsgLogLock);
753 PropertyAndCppObjectAndAssocLocksPrecedeLock(&AltHandlerDebugLock);
754
755 SideTableLocksSucceedLocks(PropertyLocks);
756 SideTableLocksSucceedLocks(CppObjectLocks);
757 SideTableLocksSucceedLock(&AssociationsManagerLock);
758
759 PropertyLocks.precedeLock(&AssociationsManagerLock);
760 CppObjectLocks.precedeLock(&AssociationsManagerLock);
761
762 #if __OBJC2__
763 lockdebug_lock_precedes_lock(&classInitLock, &runtimeLock);
764 #endif
765
766 #if __OBJC2__
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);
775 #endif
776 lockdebug_lock_precedes_lock(&runtimeLock, &DemangleCacheLock);
777 #else
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);
787 #endif
788 lockdebug_lock_precedes_lock(&methodListLock, &impLock);
789 lockdebug_lock_precedes_lock(&classLock, &selLock);
790 lockdebug_lock_precedes_lock(&classLock, &cacheUpdateLock);
791 #endif
792
793 // Striped locks use address order internally.
794 SideTableDefineLockOrder();
795 PropertyLocks.defineLockOrder();
796 StructLocks.defineLockOrder();
797 CppObjectLocks.defineLockOrder();
798 }
799 // LOCKDEBUG
800 #endif
801
802 static bool ForkIsMultithreaded;
803 void _objc_atfork_prepare()
804 {
805 // Save threaded-ness for the child's use.
806 ForkIsMultithreaded = pthread_is_threaded_np();
807
808 lockdebug_assert_no_locks_locked();
809 lockdebug_setInForkPrepare(true);
810
811 loadMethodLock.lock();
812 PropertyLocks.lockAll();
813 CppObjectLocks.lockAll();
814 AssociationsManagerLock.lock();
815 SideTableLockAll();
816 classInitLock.enter();
817 #if __OBJC2__
818 runtimeLock.lock();
819 DemangleCacheLock.lock();
820 #else
821 methodListLock.lock();
822 classLock.lock();
823 NXUniqueStringLock.lock();
824 impLock.lock();
825 #endif
826 selLock.lock();
827 #if CONFIG_USE_CACHE_LOCK
828 cacheUpdateLock.lock();
829 #endif
830 objcMsgLogLock.lock();
831 AltHandlerDebugLock.lock();
832 StructLocks.lockAll();
833 crashlog_lock.lock();
834
835 lockdebug_assert_all_locks_locked();
836 lockdebug_setInForkPrepare(false);
837 }
838
839 void _objc_atfork_parent()
840 {
841 lockdebug_assert_all_locks_locked();
842
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();
853 #endif
854 selLock.unlock();
855 SideTableUnlockAll();
856 #if __OBJC2__
857 DemangleCacheLock.unlock();
858 runtimeLock.unlock();
859 #else
860 impLock.unlock();
861 NXUniqueStringLock.unlock();
862 methodListLock.unlock();
863 classLock.unlock();
864 #endif
865 classInitLock.leave();
866
867 lockdebug_assert_no_locks_locked();
868 }
869
870 void _objc_atfork_child()
871 {
872 // Turn on +initialize fork safety enforcement if applicable.
873 if (ForkIsMultithreaded && !DisableInitializeForkSafety) {
874 MultithreadedForkChild = true;
875 }
876
877 lockdebug_assert_all_locks_locked();
878
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();
889 #endif
890 selLock.forceReset();
891 SideTableForceResetAll();
892 #if __OBJC2__
893 DemangleCacheLock.forceReset();
894 runtimeLock.forceReset();
895 #else
896 impLock.forceReset();
897 NXUniqueStringLock.forceReset();
898 methodListLock.forceReset();
899 classLock.forceReset();
900 #endif
901 classInitLock.forceReset();
902
903 lockdebug_assert_no_locks_locked();
904 }
905
906
907 /***********************************************************************
908 * _objc_init
909 * Bootstrap initialization. Registers our image notifier with dyld.
910 * Called by libSystem BEFORE library initialization time
911 **********************************************************************/
912
913 void _objc_init(void)
914 {
915 static bool initialized = false;
916 if (initialized) return;
917 initialized = true;
918
919 // fixme defer initialization until an objc-using image is found?
920 environ_init();
921 tls_init();
922 static_init();
923 runtime_init();
924 exception_init();
925 cache_init();
926 _imp_implementationWithBlock_init();
927
928 _dyld_objc_notify_register(&map_images, load_images, unmap_image);
929
930 #if __OBJC2__
931 didCallDyldNotifyRegister = true;
932 #endif
933 }
934
935
936 /***********************************************************************
937 * _headerForAddress.
938 * addr can be a class or a category
939 **********************************************************************/
940 static const header_info *_headerForAddress(void *addr)
941 {
942 #if __OBJC2__
943 const char *segnames[] = { "__DATA", "__DATA_CONST", "__DATA_DIRTY" };
944 #else
945 const char *segnames[] = { "__OBJC" };
946 #endif
947 header_info *hi;
948
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);
953 if (!seg) continue;
954
955 // Is the class in this header?
956 if ((uint8_t *)addr >= seg && (uint8_t *)addr < seg + seg_size) {
957 return hi;
958 }
959 }
960 }
961
962 // Not found
963 return 0;
964 }
965
966
967 /***********************************************************************
968 * _headerForClass
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)
973 {
974 return _headerForAddress(cls);
975 }
976
977
978 /**********************************************************************
979 * secure_open
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)
984 * 2. owned by euid
985 * 3. permissions 0600
986 * 4. link count == 1
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)
990 {
991 struct stat fs, ls;
992 int fd = -1;
993 bool truncate = NO;
994 bool create = NO;
995
996 if (flags & O_TRUNC) {
997 // Don't truncate the file until after it is open and verified.
998 truncate = YES;
999 flags &= ~O_TRUNC;
1000 }
1001 if (flags & O_CREAT) {
1002 // Don't create except when we're ready for it
1003 create = YES;
1004 flags &= ~O_CREAT;
1005 flags &= ~O_EXCL;
1006 }
1007
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);
1012 if (fd >= 0) {
1013 // File was created successfully.
1014 // New file does not need to be truncated.
1015 return fd;
1016 } else {
1017 // File creation failed.
1018 return -1;
1019 }
1020 } else {
1021 // lstat failed, or user doesn't want to create the file
1022 return -1;
1023 }
1024 } else {
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?
1030 {
1031 // Attributes look ok - open it and check attributes again
1032 fd = open(filename, flags, 0000);
1033 if (fd >= 0) {
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?
1041 {
1042 // File is open and OK
1043 if (truncate) ftruncate(fd, 0);
1044 return fd;
1045 } else {
1046 // Opened file looks funny - close it
1047 close(fd);
1048 return -1;
1049 }
1050 } else {
1051 // File didn't open
1052 return -1;
1053 }
1054 } else {
1055 // Unopened file looks funny - don't open it
1056 return -1;
1057 }
1058 }
1059 }
1060
1061
1062 #if TARGET_OS_IPHONE
1063
1064 const char *__crashreporter_info__ = NULL;
1065
1066 const char *CRSetCrashLogMessage(const char *msg)
1067 {
1068 __crashreporter_info__ = msg;
1069 return msg;
1070 }
1071 const char *CRGetCrashLogMessage(void)
1072 {
1073 return __crashreporter_info__;
1074 }
1075
1076 #endif
1077
1078 // TARGET_OS_MAC
1079 #else
1080
1081
1082 #error unknown OS
1083
1084
1085 #endif