2  * Copyright (c) 1999-2007 Apple Inc.  All Rights Reserved.
 
   4  * @APPLE_LICENSE_HEADER_START@
 
   6  * This file contains Original Code and/or Modifications of Original Code
 
   7  * as defined in and that are subject to the Apple Public Source License
 
   8  * Version 2.0 (the 'License'). You may not use this file except in
 
   9  * compliance with the License. Please obtain a copy of the License at
 
  10  * http://www.opensource.apple.com/apsl/ and read it before using this
 
  13  * The Original Code and all software distributed under the License are
 
  14  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 
  15  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 
  16  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 
  17  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 
  18  * Please see the License for the specific language governing rights and
 
  19  * limitations under the License.
 
  21  * @APPLE_LICENSE_HEADER_END@
 
  23 /***********************************************************************
 
  25 * Copyright 1988-1996, NeXT Software, Inc.
 
  28 **********************************************************************/
 
  32 /***********************************************************************
 
  34 **********************************************************************/
 
  36 #include <os/feature_private.h> // os_feature_enabled_simple()
 
  37 #include "objc-private.h"
 
  38 #include "objc-loadmethod.h"
 
  39 #include "objc-file.h"
 
  42 /***********************************************************************
 
  44 **********************************************************************/
 
  46 /* Linker metadata symbols */
 
  48 // NSObject was in Foundation/CF on macOS < 10.8.
 
  52 const char __objc_nsobject_class_10_5 = 0;
 
  53 const char __objc_nsobject_class_10_6 = 0;
 
  54 const char __objc_nsobject_class_10_7 = 0;
 
  56 const char __objc_nsobject_metaclass_10_5 = 0;
 
  57 const char __objc_nsobject_metaclass_10_6 = 0;
 
  58 const char __objc_nsobject_metaclass_10_7 = 0;
 
  60 const char __objc_nsobject_isa_10_5 = 0;
 
  61 const char __objc_nsobject_isa_10_6 = 0;
 
  62 const char __objc_nsobject_isa_10_7 = 0;
 
  66 const char __objc_nsobject_class_10_5 = 0;
 
  67 const char __objc_nsobject_class_10_6 = 0;
 
  68 const char __objc_nsobject_class_10_7 = 0;
 
  73 // Settings from environment variables
 
  74 #define OPTION(var, env, help) bool var = false;
 
  85 const option_t Settings[] = {
 
  86 #define OPTION(var, env, help) option_t{&var, #env, help, strlen(#env)}, 
 
  92     int PageCountWarning = 50;  // Default value if the environment variable is not set
 
  95 // objc's key for pthread_getspecific
 
  96 #if SUPPORT_DIRECT_THREAD_KEYS
 
  97 #define _objc_pthread_key TLS_DIRECT_KEY
 
  99 static tls_key_t _objc_pthread_key;
 
 103 SEL SEL_cxx_construct = NULL;
 
 104 SEL SEL_cxx_destruct = NULL;
 
 106 struct objc::SafeRanges objc::dataSegmentsRanges;
 
 107 header_info *FirstHeader = 0;  // NULL means empty list
 
 108 header_info *LastHeader  = 0;  // NULL means invalid; recompute it
 
 110 // Set to true on the child side of fork() 
 
 111 // if the parent process was multithreaded when fork() was called.
 
 112 bool MultithreadedForkChild = false;
 
 115 /***********************************************************************
 
 116 * objc_noop_imp. Used when we need to install a do-nothing method somewhere.
 
 117 **********************************************************************/
 
 118 id objc_noop_imp(id self, SEL _cmd __unused) {
 
 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.
 
 134 #if OBJC_IS_DEBUG_BUILD
 
 135 void _objc_isDebugBuild(void) { }
 
 139 /***********************************************************************
 
 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!
 
 144 **********************************************************************/
 
 145 Class objc_getClass(const char *aClassName)
 
 147     if (!aClassName) return Nil;
 
 149     // NO unconnected, YES class handler
 
 150     return look_up_class(aClassName, NO, YES);
 
 154 /***********************************************************************
 
 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.
 
 159 **********************************************************************/
 
 160 Class objc_getRequiredClass(const char *aClassName)
 
 162     Class cls = objc_getClass(aClassName);
 
 163     if (!cls) _objc_fatal("link error: class '%s' not found.", aClassName);
 
 168 /***********************************************************************
 
 169 * objc_lookUpClass.  Return the id of the named class.
 
 170 * If the class does not exist, call _objc_classLoader, which may create 
 
 173 * Formerly objc_getClassWithoutWarning ()
 
 174 **********************************************************************/
 
 175 Class objc_lookUpClass(const char *aClassName)
 
 177     if (!aClassName) return Nil;
 
 179     // NO unconnected, NO class handler
 
 180     return look_up_class(aClassName, NO, NO);
 
 184 /***********************************************************************
 
 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!
 
 187 **********************************************************************/
 
 188 Class objc_getMetaClass(const char *aClassName)
 
 192     if (!aClassName) return Nil;
 
 194     cls = objc_getClass (aClassName);
 
 197         _objc_inform ("class `%s' not linked into application", aClassName);
 
 204 /***********************************************************************
 
 205  * objc::SafeRanges::find.  Find an image data segment that contains address
 
 206  **********************************************************************/
 
 208 objc::SafeRanges::find(uintptr_t ptr, uint32_t &pos)
 
 211         std::sort(ranges, ranges + count, [](const Range &s1, const Range &s2){
 
 212             return s1.start < s2.start;
 
 217     uint32_t l = 0, r = count;
 
 219         uint32_t i = (l + r) / 2;
 
 221         if (ptr < ranges[i].start) {
 
 223         } else if (ptr >= ranges[i].end) {
 
 235 /***********************************************************************
 
 236  * objc::SafeRanges::add.  Register a new well known data segment.
 
 237  **********************************************************************/
 
 239 objc::SafeRanges::add(uintptr_t start, uintptr_t end)
 
 242         // Have a typical malloc growth:
 
 243         // - size <= 32:  grow by  4
 
 244         // - size <= 64:  grow by  8
 
 245         // - size <= 128: grow by 16
 
 247         size += size < 16 ? 4 : 1 << (fls(size) - 3);
 
 248         ranges = (Range *)realloc(ranges, sizeof(Range) * size);
 
 250     ranges[count++] = Range{ start, end };
 
 254 /***********************************************************************
 
 255  * objc::SafeRanges::remove.  Remove a previously known data segment.
 
 256  **********************************************************************/
 
 258 objc::SafeRanges::remove(uintptr_t start, uintptr_t end)
 
 262     if (!find(start, pos) || ranges[pos].end != end) {
 
 263         _objc_fatal("Cannot find range %#lx..%#lx", start, end);
 
 266         ranges[pos] = ranges[count];
 
 271 /***********************************************************************
 
 272 * appendHeader.  Add a newly-constructed header_info to the list. 
 
 273 **********************************************************************/
 
 274 void appendHeader(header_info *hi)
 
 276     // Add the header to the header list. 
 
 277     // The header is appended to the list, to preserve the bottom-up order.
 
 281         FirstHeader = LastHeader = hi;
 
 284             // list is not empty, but LastHeader is invalid - recompute it
 
 285             LastHeader = FirstHeader;
 
 286             while (LastHeader->getNext()) LastHeader = LastHeader->getNext();
 
 288         // LastHeader is now valid
 
 289         LastHeader->setNext(hi);
 
 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);
 
 304 /***********************************************************************
 
 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.
 
 310 **********************************************************************/
 
 311 void removeHeader(header_info *hi)
 
 313     header_info *prev = NULL;
 
 314     header_info *current = NULL;
 
 316     for (current = FirstHeader; current != NULL; current = current->getNext()) {
 
 318             header_info *deadHead = current;
 
 320             // Remove from the linked list.
 
 322                 prev->setNext(current->getNext());
 
 324                 FirstHeader = current->getNext(); // no prev so removing head
 
 326             // Update LastHeader if necessary.
 
 327             if (LastHeader == deadHead) {
 
 328                 LastHeader = NULL;  // will be recomputed next time it's used
 
 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);
 
 345 /***********************************************************************
 
 346 * SetPageCountWarning
 
 347 * Convert environment variable value to integer value.
 
 348 * If the value is valid, set the global PageCountWarning value.
 
 349 **********************************************************************/
 
 350 void SetPageCountWarning(const char* 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;
 
 362 /***********************************************************************
 
 364 * Read environment variables that affect the runtime.
 
 365 * Also print environment variable help, if requested.
 
 366 **********************************************************************/
 
 367 void environ_init(void) 
 
 370         // All environment variables are silently ignored when setuid or setgid
 
 371         // This includes OBJC_HELP and OBJC_PRINT_OPTIONS themselves.
 
 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;
 
 382     bool PrintHelp = false;
 
 383     bool PrintOptions = false;
 
 384     bool maybeMallocDebugging = false;
 
 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++) {
 
 389         if (0 == strncmp(*p, "Malloc", 6)  ||  0 == strncmp(*p, "DYLD", 4)  ||  
 
 390             0 == strncmp(*p, "NSZombiesEnabled", 16))
 
 392             maybeMallocDebugging = true;
 
 395         if (0 != strncmp(*p, "OBJC_", 5)) continue;
 
 397         if (0 == strncmp(*p, "OBJC_HELP=", 10)) {
 
 401         if (0 == strncmp(*p, "OBJC_PRINT_OPTIONS=", 19)) {
 
 406         if (0 == strncmp(*p, "OBJC_DEBUG_POOL_DEPTH=", 22)) {
 
 407             SetPageCountWarning(*p + 22);
 
 411         const char *value = strchr(*p, '=');
 
 412         if (!*value) continue;
 
 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))
 
 420                 *opt->var = (0 == strcmp(value, "YES"));
 
 426     // Special case: enable some autorelease pool debugging
 
 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")))
 
 438             (!pooldebug || 0 == strcmp(pooldebug, "YES")))
 
 440             DebugPoolAllocation = true;
 
 444     if (!os_feature_enabled_simple(objc4, preoptimizedCaches, true)) {
 
 445         DisablePreoptCaches = true;
 
 448     // Print OBJC_HELP and OBJC_PRINT_OPTIONS output.
 
 449     if (PrintHelp  ||  PrintOptions) {
 
 451             _objc_inform("Objective-C runtime debugging. Set variable=YES to enable.");
 
 452             _objc_inform("OBJC_HELP: describe available environment variables");
 
 454                 _objc_inform("OBJC_HELP is set");
 
 456             _objc_inform("OBJC_PRINT_OPTIONS: list which options are set");
 
 459             _objc_inform("OBJC_PRINT_OPTIONS is set");
 
 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);
 
 471 /***********************************************************************
 
 473 * OBJC_PRINT_REPLACED_METHODS implementation
 
 474 **********************************************************************/
 
 476 logReplacedMethod(const char *className, SEL s, 
 
 477                   bool isMeta, const char *catName, 
 
 478                   IMP oldImp, IMP newImp)
 
 480     const char *oldImage = "??";
 
 481     const char *newImage = "??";
 
 483     // Silently ignore +load replacement because category +load is special
 
 484     if (s == @selector(load)) return;
 
 487     // don't know dladdr()/dli_fname equivalent
 
 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;
 
 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);
 
 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 **********************************************************************/
 
 508 _objc_pthread_data *_objc_fetch_pthread_data(bool create)
 
 510     _objc_pthread_data *data;
 
 512     data = (_objc_pthread_data *)tls_get(_objc_pthread_key);
 
 513     if (!data  &&  create) {
 
 514         data = (_objc_pthread_data *)
 
 515             calloc(1, sizeof(_objc_pthread_data));
 
 516         tls_set(_objc_pthread_key, data);
 
 523 /***********************************************************************
 
 524 * _objc_pthread_destroyspecific
 
 525 * Destructor for objc's per-thread data.
 
 526 * arg shouldn't be NULL, but we check anyway.
 
 527 **********************************************************************/
 
 528 extern void _destroyInitializingClassList(struct _objc_initializing_classes *list);
 
 529 void _objc_pthread_destroyspecific(void *arg)
 
 531     _objc_pthread_data *data = (_objc_pthread_data *)arg;
 
 533         _destroyInitializingClassList(data->initializingClasses);
 
 534         _destroySyncCache(data->syncCache);
 
 535         _destroyAltHandlerList(data->handlerList);
 
 536         for (int i = 0; i < (int)countof(data->printableNames); i++) {
 
 537             if (data->printableNames[i]) {
 
 538                 free(data->printableNames[i]);  
 
 541         free(data->classNameLookups);
 
 543         // add further cleanup here...
 
 552 #if SUPPORT_DIRECT_THREAD_KEYS
 
 553     pthread_key_init_np(TLS_DIRECT_KEY, &_objc_pthread_destroyspecific);
 
 555     _objc_pthread_key = tls_create(&_objc_pthread_destroyspecific);
 
 560 /***********************************************************************
 
 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.
 
 565 **********************************************************************/
 
 572 /***********************************************************************
 
 573 * objc_setForwardHandler
 
 574 **********************************************************************/
 
 578 // Default forward handler (nil) goes to forward:: dispatch.
 
 579 void *_objc_forward_handler = nil;
 
 580 void *_objc_forward_stret_handler = nil;
 
 584 // Default forward handler halts the process.
 
 585 __attribute__((noreturn, cold)) void
 
 586 objc_defaultForwardHandler(id self, SEL sel)
 
 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);
 
 593 void *_objc_forward_handler = (void*)objc_defaultForwardHandler;
 
 596 struct stret { int i[100]; };
 
 597 __attribute__((noreturn, cold)) struct stret
 
 598 objc_defaultForwardStretHandler(id self, SEL sel)
 
 600     objc_defaultForwardHandler(self, sel);
 
 602 void *_objc_forward_stret_handler = (void*)objc_defaultForwardStretHandler;
 
 607 void objc_setForwardHandler(void *fwd, void *fwd_stret)
 
 609     _objc_forward_handler = fwd;
 
 611     _objc_forward_stret_handler = fwd_stret;
 
 618 extern "C" Class _objc_getOrigClass(const char *name);
 
 621 static BOOL internal_class_getImageName(Class cls, const char **outName)
 
 624     cls = _objc_getOrigClass(cls->demangledName());
 
 626     auto result = dyld_image_path_containing_address(cls);
 
 628     return (result != nil);
 
 632 static ChainedHookFunction<objc_hook_getImageName>
 
 633 GetImageNameHook{internal_class_getImageName};
 
 635 void objc_setHook_getImageName(objc_hook_getImageName newValue,
 
 636                                objc_hook_getImageName *outOldValue)
 
 638     GetImageNameHook.set(newValue, outOldValue);
 
 641 const char *class_getImageName(Class cls)
 
 643     if (!cls) return nil;
 
 646     if (GetImageNameHook.get()(cls, &name)) return name;
 
 651 /**********************************************************************
 
 652 * Fast Enumeration Support
 
 653 **********************************************************************/
 
 655 static void (*enumerationMutationHandler)(id);
 
 657 /**********************************************************************
 
 658 * objc_enumerationMutation
 
 659 * called by compiler when a mutation is detected during foreach iteration
 
 660 **********************************************************************/
 
 661 void objc_enumerationMutation(id object) {
 
 662     if (enumerationMutationHandler == nil) {
 
 663         _objc_fatal("mutation detected during 'for(... in ...)'  enumeration of object %p.", (void*)object);
 
 665     (*enumerationMutationHandler)(object);
 
 669 /**********************************************************************
 
 670 * objc_setEnumerationMutationHandler
 
 671 * an entry point to customize mutation error handing
 
 672 **********************************************************************/
 
 673 void objc_setEnumerationMutationHandler(void (*handler)(id)) {
 
 674     enumerationMutationHandler = handler;
 
 678 /**********************************************************************
 
 679 * Associative Reference Support
 
 680 **********************************************************************/
 
 683 objc_getAssociatedObject(id object, const void *key)
 
 685     return _object_get_associative_reference(object, key);
 
 688 typedef void (*objc_hook_setAssociatedObject)(id _Nonnull object, const void * _Nonnull key,
 
 689                                               id _Nullable value, objc_AssociationPolicy policy);
 
 692 objc_setHook_setAssociatedObject(objc_hook_setAssociatedObject _Nonnull newValue,
 
 693                                  objc_hook_setAssociatedObject _Nullable * _Nonnull outOldValue) {
 
 694   // See objc_object::setHasAssociatedObjects() for a replacement
 
 698 objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
 
 700     _object_set_associative_reference(object, key, value, policy);
 
 703 void objc_removeAssociatedObjects(id object) 
 
 705     if (object && object->hasAssociatedObjects()) {
 
 706         _object_remove_assocations(object, /*deallocating*/false);
 
 712 #if SUPPORT_GC_COMPAT
 
 714 #include <mach-o/fat.h>
 
 716 // GC preflight for an app executable.
 
 724 // Overloaded template wrappers around clang's overflow-checked arithmetic.
 
 726 template <typename T> bool uadd_overflow(T x, T y, T* sum);
 
 727 template <typename T> bool usub_overflow(T x, T y, T* diff);
 
 728 template <typename T> bool umul_overflow(T x, T y, T* prod);
 
 730 template <typename T> bool sadd_overflow(T x, T y, T* sum);
 
 731 template <typename T> bool ssub_overflow(T x, T y, T* diff);
 
 732 template <typename T> bool smul_overflow(T x, T y, T* prod);
 
 734 template <> bool uadd_overflow(unsigned x, unsigned y, unsigned* sum) { return __builtin_uadd_overflow(x, y, sum); }
 
 735 template <> bool uadd_overflow(unsigned long x, unsigned long y, unsigned long* sum) { return __builtin_uaddl_overflow(x, y, sum); }
 
 736 template <> bool uadd_overflow(unsigned long long x, unsigned long long y, unsigned long long* sum) { return __builtin_uaddll_overflow(x, y, sum); }
 
 738 template <> bool usub_overflow(unsigned x, unsigned y, unsigned* diff) { return __builtin_usub_overflow(x, y, diff); }
 
 739 template <> bool usub_overflow(unsigned long x, unsigned long y, unsigned long* diff) { return __builtin_usubl_overflow(x, y, diff); }
 
 740 template <> bool usub_overflow(unsigned long long x, unsigned long long y, unsigned long long* diff) { return __builtin_usubll_overflow(x, y, diff); }
 
 742 template <> bool umul_overflow(unsigned x, unsigned y, unsigned* prod) { return __builtin_umul_overflow(x, y, prod); }
 
 743 template <> bool umul_overflow(unsigned long x, unsigned long y, unsigned long* prod) { return __builtin_umull_overflow(x, y, prod); }
 
 744 template <> bool umul_overflow(unsigned long long x, unsigned long long y, unsigned long long* prod) { return __builtin_umulll_overflow(x, y, prod); }
 
 746 template <> bool sadd_overflow(signed x, signed y, signed* sum) { return __builtin_sadd_overflow(x, y, sum); }
 
 747 template <> bool sadd_overflow(signed long x, signed long y, signed long* sum) { return __builtin_saddl_overflow(x, y, sum); }
 
 748 template <> bool sadd_overflow(signed long long x, signed long long y, signed long long* sum) { return __builtin_saddll_overflow(x, y, sum); }
 
 750 template <> bool ssub_overflow(signed x, signed y, signed* diff) { return __builtin_ssub_overflow(x, y, diff); }
 
 751 template <> bool ssub_overflow(signed long x, signed long y, signed long* diff) { return __builtin_ssubl_overflow(x, y, diff); }
 
 752 template <> bool ssub_overflow(signed long long x, signed long long y, signed long long* diff) { return __builtin_ssubll_overflow(x, y, diff); }
 
 754 template <> bool smul_overflow(signed x, signed y, signed* prod) { return __builtin_smul_overflow(x, y, prod); }
 
 755 template <> bool smul_overflow(signed long x, signed long y, signed long* prod) { return __builtin_smull_overflow(x, y, prod); }
 
 756 template <> bool smul_overflow(signed long long x, signed long long y, signed long long* prod) { return __builtin_smulll_overflow(x, y, prod); }
 
 759 // Range-checking subview of a file.
 
 762     uint64_t sliceOffset;
 
 766     FileSlice() : fd(-1), sliceOffset(0), sliceSize(0) { }
 
 768     FileSlice(int newfd, uint64_t newOffset, uint64_t newSize) 
 
 769         : fd(newfd) , sliceOffset(newOffset) , sliceSize(newSize) { }
 
 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) {
 
 775         if (uadd_overflow(readOffset, readSize, &readEnd)) return NO;
 
 776         if (readEnd > sliceSize) return NO;
 
 778         uint64_t preadOffset;
 
 779         if (uadd_overflow(sliceOffset, readOffset, &preadOffset)) return NO;
 
 781         int64_t readed = ::pread(fd, buf, (size_t)readSize, preadOffset);
 
 782         if (readed < 0  ||  (uint64_t)readed != readSize) return NO;
 
 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
 
 791         if (uadd_overflow(newOffset, newSize, &newEnd)) return NO;
 
 792         if (newEnd > sliceSize) return NO;
 
 794         if (uadd_overflow(sliceOffset, newOffset, &result.sliceOffset)) {
 
 797         result.sliceSize = newSize;
 
 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;
 
 812 // Arch32 and Arch64 are used to specialize sliceRequiresGC()
 
 813 // to interrogate old-ABI i386 and new-ABI x86_64 files.
 
 816     using mh_t = struct mach_header;
 
 817     using segment_command_t = struct segment_command;
 
 818     using section_t = struct section;
 
 820     enum : cpu_type_t { cputype = CPU_TYPE_X86 };
 
 821     enum : int { segment_cmd = LC_SEGMENT };
 
 823     static bool isObjCSegment(const char *segname) {
 
 824         return segnameEquals(segname, "__OBJC");
 
 827     static bool isImageInfoSection(const char *sectname) {
 
 828         return sectnameEquals(sectname, "__image_info");
 
 831     static bool countClasses(FileSlice file, section_t& sect, 
 
 832                              int& classCount, int& classrefCount)
 
 834         if (sectnameEquals(sect.sectname, "__cls_refs")) {
 
 835             classrefCount += sect.size / 4;
 
 837         else if (sectnameEquals(sect.sectname, "__module_info")) {
 
 841                 uint32_t name;    // not bound
 
 842                 uint32_t symtab;  // not bound
 
 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.
 
 852             } else if (mod_count == 1) {
 
 853                 FileSlice moduleSlice;
 
 854                 if (!file.slice(sect.offset, sect.size, moduleSlice)) return NO;
 
 856                 if (!moduleSlice.pread(&module, sizeof(module))) return NO;
 
 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.
 
 872     using mh_t = struct mach_header_64;
 
 873     using segment_command_t = struct segment_command_64;
 
 874     using section_t = struct section_64;
 
 876     enum : cpu_type_t { cputype = CPU_TYPE_X86_64 };
 
 877     enum : int { segment_cmd = LC_SEGMENT_64 };
 
 879     static bool isObjCSegment(const char *segname) {
 
 881             segnameEquals(segname, "__DATA")  ||  
 
 882             segnameEquals(segname, "__DATA_CONST")  ||  
 
 883             segnameEquals(segname, "__DATA_DIRTY");
 
 886     static bool isImageInfoSection(const char *sectname) {
 
 887         return sectnameEquals(sectname, "__objc_imageinfo");
 
 890     static bool countClasses(FileSlice, section_t& sect, 
 
 891                              int& classCount, int& classrefCount)
 
 893         if (sectnameEquals(sect.sectname, "__objc_classlist")) {
 
 894             classCount += sect.size / 8;
 
 896         else if (sectnameEquals(sect.sectname, "__objc_classrefs")) {
 
 897             classrefCount += sect.size / 8;
 
 904 #define SANE_HEADER_SIZE (32*1024)
 
 906 template <typename Arch>
 
 907 static int sliceRequiresGC(typename Arch::mh_t mh, FileSlice file)
 
 909     // We assume there is only one arch per pointer size that can support GC.
 
 911     if (mh.cputype != Arch::cputype) return 0;
 
 913     // We only check the main executable.
 
 914     if (mh.filetype != MH_EXECUTE) return 0;
 
 916     // Look for ObjC segment.
 
 917     // Look for AppleScriptObjC linkage.
 
 919     if (!file.slice(sizeof(mh), mh.sizeofcmds, cmds)) return Error;
 
 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.
 
 927     bool linksToAppleScriptObjC = NO;
 
 929     int classrefCount = 0;
 
 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;
 
 936     for (uint32_t cmdindex = 0; cmdindex < mh.ncmds; cmdindex++) {
 
 937         struct load_command lc;
 
 938         if (!cmds.pread(&lc, sizeof(lc))) return Error;
 
 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;
 
 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) 
 
 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;
 
 953             const char *asoFramework = 
 
 954                 "/System/Library/Frameworks/AppleScriptObjC.framework"
 
 955                 "/Versions/A/AppleScriptObjC";
 
 956             size_t asoLen = strlen(asoFramework);
 
 959             if (dylibSlice.slice(dylib.dylib.name.offset, asoLen, nameSlice)) {
 
 961                 if (!nameSlice.pread(name, asoLen)) return Error;
 
 962                 if (0 == memcmp(name, asoFramework, asoLen)) {
 
 963                     linksToAppleScriptObjC = YES;
 
 967         else if (lc.cmd == Arch::segment_cmd) {
 
 968             typename Arch::segment_command_t seg;
 
 969             if (!cmds.pread(&seg, sizeof(seg))) return Error;
 
 971             if (Arch::isObjCSegment(seg.segname)) {
 
 973                 // Look for image info section.
 
 974                 // Look for class implementations and class references.
 
 976                 if (!cmds.slice(0, seg.cmdsize, sections)) return Error;
 
 977                 if (!sections.advance(sizeof(seg))) return Error;
 
 979                 for (uint32_t segindex = 0; segindex < seg.nsects; segindex++) {
 
 980                     typename Arch::section_t sect;
 
 981                     if (!sections.pread(§, sizeof(sect))) return Error;
 
 982                     if (!Arch::isObjCSegment(sect.segname)) return Error;
 
 984                     if (!Arch::countClasses(file, sect, 
 
 985                                             classCount, classrefCount)) 
 
 990                     if ((sect.flags & SECTION_TYPE) == S_REGULAR  &&  
 
 991                         Arch::isImageInfoSection(sect.sectname))
 
 993                         // ObjC image info section.
 
 994                         // Check its contents.
 
 996                         if (!file.slice(sect.offset, sect.size, section)) {
 
 999                         // The subset of objc_image_info that was in use for GC.
 
1004                         if (!section.pread(&ii, sizeof(ii))) return Error;
 
1005                         if (ii.flags & (1<<1)) {
 
1007                             // Don't return yet because we need to 
 
1008                             // check the AppleScriptObjC exception.
 
1013                     if (!sections.advance(sizeof(sect))) return Error;
 
1018         if (!cmds.advance(lc.cmdsize)) return Error;
 
1025     else if (linksToAppleScriptObjC && classCount == 0 && classrefCount == 1) {
 
1026         // Has GC bit but falls under the AppleScriptObjC exception.
 
1030         // Has GC bit and is not AppleScriptObjC.
 
1036 static int sliceRequiresGC(FileSlice file)
 
1038     // Read mach-o header.
 
1039     struct mach_header_64 mh;
 
1040     if (!file.pread(&mh, sizeof(mh))) return Error;
 
1042     // Check header magic. We assume only host-endian slices can support GC.
 
1045         return sliceRequiresGC<Arch32>(*(struct mach_header *)&mh, file);
 
1047         return sliceRequiresGC<Arch64>(mh, file);
 
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.
 
1057 int objc_appRequiresGC(int fd)
 
1060     if (fstat(fd, &st) < 0) return Error;
 
1062     FileSlice file(fd, 0, st.st_size);
 
1064     // Read fat header, if any.
 
1065     struct fat_header fh;
 
1067     if (! file.pread(&fh, sizeof(fh))) return Error;
 
1071     if (OSSwapBigToHostInt32(fh.magic) == FAT_MAGIC) {
 
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;
 
1079         if (umul_overflow(nfat_arch, sizeof(struct fat_arch), &fat_size)) {
 
1084         if (!file.slice(sizeof(fh), fat_size, archlist)) return Error;
 
1087         for (size_t i = 0; i < nfat_arch; i++) {
 
1089             if (!archlist.pread(&fa, sizeof(fa))) return Error;
 
1090             if (!archlist.advance(sizeof(fa))) return Error;
 
1093             if (!file.slice(OSSwapBigToHostInt32(fa.offset), 
 
1094                             OSSwapBigToHostInt32(fa.size), thin)) 
 
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;
 
1106         // Thin header or not a header.
 
1107         result = sliceRequiresGC(file);
 
1113 // SUPPORT_GC_COMPAT