]> git.saurik.com Git - apple/objc4.git/blame - runtime/objc-runtime.mm
objc4-818.2.tar.gz
[apple/objc4.git] / runtime / objc-runtime.mm
CommitLineData
13d88034 1/*
b3962a83 2 * Copyright (c) 1999-2007 Apple Inc. All Rights Reserved.
390d5862 3 *
b3962a83 4 * @APPLE_LICENSE_HEADER_START@
390d5862
A
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 *
13d88034 13 * The Original Code and all software distributed under the License are
390d5862 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
13d88034
A
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
390d5862
A
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 *
13d88034
A
21 * @APPLE_LICENSE_HEADER_END@
22 */
23/***********************************************************************
41c8faa5
A
24* objc-runtime.m
25* Copyright 1988-1996, NeXT Software, Inc.
26* Author: s. naroff
27*
28**********************************************************************/
13d88034 29
2bfd4448
A
30
31
13d88034 32/***********************************************************************
41c8faa5
A
33* Imports.
34**********************************************************************/
13d88034 35
34d5b5e8 36#include <os/feature_private.h> // os_feature_enabled_simple()
7af964d1
A
37#include "objc-private.h"
38#include "objc-loadmethod.h"
1807f628 39#include "objc-file.h"
8972963c 40#include "message.h"
2bfd4448 41
2bfd4448 42/***********************************************************************
b3962a83 43* Exports.
2bfd4448 44**********************************************************************/
2bfd4448 45
66799735
A
46/* Linker metadata symbols */
47
48// NSObject was in Foundation/CF on macOS < 10.8.
49#if TARGET_OS_OSX
50#if __OBJC2__
51
52const char __objc_nsobject_class_10_5 = 0;
53const char __objc_nsobject_class_10_6 = 0;
54const char __objc_nsobject_class_10_7 = 0;
55
56const char __objc_nsobject_metaclass_10_5 = 0;
57const char __objc_nsobject_metaclass_10_6 = 0;
58const char __objc_nsobject_metaclass_10_7 = 0;
59
60const char __objc_nsobject_isa_10_5 = 0;
61const char __objc_nsobject_isa_10_6 = 0;
62const char __objc_nsobject_isa_10_7 = 0;
63
64#else
65
66const char __objc_nsobject_class_10_5 = 0;
67const char __objc_nsobject_class_10_6 = 0;
68const char __objc_nsobject_class_10_7 = 0;
69
70#endif
71#endif
72
b3962a83 73// Settings from environment variables
7257e56c
A
74#define OPTION(var, env, help) bool var = false;
75#include "objc-env.h"
76#undef OPTION
77
78struct option_t {
79 bool* var;
80 const char *env;
81 const char *help;
82 size_t envlen;
83};
84
85const option_t Settings[] = {
86#define OPTION(var, env, help) option_t{&var, #env, help, strlen(#env)},
87#include "objc-env.h"
88#undef OPTION
89};
2bfd4448 90
34d5b5e8
A
91namespace objc {
92 int PageCountWarning = 50; // Default value if the environment variable is not set
93}
2bfd4448 94
b3962a83 95// objc's key for pthread_getspecific
1807f628
A
96#if SUPPORT_DIRECT_THREAD_KEYS
97#define _objc_pthread_key TLS_DIRECT_KEY
98#else
7af964d1 99static tls_key_t _objc_pthread_key;
1807f628 100#endif
2bfd4448 101
7af964d1 102// Selectors
cd5f04f5
A
103SEL SEL_cxx_construct = NULL;
104SEL SEL_cxx_destruct = NULL;
cd5f04f5 105
1807f628 106struct objc::SafeRanges objc::dataSegmentsRanges;
cd5f04f5
A
107header_info *FirstHeader = 0; // NULL means empty list
108header_info *LastHeader = 0; // NULL means invalid; recompute it
2bfd4448 109
4a109af3
A
110// Set to true on the child side of fork()
111// if the parent process was multithreaded when fork() was called.
112bool MultithreadedForkChild = false;
113
114
115/***********************************************************************
116* objc_noop_imp. Used when we need to install a do-nothing method somewhere.
117**********************************************************************/
118id objc_noop_imp(id self, SEL _cmd __unused) {
119 return self;
120}
121
122
13ba007e
A
123/***********************************************************************
124* _objc_isDebugBuild. Defined in debug builds only.
125* Some test code looks for the presence of this symbol.
126**********************************************************************/
127#if DEBUG != OBJC_IS_DEBUG_BUILD
128#error mismatch in debug-ness macros
129// DEBUG is used in our code. OBJC_IS_DEBUG_BUILD is used in the
130// header declaration of _objc_isDebugBuild() because that header
131// is visible to other clients who might have their own DEBUG macro.
132#endif
133
134#if OBJC_IS_DEBUG_BUILD
135void _objc_isDebugBuild(void) { }
136#endif
137
138
13d88034 139/***********************************************************************
b3962a83
A
140* objc_getClass. Return the id of the named class. If the class does
141* not exist, call _objc_classLoader and then objc_classHandler, either of
142* which may create a new class.
143* Warning: doesn't work if aClassName is the name of a posed-for class's isa!
41c8faa5 144**********************************************************************/
7257e56c 145Class objc_getClass(const char *aClassName)
13d88034 146{
b3962a83 147 if (!aClassName) return Nil;
41c8faa5 148
b3962a83
A
149 // NO unconnected, YES class handler
150 return look_up_class(aClassName, NO, YES);
13d88034
A
151}
152
2bfd4448 153
13d88034 154/***********************************************************************
b3962a83
A
155* objc_getRequiredClass.
156* Same as objc_getClass, but kills the process if the class is not found.
157* This is used by ZeroLink, where failing to find a class would be a
158* compile-time link error without ZeroLink.
41c8faa5 159**********************************************************************/
7257e56c 160Class objc_getRequiredClass(const char *aClassName)
13d88034 161{
7257e56c 162 Class cls = objc_getClass(aClassName);
b3962a83
A
163 if (!cls) _objc_fatal("link error: class '%s' not found.", aClassName);
164 return cls;
13d88034
A
165}
166
2bfd4448 167
13d88034 168/***********************************************************************
b3962a83
A
169* objc_lookUpClass. Return the id of the named class.
170* If the class does not exist, call _objc_classLoader, which may create
171* a new class.
172*
173* Formerly objc_getClassWithoutWarning ()
41c8faa5 174**********************************************************************/
7257e56c 175Class objc_lookUpClass(const char *aClassName)
13d88034 176{
b3962a83 177 if (!aClassName) return Nil;
13d88034 178
b3962a83
A
179 // NO unconnected, NO class handler
180 return look_up_class(aClassName, NO, NO);
181}
2bfd4448 182
2bfd4448 183
13d88034 184/***********************************************************************
b3962a83
A
185* objc_getMetaClass. Return the id of the meta class the named class.
186* Warning: doesn't work if aClassName is the name of a posed-for class's isa!
41c8faa5 187**********************************************************************/
7257e56c 188Class objc_getMetaClass(const char *aClassName)
41c8faa5 189{
b3962a83 190 Class cls;
41c8faa5 191
b3962a83 192 if (!aClassName) return Nil;
390d5862 193
7257e56c 194 cls = objc_getClass (aClassName);
b3962a83 195 if (!cls)
41c8faa5 196 {
b3962a83
A
197 _objc_inform ("class `%s' not linked into application", aClassName);
198 return Nil;
41c8faa5 199 }
2bfd4448 200
7257e56c 201 return cls->ISA();
13d88034
A
202}
203
1807f628
A
204/***********************************************************************
205 * objc::SafeRanges::find. Find an image data segment that contains address
206 **********************************************************************/
207bool
208objc::SafeRanges::find(uintptr_t ptr, uint32_t &pos)
209{
210 if (!sorted) {
211 std::sort(ranges, ranges + count, [](const Range &s1, const Range &s2){
212 return s1.start < s2.start;
213 });
214 sorted = true;
215 }
216
217 uint32_t l = 0, r = count;
218 while (l < r) {
219 uint32_t i = (l + r) / 2;
220
221 if (ptr < ranges[i].start) {
222 r = i;
223 } else if (ptr >= ranges[i].end) {
224 l = i + 1;
225 } else {
226 pos = i;
227 return true;
228 }
229 }
230
231 pos = UINT32_MAX;
232 return false;
233}
234
235/***********************************************************************
236 * objc::SafeRanges::add. Register a new well known data segment.
237 **********************************************************************/
238void
239objc::SafeRanges::add(uintptr_t start, uintptr_t end)
240{
241 if (count == size) {
242 // Have a typical malloc growth:
243 // - size <= 32: grow by 4
244 // - size <= 64: grow by 8
245 // - size <= 128: grow by 16
246 // ... etc
247 size += size < 16 ? 4 : 1 << (fls(size) - 3);
248 ranges = (Range *)realloc(ranges, sizeof(Range) * size);
249 }
250 ranges[count++] = Range{ start, end };
251 sorted = false;
252}
253
254/***********************************************************************
255 * objc::SafeRanges::remove. Remove a previously known data segment.
256 **********************************************************************/
257void
258objc::SafeRanges::remove(uintptr_t start, uintptr_t end)
259{
260 uint32_t pos;
261
262 if (!find(start, pos) || ranges[pos].end != end) {
263 _objc_fatal("Cannot find range %#lx..%#lx", start, end);
264 }
265 if (pos < --count) {
266 ranges[pos] = ranges[count];
267 sorted = false;
268 }
269}
13d88034 270
13d88034 271/***********************************************************************
cd5f04f5 272* appendHeader. Add a newly-constructed header_info to the list.
41c8faa5 273**********************************************************************/
cd5f04f5 274void appendHeader(header_info *hi)
b3962a83 275{
2bfd4448
A
276 // Add the header to the header list.
277 // The header is appended to the list, to preserve the bottom-up order.
c1e772c4 278 hi->setNext(NULL);
2bfd4448
A
279 if (!FirstHeader) {
280 // list is empty
7af964d1 281 FirstHeader = LastHeader = hi;
2bfd4448
A
282 } else {
283 if (!LastHeader) {
284 // list is not empty, but LastHeader is invalid - recompute it
285 LastHeader = FirstHeader;
c1e772c4 286 while (LastHeader->getNext()) LastHeader = LastHeader->getNext();
390d5862 287 }
2bfd4448 288 // LastHeader is now valid
c1e772c4 289 LastHeader->setNext(hi);
7af964d1 290 LastHeader = hi;
390d5862 291 }
1807f628
A
292
293#if __OBJC2__
294 if ((hi->mhdr()->flags & MH_DYLIB_IN_CACHE) == 0) {
295 foreach_data_segment(hi->mhdr(), [](const segmentType *seg, intptr_t slide) {
296 uintptr_t start = (uintptr_t)seg->vmaddr + slide;
297 objc::dataSegmentsRanges.add(start, start + seg->vmsize);
298 });
299 }
300#endif
390d5862
A
301}
302
2bfd4448 303
390d5862 304/***********************************************************************
cd5f04f5 305* removeHeader
2bfd4448
A
306* Remove the given header from the header list.
307* FirstHeader is updated.
308* LastHeader is set to NULL. Any code that uses LastHeader must
309* detect this NULL and recompute LastHeader by traversing the list.
390d5862 310**********************************************************************/
cd5f04f5 311void removeHeader(header_info *hi)
390d5862 312{
c1e772c4
A
313 header_info *prev = NULL;
314 header_info *current = NULL;
315
316 for (current = FirstHeader; current != NULL; current = current->getNext()) {
317 if (current == hi) {
318 header_info *deadHead = current;
319
320 // Remove from the linked list.
321 if (prev)
322 prev->setNext(current->getNext());
323 else
324 FirstHeader = current->getNext(); // no prev so removing head
2bfd4448
A
325
326 // Update LastHeader if necessary.
327 if (LastHeader == deadHead) {
328 LastHeader = NULL; // will be recomputed next time it's used
329 }
2bfd4448 330 break;
390d5862 331 }
c1e772c4 332 prev = current;
390d5862 333 }
1807f628
A
334
335#if __OBJC2__
336 if ((hi->mhdr()->flags & MH_DYLIB_IN_CACHE) == 0) {
337 foreach_data_segment(hi->mhdr(), [](const segmentType *seg, intptr_t slide) {
338 uintptr_t start = (uintptr_t)seg->vmaddr + slide;
339 objc::dataSegmentsRanges.remove(start, start + seg->vmsize);
340 });
341 }
342#endif
390d5862
A
343}
344
34d5b5e8
A
345/***********************************************************************
346* SetPageCountWarning
347* Convert environment variable value to integer value.
348* If the value is valid, set the global PageCountWarning value.
349**********************************************************************/
350void SetPageCountWarning(const char* envvar) {
351 if (envvar) {
352 long result = strtol(envvar, NULL, 10);
353 if (result <= INT_MAX && result >= -1) {
354 int32_t var = (int32_t)result;
355 if (var != 0) { // 0 is not a valid value for the env var
356 objc::PageCountWarning = var;
357 }
358 }
359 }
360}
390d5862 361
13d88034 362/***********************************************************************
7af964d1 363* environ_init
2bfd4448
A
364* Read environment variables that affect the runtime.
365* Also print environment variable help, if requested.
41c8faa5 366**********************************************************************/
cd5f04f5 367void environ_init(void)
7af964d1 368{
7257e56c
A
369 if (issetugid()) {
370 // All environment variables are silently ignored when setuid or setgid
7af964d1 371 // This includes OBJC_HELP and OBJC_PRINT_OPTIONS themselves.
7257e56c 372 return;
b3962a83 373 }
7257e56c 374
34d5b5e8
A
375 // Turn off autorelease LRU coalescing by default for apps linked against
376 // older SDKs. LRU coalescing can reorder releases and certain older apps
377 // are accidentally relying on the ordering.
378 // rdar://problem/63886091
379 if (!dyld_program_sdk_at_least(dyld_fall_2020_os_versions))
380 DisableAutoreleaseCoalescingLRU = true;
381
7257e56c
A
382 bool PrintHelp = false;
383 bool PrintOptions = false;
31875a97 384 bool maybeMallocDebugging = false;
7257e56c
A
385
386 // Scan environ[] directly instead of calling getenv() a lot.
387 // This optimizes the case where none are set.
388 for (char **p = *_NSGetEnviron(); *p != nil; p++) {
31875a97
A
389 if (0 == strncmp(*p, "Malloc", 6) || 0 == strncmp(*p, "DYLD", 4) ||
390 0 == strncmp(*p, "NSZombiesEnabled", 16))
391 {
392 maybeMallocDebugging = true;
393 }
394
7257e56c
A
395 if (0 != strncmp(*p, "OBJC_", 5)) continue;
396
397 if (0 == strncmp(*p, "OBJC_HELP=", 10)) {
398 PrintHelp = true;
399 continue;
400 }
401 if (0 == strncmp(*p, "OBJC_PRINT_OPTIONS=", 19)) {
402 PrintOptions = true;
403 continue;
404 }
405
34d5b5e8
A
406 if (0 == strncmp(*p, "OBJC_DEBUG_POOL_DEPTH=", 22)) {
407 SetPageCountWarning(*p + 22);
408 continue;
409 }
410
7257e56c
A
411 const char *value = strchr(*p, '=');
412 if (!*value) continue;
413 value++;
414
415 for (size_t i = 0; i < sizeof(Settings)/sizeof(Settings[0]); i++) {
416 const option_t *opt = &Settings[i];
417 if ((size_t)(value - *p) == 1+opt->envlen &&
418 0 == strncmp(*p, opt->env, opt->envlen))
419 {
420 *opt->var = (0 == strcmp(value, "YES"));
421 break;
422 }
34d5b5e8 423 }
7257e56c
A
424 }
425
34d5b5e8 426 // Special case: enable some autorelease pool debugging
31875a97
A
427 // when some malloc debugging is enabled
428 // and OBJC_DEBUG_POOL_ALLOCATION is not set to something other than NO.
429 if (maybeMallocDebugging) {
430 const char *insert = getenv("DYLD_INSERT_LIBRARIES");
431 const char *zombie = getenv("NSZombiesEnabled");
432 const char *pooldebug = getenv("OBJC_DEBUG_POOL_ALLOCATION");
433 if ((getenv("MallocStackLogging")
434 || getenv("MallocStackLoggingNoCompact")
435 || (zombie && (*zombie == 'Y' || *zombie == 'y'))
436 || (insert && strstr(insert, "libgmalloc")))
437 &&
438 (!pooldebug || 0 == strcmp(pooldebug, "YES")))
439 {
440 DebugPoolAllocation = true;
441 }
442 }
443
34d5b5e8
A
444 if (!os_feature_enabled_simple(objc4, preoptimizedCaches, true)) {
445 DisablePreoptCaches = true;
446 }
447
7257e56c
A
448 // Print OBJC_HELP and OBJC_PRINT_OPTIONS output.
449 if (PrintHelp || PrintOptions) {
b3962a83 450 if (PrintHelp) {
7af964d1
A
451 _objc_inform("Objective-C runtime debugging. Set variable=YES to enable.");
452 _objc_inform("OBJC_HELP: describe available environment variables");
b3962a83
A
453 if (PrintOptions) {
454 _objc_inform("OBJC_HELP is set");
455 }
456 _objc_inform("OBJC_PRINT_OPTIONS: list which options are set");
457 }
2bfd4448 458 if (PrintOptions) {
b3962a83 459 _objc_inform("OBJC_PRINT_OPTIONS is set");
2bfd4448 460 }
b3962a83 461
7257e56c
A
462 for (size_t i = 0; i < sizeof(Settings)/sizeof(Settings[0]); i++) {
463 const option_t *opt = &Settings[i];
464 if (PrintHelp) _objc_inform("%s: %s", opt->env, opt->help);
465 if (PrintOptions && *opt->var) _objc_inform("%s is set", opt->env);
466 }
467 }
7af964d1
A
468}
469
470
471/***********************************************************************
472* logReplacedMethod
473* OBJC_PRINT_REPLACED_METHODS implementation
474**********************************************************************/
cd5f04f5 475void
7af964d1 476logReplacedMethod(const char *className, SEL s,
31875a97 477 bool isMeta, const char *catName,
7af964d1
A
478 IMP oldImp, IMP newImp)
479{
480 const char *oldImage = "??";
481 const char *newImage = "??";
482
483 // Silently ignore +load replacement because category +load is special
1807f628 484 if (s == @selector(load)) return;
7af964d1
A
485
486#if TARGET_OS_WIN32
487 // don't know dladdr()/dli_fname equivalent
488#else
489 Dl_info dl;
490
cd5f04f5
A
491 if (dladdr((void*)oldImp, &dl) && dl.dli_fname) oldImage = dl.dli_fname;
492 if (dladdr((void*)newImp, &dl) && dl.dli_fname) newImage = dl.dli_fname;
7af964d1
A
493#endif
494
495 _objc_inform("REPLACED: %c[%s %s] %s%s (IMP was %p (%s), now %p (%s))",
496 isMeta ? '+' : '-', className, sel_getName(s),
497 catName ? "by category " : "", catName ? catName : "",
498 oldImp, oldImage, newImp, newImage);
41c8faa5 499}
2bfd4448
A
500
501
b3962a83
A
502/***********************************************************************
503* _objc_fetch_pthread_data
504* Fetch objc's pthread data for this thread.
505* If the data doesn't exist yet and create is NO, return NULL.
506* If the data doesn't exist yet and create is YES, allocate and return it.
507**********************************************************************/
31875a97 508_objc_pthread_data *_objc_fetch_pthread_data(bool create)
b3962a83
A
509{
510 _objc_pthread_data *data;
511
cd5f04f5 512 data = (_objc_pthread_data *)tls_get(_objc_pthread_key);
b3962a83 513 if (!data && create) {
cd5f04f5 514 data = (_objc_pthread_data *)
31875a97 515 calloc(1, sizeof(_objc_pthread_data));
7af964d1 516 tls_set(_objc_pthread_key, data);
b3962a83
A
517 }
518
519 return data;
520}
521
1f20c7a7
A
522
523/***********************************************************************
524* _objc_pthread_destroyspecific
525* Destructor for objc's per-thread data.
526* arg shouldn't be NULL, but we check anyway.
527**********************************************************************/
528extern void _destroyInitializingClassList(struct _objc_initializing_classes *list);
cd5f04f5 529void _objc_pthread_destroyspecific(void *arg)
1f20c7a7
A
530{
531 _objc_pthread_data *data = (_objc_pthread_data *)arg;
532 if (data != NULL) {
533 _destroyInitializingClassList(data->initializingClasses);
b3962a83
A
534 _destroySyncCache(data->syncCache);
535 _destroyAltHandlerList(data->handlerList);
8070259c
A
536 for (int i = 0; i < (int)countof(data->printableNames); i++) {
537 if (data->printableNames[i]) {
538 free(data->printableNames[i]);
539 }
540 }
13ba007e 541 free(data->classNameLookups);
1f20c7a7
A
542
543 // add further cleanup here...
544
31875a97 545 free(data);
b3962a83
A
546 }
547}
548
549
cd5f04f5 550void tls_init(void)
b3962a83 551{
8972963c 552#if SUPPORT_DIRECT_THREAD_KEYS
7af964d1 553 pthread_key_init_np(TLS_DIRECT_KEY, &_objc_pthread_destroyspecific);
8972963c
A
554#else
555 _objc_pthread_key = tls_create(&_objc_pthread_destroyspecific);
b3962a83 556#endif
2bfd4448
A
557}
558
13d88034 559
2bfd4448 560/***********************************************************************
7af964d1
A
561* _objcInit
562* Former library initializer. This function is now merely a placeholder
563* for external callers. All runtime initialization has now been moved
564* to map_images() and _objc_init.
41c8faa5 565**********************************************************************/
7af964d1 566void _objcInit(void)
2bfd4448 567{
7af964d1 568 // do nothing
13d88034 569}
13d88034 570
2bfd4448 571
13d88034 572/***********************************************************************
8070259c 573* objc_setForwardHandler
41c8faa5 574**********************************************************************/
390d5862 575
8070259c
A
576#if !__OBJC2__
577
578// Default forward handler (nil) goes to forward:: dispatch.
579void *_objc_forward_handler = nil;
580void *_objc_forward_stret_handler = nil;
390d5862 581
8070259c
A
582#else
583
584// Default forward handler halts the process.
1807f628 585__attribute__((noreturn, cold)) void
8070259c
A
586objc_defaultForwardHandler(id self, SEL sel)
587{
588 _objc_fatal("%c[%s %s]: unrecognized selector sent to instance %p "
589 "(no message forward handler is installed)",
590 class_isMetaClass(object_getClass(self)) ? '+' : '-',
591 object_getClassName(self), sel_getName(sel), self);
13d88034 592}
8070259c 593void *_objc_forward_handler = (void*)objc_defaultForwardHandler;
13d88034 594
8070259c
A
595#if SUPPORT_STRET
596struct stret { int i[100]; };
1807f628 597__attribute__((noreturn, cold)) struct stret
8070259c 598objc_defaultForwardStretHandler(id self, SEL sel)
13d88034 599{
8070259c 600 objc_defaultForwardHandler(self, sel);
13d88034 601}
8070259c 602void *_objc_forward_stret_handler = (void*)objc_defaultForwardStretHandler;
7af964d1 603#endif
13d88034 604
8070259c 605#endif
13d88034 606
b3962a83
A
607void objc_setForwardHandler(void *fwd, void *fwd_stret)
608{
609 _objc_forward_handler = fwd;
8070259c 610#if SUPPORT_STRET
b3962a83 611 _objc_forward_stret_handler = fwd_stret;
8070259c 612#endif
b3962a83
A
613}
614
615
b3962a83
A
616#if !__OBJC2__
617// GrP fixme
7257e56c 618extern "C" Class _objc_getOrigClass(const char *name);
b3962a83 619#endif
b3962a83 620
66799735
A
621static BOOL internal_class_getImageName(Class cls, const char **outName)
622{
b3962a83 623#if !__OBJC2__
8070259c 624 cls = _objc_getOrigClass(cls->demangledName());
b3962a83 625#endif
66799735
A
626 auto result = dyld_image_path_containing_address(cls);
627 *outName = result;
628 return (result != nil);
b3962a83
A
629}
630
631
66799735
A
632static ChainedHookFunction<objc_hook_getImageName>
633GetImageNameHook{internal_class_getImageName};
b3962a83 634
66799735
A
635void objc_setHook_getImageName(objc_hook_getImageName newValue,
636 objc_hook_getImageName *outOldValue)
637{
638 GetImageNameHook.set(newValue, outOldValue);
b3962a83
A
639}
640
66799735 641const char *class_getImageName(Class cls)
b3962a83 642{
66799735 643 if (!cls) return nil;
b3962a83 644
66799735
A
645 const char *name;
646 if (GetImageNameHook.get()(cls, &name)) return name;
647 else return nil;
b3962a83 648}
66799735 649
b3962a83
A
650
651/**********************************************************************
652* Fast Enumeration Support
653**********************************************************************/
654
655static void (*enumerationMutationHandler)(id);
656
657/**********************************************************************
658* objc_enumerationMutation
659* called by compiler when a mutation is detected during foreach iteration
660**********************************************************************/
661void objc_enumerationMutation(id object) {
662 if (enumerationMutationHandler == nil) {
7257e56c 663 _objc_fatal("mutation detected during 'for(... in ...)' enumeration of object %p.", (void*)object);
b3962a83
A
664 }
665 (*enumerationMutationHandler)(object);
666}
667
668
669/**********************************************************************
670* objc_setEnumerationMutationHandler
671* an entry point to customize mutation error handing
672**********************************************************************/
673void objc_setEnumerationMutationHandler(void (*handler)(id)) {
674 enumerationMutationHandler = handler;
675}
7af964d1
A
676
677
8972963c
A
678/**********************************************************************
679* Associative Reference Support
680**********************************************************************/
681
1807f628
A
682id
683objc_getAssociatedObject(id object, const void *key)
684{
685 return _object_get_associative_reference(object, key);
686}
687
34d5b5e8
A
688typedef void (*objc_hook_setAssociatedObject)(id _Nonnull object, const void * _Nonnull key,
689 id _Nullable value, objc_AssociationPolicy policy);
7257e56c 690
1807f628
A
691void
692objc_setHook_setAssociatedObject(objc_hook_setAssociatedObject _Nonnull newValue,
693 objc_hook_setAssociatedObject _Nullable * _Nonnull outOldValue) {
34d5b5e8 694 // See objc_object::setHasAssociatedObjects() for a replacement
1807f628
A
695}
696
697void
698objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
699{
34d5b5e8 700 _object_set_associative_reference(object, key, value, policy);
8972963c
A
701}
702
c1e772c4
A
703void objc_removeAssociatedObjects(id object)
704{
705 if (object && object->hasAssociatedObjects()) {
34d5b5e8 706 _object_remove_assocations(object, /*deallocating*/false);
c1e772c4
A
707 }
708}
7257e56c 709
31875a97 710
7257e56c 711
c1e772c4
A
712#if SUPPORT_GC_COMPAT
713
714#include <mach-o/fat.h>
715
716// GC preflight for an app executable.
717
718enum GCness {
719 WithGC = 1,
720 WithoutGC = 0,
721 Error = -1
722};
723
724// Overloaded template wrappers around clang's overflow-checked arithmetic.
725
726template <typename T> bool uadd_overflow(T x, T y, T* sum);
727template <typename T> bool usub_overflow(T x, T y, T* diff);
728template <typename T> bool umul_overflow(T x, T y, T* prod);
729
730template <typename T> bool sadd_overflow(T x, T y, T* sum);
731template <typename T> bool ssub_overflow(T x, T y, T* diff);
732template <typename T> bool smul_overflow(T x, T y, T* prod);
733
734template <> bool uadd_overflow(unsigned x, unsigned y, unsigned* sum) { return __builtin_uadd_overflow(x, y, sum); }
735template <> bool uadd_overflow(unsigned long x, unsigned long y, unsigned long* sum) { return __builtin_uaddl_overflow(x, y, sum); }
736template <> bool uadd_overflow(unsigned long long x, unsigned long long y, unsigned long long* sum) { return __builtin_uaddll_overflow(x, y, sum); }
737
738template <> bool usub_overflow(unsigned x, unsigned y, unsigned* diff) { return __builtin_usub_overflow(x, y, diff); }
739template <> bool usub_overflow(unsigned long x, unsigned long y, unsigned long* diff) { return __builtin_usubl_overflow(x, y, diff); }
740template <> bool usub_overflow(unsigned long long x, unsigned long long y, unsigned long long* diff) { return __builtin_usubll_overflow(x, y, diff); }
741
742template <> bool umul_overflow(unsigned x, unsigned y, unsigned* prod) { return __builtin_umul_overflow(x, y, prod); }
743template <> bool umul_overflow(unsigned long x, unsigned long y, unsigned long* prod) { return __builtin_umull_overflow(x, y, prod); }
744template <> bool umul_overflow(unsigned long long x, unsigned long long y, unsigned long long* prod) { return __builtin_umulll_overflow(x, y, prod); }
745
746template <> bool sadd_overflow(signed x, signed y, signed* sum) { return __builtin_sadd_overflow(x, y, sum); }
747template <> bool sadd_overflow(signed long x, signed long y, signed long* sum) { return __builtin_saddl_overflow(x, y, sum); }
748template <> bool sadd_overflow(signed long long x, signed long long y, signed long long* sum) { return __builtin_saddll_overflow(x, y, sum); }
749
750template <> bool ssub_overflow(signed x, signed y, signed* diff) { return __builtin_ssub_overflow(x, y, diff); }
751template <> bool ssub_overflow(signed long x, signed long y, signed long* diff) { return __builtin_ssubl_overflow(x, y, diff); }
752template <> bool ssub_overflow(signed long long x, signed long long y, signed long long* diff) { return __builtin_ssubll_overflow(x, y, diff); }
753
754template <> bool smul_overflow(signed x, signed y, signed* prod) { return __builtin_smul_overflow(x, y, prod); }
755template <> bool smul_overflow(signed long x, signed long y, signed long* prod) { return __builtin_smull_overflow(x, y, prod); }
756template <> bool smul_overflow(signed long long x, signed long long y, signed long long* prod) { return __builtin_smulll_overflow(x, y, prod); }
757
758
759// Range-checking subview of a file.
760class FileSlice {
761 int fd;
762 uint64_t sliceOffset;
763 uint64_t sliceSize;
764
765public:
766 FileSlice() : fd(-1), sliceOffset(0), sliceSize(0) { }
767
768 FileSlice(int newfd, uint64_t newOffset, uint64_t newSize)
769 : fd(newfd) , sliceOffset(newOffset) , sliceSize(newSize) { }
770
771 // Read bytes from this slice.
772 // Returns YES if all bytes were read successfully.
773 bool pread(void *buf, uint64_t readSize, uint64_t readOffset = 0) {
774 uint64_t readEnd;
775 if (uadd_overflow(readOffset, readSize, &readEnd)) return NO;
776 if (readEnd > sliceSize) return NO;
31875a97 777
c1e772c4
A
778 uint64_t preadOffset;
779 if (uadd_overflow(sliceOffset, readOffset, &preadOffset)) return NO;
780
781 int64_t readed = ::pread(fd, buf, (size_t)readSize, preadOffset);
782 if (readed < 0 || (uint64_t)readed != readSize) return NO;
783 return YES;
8972963c 784 }
8972963c 785
c1e772c4
A
786 // Create a new slice that is a subset of this slice.
787 // Returnes YES if successful.
788 bool slice(uint64_t newOffset, uint64_t newSize, FileSlice& result) {
789 // fixme arithmetic overflow
790 uint64_t newEnd;
791 if (uadd_overflow(newOffset, newSize, &newEnd)) return NO;
792 if (newEnd > sliceSize) return NO;
7257e56c 793
c1e772c4
A
794 if (uadd_overflow(sliceOffset, newOffset, &result.sliceOffset)) {
795 return NO;
796 }
797 result.sliceSize = newSize;
798 result.fd = fd;
799 return YES;
800 }
801
802 // Shorten this slice in place by removing a range from the start.
803 bool advance(uint64_t distance) {
804 if (distance > sliceSize) return NO;
805 if (uadd_overflow(sliceOffset, distance, &sliceOffset)) return NO;
806 if (usub_overflow(sliceSize, distance, &sliceSize)) return NO;
807 return YES;
808 }
809};
810
811
812// Arch32 and Arch64 are used to specialize sliceRequiresGC()
813// to interrogate old-ABI i386 and new-ABI x86_64 files.
814
815struct Arch32 {
816 using mh_t = struct mach_header;
817 using segment_command_t = struct segment_command;
818 using section_t = struct section;
819
820 enum : cpu_type_t { cputype = CPU_TYPE_X86 };
821 enum : int { segment_cmd = LC_SEGMENT };
822
823 static bool isObjCSegment(const char *segname) {
824 return segnameEquals(segname, "__OBJC");
825 }
826
827 static bool isImageInfoSection(const char *sectname) {
828 return sectnameEquals(sectname, "__image_info");
829 }
830
831 static bool countClasses(FileSlice file, section_t& sect,
832 int& classCount, int& classrefCount)
833 {
834 if (sectnameEquals(sect.sectname, "__cls_refs")) {
835 classrefCount += sect.size / 4;
836 }
837 else if (sectnameEquals(sect.sectname, "__module_info")) {
838 struct module_t {
839 uint32_t version;
840 uint32_t size;
841 uint32_t name; // not bound
842 uint32_t symtab; // not bound
843 };
844 size_t mod_count = sect.size / sizeof(module_t);
845 if (mod_count == 0) {
846 // no classes defined
847 } else if (mod_count > 1) {
848 // AppleScriptObjC apps only have one module.
849 // Disqualify this app by setting classCount to non-zero.
850 // We don't actually need an accurate count.
851 classCount = 1;
852 } else if (mod_count == 1) {
853 FileSlice moduleSlice;
854 if (!file.slice(sect.offset, sect.size, moduleSlice)) return NO;
855 module_t module;
856 if (!moduleSlice.pread(&module, sizeof(module))) return NO;
857 if (module.symtab) {
858 // AppleScriptObjC apps only have a module with no symtab.
859 // Disqualify this app by setting classCount to non-zero.
860 // We don't actually need an accurate count.
861 classCount = 1;
862 }
863 }
864
865 }
866 return YES;
867 }
868
869};
7257e56c 870
c1e772c4
A
871struct Arch64 {
872 using mh_t = struct mach_header_64;
873 using segment_command_t = struct segment_command_64;
874 using section_t = struct section_64;
875
876 enum : cpu_type_t { cputype = CPU_TYPE_X86_64 };
877 enum : int { segment_cmd = LC_SEGMENT_64 };
878
879 static bool isObjCSegment(const char *segname) {
880 return
881 segnameEquals(segname, "__DATA") ||
882 segnameEquals(segname, "__DATA_CONST") ||
883 segnameEquals(segname, "__DATA_DIRTY");
884 }
885
886 static bool isImageInfoSection(const char *sectname) {
887 return sectnameEquals(sectname, "__objc_imageinfo");
888 }
889
890 static bool countClasses(FileSlice, section_t& sect,
891 int& classCount, int& classrefCount)
892 {
893 if (sectnameEquals(sect.sectname, "__objc_classlist")) {
894 classCount += sect.size / 8;
895 }
896 else if (sectnameEquals(sect.sectname, "__objc_classrefs")) {
897 classrefCount += sect.size / 8;
898 }
899 return YES;
900 }
901};
902
903
904#define SANE_HEADER_SIZE (32*1024)
905
906template <typename Arch>
907static int sliceRequiresGC(typename Arch::mh_t mh, FileSlice file)
7257e56c 908{
c1e772c4
A
909 // We assume there is only one arch per pointer size that can support GC.
910 // (i386 and x86_64)
911 if (mh.cputype != Arch::cputype) return 0;
912
913 // We only check the main executable.
914 if (mh.filetype != MH_EXECUTE) return 0;
915
916 // Look for ObjC segment.
917 // Look for AppleScriptObjC linkage.
918 FileSlice cmds;
919 if (!file.slice(sizeof(mh), mh.sizeofcmds, cmds)) return Error;
920
921 // Exception: Some AppleScriptObjC apps built for GC can run without GC.
922 // 1. executable defines no classes
923 // 2. executable references NSBundle only
924 // 3. executable links to AppleScriptObjC.framework
925 // Note that shouldRejectGCApp() also knows about this.
926 bool wantsGC = NO;
927 bool linksToAppleScriptObjC = NO;
928 int classCount = 0;
929 int classrefCount = 0;
930
931 // Disallow abusively-large executables that could hang this checker.
932 // dyld performs similar checks (MAX_MACH_O_HEADER_AND_LOAD_COMMANDS_SIZE)
933 if (mh.sizeofcmds > SANE_HEADER_SIZE) return Error;
934 if (mh.ncmds > mh.sizeofcmds / sizeof(struct load_command)) return Error;
935
936 for (uint32_t cmdindex = 0; cmdindex < mh.ncmds; cmdindex++) {
937 struct load_command lc;
938 if (!cmds.pread(&lc, sizeof(lc))) return Error;
939
940 // Disallow abusively-small load commands that could hang this checker.
941 // dyld performs a similar check.
942 if (lc.cmdsize < sizeof(lc)) return Error;
943
944 if (lc.cmd == LC_LOAD_DYLIB || lc.cmd == LC_LOAD_UPWARD_DYLIB ||
945 lc.cmd == LC_LOAD_WEAK_DYLIB || lc.cmd == LC_REEXPORT_DYLIB)
946 {
947 // Look for AppleScriptObjC linkage.
948 FileSlice dylibSlice;
949 if (!cmds.slice(0, lc.cmdsize, dylibSlice)) return Error;
950 struct dylib_command dylib;
951 if (!dylibSlice.pread(&dylib, sizeof(dylib))) return Error;
952
953 const char *asoFramework =
954 "/System/Library/Frameworks/AppleScriptObjC.framework"
955 "/Versions/A/AppleScriptObjC";
956 size_t asoLen = strlen(asoFramework);
957
958 FileSlice nameSlice;
959 if (dylibSlice.slice(dylib.dylib.name.offset, asoLen, nameSlice)) {
960 char name[asoLen];
961 if (!nameSlice.pread(name, asoLen)) return Error;
962 if (0 == memcmp(name, asoFramework, asoLen)) {
963 linksToAppleScriptObjC = YES;
964 }
965 }
966 }
967 else if (lc.cmd == Arch::segment_cmd) {
968 typename Arch::segment_command_t seg;
969 if (!cmds.pread(&seg, sizeof(seg))) return Error;
970
971 if (Arch::isObjCSegment(seg.segname)) {
972 // ObjC segment.
973 // Look for image info section.
974 // Look for class implementations and class references.
975 FileSlice sections;
976 if (!cmds.slice(0, seg.cmdsize, sections)) return Error;
977 if (!sections.advance(sizeof(seg))) return Error;
978
979 for (uint32_t segindex = 0; segindex < seg.nsects; segindex++) {
980 typename Arch::section_t sect;
981 if (!sections.pread(&sect, sizeof(sect))) return Error;
982 if (!Arch::isObjCSegment(sect.segname)) return Error;
983
984 if (!Arch::countClasses(file, sect,
985 classCount, classrefCount))
986 {
987 return Error;
988 }
989
990 if ((sect.flags & SECTION_TYPE) == S_REGULAR &&
991 Arch::isImageInfoSection(sect.sectname))
992 {
993 // ObjC image info section.
994 // Check its contents.
995 FileSlice section;
996 if (!file.slice(sect.offset, sect.size, section)) {
997 return Error;
998 }
999 // The subset of objc_image_info that was in use for GC.
1000 struct {
1001 uint32_t version;
1002 uint32_t flags;
1003 } ii;
1004 if (!section.pread(&ii, sizeof(ii))) return Error;
1005 if (ii.flags & (1<<1)) {
1006 // App wants GC.
1007 // Don't return yet because we need to
1008 // check the AppleScriptObjC exception.
1009 wantsGC = YES;
1010 }
1011 }
1012
1013 if (!sections.advance(sizeof(sect))) return Error;
1014 }
1015 }
1016 }
1017
1018 if (!cmds.advance(lc.cmdsize)) return Error;
1019 }
1020
1021 if (!wantsGC) {
1022 // No GC bit set.
1023 return WithoutGC;
1024 }
1025 else if (linksToAppleScriptObjC && classCount == 0 && classrefCount == 1) {
1026 // Has GC bit but falls under the AppleScriptObjC exception.
1027 return WithoutGC;
1028 }
1029 else {
1030 // Has GC bit and is not AppleScriptObjC.
1031 return WithGC;
1032 }
8972963c
A
1033}
1034
c1e772c4
A
1035
1036static int sliceRequiresGC(FileSlice file)
7257e56c 1037{
c1e772c4
A
1038 // Read mach-o header.
1039 struct mach_header_64 mh;
1040 if (!file.pread(&mh, sizeof(mh))) return Error;
1041
1042 // Check header magic. We assume only host-endian slices can support GC.
1043 switch (mh.magic) {
1044 case MH_MAGIC:
1045 return sliceRequiresGC<Arch32>(*(struct mach_header *)&mh, file);
1046 case MH_MAGIC_64:
1047 return sliceRequiresGC<Arch64>(mh, file);
1048 default:
1049 return WithoutGC;
1050 }
8972963c
A
1051}
1052
7257e56c 1053
c1e772c4
A
1054// Returns 1 if any slice requires GC.
1055// Returns 0 if no slice requires GC.
1056// Returns -1 on any I/O or file format error.
1057int objc_appRequiresGC(int fd)
7257e56c 1058{
c1e772c4
A
1059 struct stat st;
1060 if (fstat(fd, &st) < 0) return Error;
1061
1062 FileSlice file(fd, 0, st.st_size);
1063
1064 // Read fat header, if any.
1065 struct fat_header fh;
1066
1067 if (! file.pread(&fh, sizeof(fh))) return Error;
1068
1069 int result;
1070
1071 if (OSSwapBigToHostInt32(fh.magic) == FAT_MAGIC) {
1072 // Fat header.
1073
1074 size_t nfat_arch = OSSwapBigToHostInt32(fh.nfat_arch);
1075 // Disallow abusively-large files that could hang this checker.
1076 if (nfat_arch > SANE_HEADER_SIZE/sizeof(struct fat_arch)) return Error;
1077
1078 size_t fat_size;
1079 if (umul_overflow(nfat_arch, sizeof(struct fat_arch), &fat_size)) {
1080 return Error;
1081 }
1082
1083 FileSlice archlist;
1084 if (!file.slice(sizeof(fh), fat_size, archlist)) return Error;
1085
1086 result = WithoutGC;
1087 for (size_t i = 0; i < nfat_arch; i++) {
1088 struct fat_arch fa;
1089 if (!archlist.pread(&fa, sizeof(fa))) return Error;
1090 if (!archlist.advance(sizeof(fa))) return Error;
1091
1092 FileSlice thin;
1093 if (!file.slice(OSSwapBigToHostInt32(fa.offset),
1094 OSSwapBigToHostInt32(fa.size), thin))
1095 {
1096 return Error;
1097 }
1098 switch (sliceRequiresGC(thin)) {
1099 case WithoutGC: break; // no change
1100 case WithGC: if (result != Error) result = WithGC; break;
1101 case Error: result = Error; break;
1102 }
7af964d1
A
1103 }
1104 }
c1e772c4
A
1105 else {
1106 // Thin header or not a header.
1107 result = sliceRequiresGC(file);
1108 }
1109
1110 return result;
7af964d1
A
1111}
1112
c1e772c4
A
1113// SUPPORT_GC_COMPAT
1114#endif