]> git.saurik.com Git - apple/objc4.git/blob - runtime/objc-os.mm
objc4-787.1.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 // If dyld3 optimized the main executable, then there shouldn't
496 // be any selrefs needed in the dynamic map so we can just init
497 // to a 0 sized map
498 if ( !hi->hasPreoptimizedSelectors() ) {
499 size_t count;
500 _getObjc2SelectorRefs(hi, &count);
501 selrefCount += count;
502 _getObjc2MessageRefs(hi, &count);
503 selrefCount += count;
504 }
505 #else
506 _getObjcSelectorRefs(hi, &selrefCount);
507 #endif
508
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.");
517 }
518 #endif
519 }
520
521 hList[hCount++] = hi;
522
523 if (PrintImages) {
524 _objc_inform("IMAGES: loading image for %s%s%s%s%s\n",
525 hi->fname(),
526 mhdr->filetype == MH_BUNDLE ? " (bundle)" : "",
527 hi->info()->isReplacement() ? " (replacement)" : "",
528 hi->info()->hasCategoryClassProperties() ? " (has class properties)" : "",
529 hi->info()->optimizedByDyld()?" (preoptimized)":"");
530 }
531 }
532 }
533
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.
540 if (firstTime) {
541 sel_init(selrefCount);
542 arr_init();
543
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.
548
549 for (uint32_t i = 0; i < hCount; i++) {
550 auto hi = hList[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());
558 }
559 }
560 #endif
561
562 #if TARGET_OS_OSX
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.
566
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()));
574 }
575 }
576
577 for (uint32_t i = 0; i < hCount; i++) {
578 auto hi = hList[i];
579 auto mh = hi->mhdr();
580 if (mh->filetype != MH_EXECUTE) continue;
581 unsigned long size;
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");
588 }
589 }
590 break; // assume only one MH_EXECUTE image
591 }
592 #endif
593
594 }
595
596 if (hCount > 0) {
597 _read_images(hList, hCount, totalClasses, unoptimizedTotalClasses);
598 }
599
600 firstTime = NO;
601
602 // Call image load funcs after everything is set up.
603 for (auto func : loadImageFuncs) {
604 for (uint32_t i = 0; i < mhCount; i++) {
605 func(mhdrs[i]);
606 }
607 }
608 }
609
610
611 /***********************************************************************
612 * unmap_image_nolock
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.
616 *
617 * Locking: loadMethodLock(both) and runtimeLock(new) acquired by unmap_image.
618 **********************************************************************/
619 void
620 unmap_image_nolock(const struct mach_header *mh)
621 {
622 if (PrintImages) {
623 _objc_inform("IMAGES: processing 1 newly-unmapped image...\n");
624 }
625
626 header_info *hi;
627
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) {
631 break;
632 }
633 }
634
635 if (!hi) return;
636
637 if (PrintImages) {
638 _objc_inform("IMAGES: unloading image for %s%s%s\n",
639 hi->fname(),
640 hi->mhdr()->filetype == MH_BUNDLE ? " (bundle)" : "",
641 hi->info()->isReplacement() ? " (replacement)" : "");
642 }
643
644 _unload_image(hi);
645
646 // Remove header_info from header list
647 removeHeader(hi);
648 free(hi);
649 }
650
651
652 /***********************************************************************
653 * static_init
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()
659 {
660 size_t count;
661 auto inits = getLibobjcInitializers(&_mh_dylib_header, &count);
662 for (size_t i = 0; i < count; i++) {
663 inits[i]();
664 }
665 }
666
667
668 /***********************************************************************
669 * _objc_atfork_prepare
670 * _objc_atfork_parent
671 * _objc_atfork_child
672 * Allow ObjC to be used between fork() and exec().
673 * libc requires this because it has fork-safe functions that use os_objects.
674 *
675 * _objc_atfork_prepare() acquires all locks.
676 * _objc_atfork_parent() releases the locks again.
677 * _objc_atfork_child() forcibly resets the locks.
678 **********************************************************************/
679
680 // Declare lock ordering.
681 #if LOCKDEBUG
682 __attribute__((constructor))
683 static void defineLockOrder()
684 {
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);
689 #if __OBJC2__
690 lockdebug_lock_precedes_lock(&runtimeLock, &crashlog_lock);
691 lockdebug_lock_precedes_lock(&DemangleCacheLock, &crashlog_lock);
692 #else
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);
697 #endif
698 lockdebug_lock_precedes_lock(&selLock, &crashlog_lock);
699 #if CONFIG_USE_CACHE_LOCK
700 lockdebug_lock_precedes_lock(&cacheUpdateLock, &crashlog_lock);
701 #endif
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);
709
710 // loadMethodLock precedes everything
711 // because it is held while +load methods run
712 lockdebug_lock_precedes_lock(&loadMethodLock, &classInitLock);
713 #if __OBJC2__
714 lockdebug_lock_precedes_lock(&loadMethodLock, &runtimeLock);
715 lockdebug_lock_precedes_lock(&loadMethodLock, &DemangleCacheLock);
716 #else
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);
721 #endif
722 lockdebug_lock_precedes_lock(&loadMethodLock, &selLock);
723 #if CONFIG_USE_CACHE_LOCK
724 lockdebug_lock_precedes_lock(&loadMethodLock, &cacheUpdateLock);
725 #endif
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);
733
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);
742 };
743 #if __OBJC2__
744 PropertyAndCppObjectAndAssocLocksPrecedeLock(&runtimeLock);
745 PropertyAndCppObjectAndAssocLocksPrecedeLock(&DemangleCacheLock);
746 #else
747 PropertyAndCppObjectAndAssocLocksPrecedeLock(&methodListLock);
748 PropertyAndCppObjectAndAssocLocksPrecedeLock(&classLock);
749 PropertyAndCppObjectAndAssocLocksPrecedeLock(&NXUniqueStringLock);
750 PropertyAndCppObjectAndAssocLocksPrecedeLock(&impLock);
751 #endif
752 PropertyAndCppObjectAndAssocLocksPrecedeLock(&classInitLock);
753 PropertyAndCppObjectAndAssocLocksPrecedeLock(&selLock);
754 #if CONFIG_USE_CACHE_LOCK
755 PropertyAndCppObjectAndAssocLocksPrecedeLock(&cacheUpdateLock);
756 #endif
757 PropertyAndCppObjectAndAssocLocksPrecedeLock(&objcMsgLogLock);
758 PropertyAndCppObjectAndAssocLocksPrecedeLock(&AltHandlerDebugLock);
759
760 SideTableLocksSucceedLocks(PropertyLocks);
761 SideTableLocksSucceedLocks(CppObjectLocks);
762 SideTableLocksSucceedLock(&AssociationsManagerLock);
763
764 PropertyLocks.precedeLock(&AssociationsManagerLock);
765 CppObjectLocks.precedeLock(&AssociationsManagerLock);
766
767 #if __OBJC2__
768 lockdebug_lock_precedes_lock(&classInitLock, &runtimeLock);
769 #endif
770
771 #if __OBJC2__
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);
780 #endif
781 lockdebug_lock_precedes_lock(&runtimeLock, &DemangleCacheLock);
782 #else
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);
792 #endif
793 lockdebug_lock_precedes_lock(&methodListLock, &impLock);
794 lockdebug_lock_precedes_lock(&classLock, &selLock);
795 lockdebug_lock_precedes_lock(&classLock, &cacheUpdateLock);
796 #endif
797
798 // Striped locks use address order internally.
799 SideTableDefineLockOrder();
800 PropertyLocks.defineLockOrder();
801 StructLocks.defineLockOrder();
802 CppObjectLocks.defineLockOrder();
803 }
804 // LOCKDEBUG
805 #endif
806
807 static bool ForkIsMultithreaded;
808 void _objc_atfork_prepare()
809 {
810 // Save threaded-ness for the child's use.
811 ForkIsMultithreaded = pthread_is_threaded_np();
812
813 lockdebug_assert_no_locks_locked();
814 lockdebug_setInForkPrepare(true);
815
816 loadMethodLock.lock();
817 PropertyLocks.lockAll();
818 CppObjectLocks.lockAll();
819 AssociationsManagerLock.lock();
820 SideTableLockAll();
821 classInitLock.enter();
822 #if __OBJC2__
823 runtimeLock.lock();
824 DemangleCacheLock.lock();
825 #else
826 methodListLock.lock();
827 classLock.lock();
828 NXUniqueStringLock.lock();
829 impLock.lock();
830 #endif
831 selLock.lock();
832 #if CONFIG_USE_CACHE_LOCK
833 cacheUpdateLock.lock();
834 #endif
835 objcMsgLogLock.lock();
836 AltHandlerDebugLock.lock();
837 StructLocks.lockAll();
838 crashlog_lock.lock();
839
840 lockdebug_assert_all_locks_locked();
841 lockdebug_setInForkPrepare(false);
842 }
843
844 void _objc_atfork_parent()
845 {
846 lockdebug_assert_all_locks_locked();
847
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();
858 #endif
859 selLock.unlock();
860 SideTableUnlockAll();
861 #if __OBJC2__
862 DemangleCacheLock.unlock();
863 runtimeLock.unlock();
864 #else
865 impLock.unlock();
866 NXUniqueStringLock.unlock();
867 methodListLock.unlock();
868 classLock.unlock();
869 #endif
870 classInitLock.leave();
871
872 lockdebug_assert_no_locks_locked();
873 }
874
875 void _objc_atfork_child()
876 {
877 // Turn on +initialize fork safety enforcement if applicable.
878 if (ForkIsMultithreaded && !DisableInitializeForkSafety) {
879 MultithreadedForkChild = true;
880 }
881
882 lockdebug_assert_all_locks_locked();
883
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();
894 #endif
895 selLock.forceReset();
896 SideTableForceResetAll();
897 #if __OBJC2__
898 DemangleCacheLock.forceReset();
899 runtimeLock.forceReset();
900 #else
901 impLock.forceReset();
902 NXUniqueStringLock.forceReset();
903 methodListLock.forceReset();
904 classLock.forceReset();
905 #endif
906 classInitLock.forceReset();
907
908 lockdebug_assert_no_locks_locked();
909 }
910
911
912 /***********************************************************************
913 * _objc_init
914 * Bootstrap initialization. Registers our image notifier with dyld.
915 * Called by libSystem BEFORE library initialization time
916 **********************************************************************/
917
918 void _objc_init(void)
919 {
920 static bool initialized = false;
921 if (initialized) return;
922 initialized = true;
923
924 // fixme defer initialization until an objc-using image is found?
925 environ_init();
926 tls_init();
927 static_init();
928 runtime_init();
929 exception_init();
930 cache_init();
931 _imp_implementationWithBlock_init();
932
933 _dyld_objc_notify_register(&map_images, load_images, unmap_image);
934
935 #if __OBJC2__
936 didCallDyldNotifyRegister = true;
937 #endif
938 }
939
940
941 /***********************************************************************
942 * _headerForAddress.
943 * addr can be a class or a category
944 **********************************************************************/
945 static const header_info *_headerForAddress(void *addr)
946 {
947 #if __OBJC2__
948 const char *segnames[] = { "__DATA", "__DATA_CONST", "__DATA_DIRTY" };
949 #else
950 const char *segnames[] = { "__OBJC" };
951 #endif
952 header_info *hi;
953
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);
958 if (!seg) continue;
959
960 // Is the class in this header?
961 if ((uint8_t *)addr >= seg && (uint8_t *)addr < seg + seg_size) {
962 return hi;
963 }
964 }
965 }
966
967 // Not found
968 return 0;
969 }
970
971
972 /***********************************************************************
973 * _headerForClass
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)
978 {
979 return _headerForAddress(cls);
980 }
981
982
983 /**********************************************************************
984 * secure_open
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)
989 * 2. owned by euid
990 * 3. permissions 0600
991 * 4. link count == 1
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)
995 {
996 struct stat fs, ls;
997 int fd = -1;
998 bool truncate = NO;
999 bool create = NO;
1000
1001 if (flags & O_TRUNC) {
1002 // Don't truncate the file until after it is open and verified.
1003 truncate = YES;
1004 flags &= ~O_TRUNC;
1005 }
1006 if (flags & O_CREAT) {
1007 // Don't create except when we're ready for it
1008 create = YES;
1009 flags &= ~O_CREAT;
1010 flags &= ~O_EXCL;
1011 }
1012
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);
1017 if (fd >= 0) {
1018 // File was created successfully.
1019 // New file does not need to be truncated.
1020 return fd;
1021 } else {
1022 // File creation failed.
1023 return -1;
1024 }
1025 } else {
1026 // lstat failed, or user doesn't want to create the file
1027 return -1;
1028 }
1029 } else {
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?
1035 {
1036 // Attributes look ok - open it and check attributes again
1037 fd = open(filename, flags, 0000);
1038 if (fd >= 0) {
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?
1046 {
1047 // File is open and OK
1048 if (truncate) ftruncate(fd, 0);
1049 return fd;
1050 } else {
1051 // Opened file looks funny - close it
1052 close(fd);
1053 return -1;
1054 }
1055 } else {
1056 // File didn't open
1057 return -1;
1058 }
1059 } else {
1060 // Unopened file looks funny - don't open it
1061 return -1;
1062 }
1063 }
1064 }
1065
1066
1067 #if TARGET_OS_IPHONE
1068
1069 const char *__crashreporter_info__ = NULL;
1070
1071 const char *CRSetCrashLogMessage(const char *msg)
1072 {
1073 __crashreporter_info__ = msg;
1074 return msg;
1075 }
1076 const char *CRGetCrashLogMessage(void)
1077 {
1078 return __crashreporter_info__;
1079 }
1080
1081 #endif
1082
1083 // TARGET_OS_MAC
1084 #else
1085
1086
1087 #error unknown OS
1088
1089
1090 #endif