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 "objc-private.h"
37 #include "objc-loadmethod.h"
40 /***********************************************************************
42 **********************************************************************/
44 /* Linker metadata symbols */
46 // NSObject was in Foundation/CF on macOS < 10.8.
50 const char __objc_nsobject_class_10_5 = 0;
51 const char __objc_nsobject_class_10_6 = 0;
52 const char __objc_nsobject_class_10_7 = 0;
54 const char __objc_nsobject_metaclass_10_5 = 0;
55 const char __objc_nsobject_metaclass_10_6 = 0;
56 const char __objc_nsobject_metaclass_10_7 = 0;
58 const char __objc_nsobject_isa_10_5 = 0;
59 const char __objc_nsobject_isa_10_6 = 0;
60 const char __objc_nsobject_isa_10_7 = 0;
64 const char __objc_nsobject_class_10_5 = 0;
65 const char __objc_nsobject_class_10_6 = 0;
66 const char __objc_nsobject_class_10_7 = 0;
71 // Settings from environment variables
72 #define OPTION(var, env, help) bool var = false;
83 const option_t Settings[] = {
84 #define OPTION(var, env, help) option_t{&var, #env, help, strlen(#env)},
90 // objc's key for pthread_getspecific
91 static tls_key_t _objc_pthread_key;
95 SEL SEL_initialize = NULL;
96 SEL SEL_resolveInstanceMethod = NULL;
97 SEL SEL_resolveClassMethod = NULL;
98 SEL SEL_cxx_construct = NULL;
99 SEL SEL_cxx_destruct = NULL;
100 SEL SEL_retain = NULL;
101 SEL SEL_release = NULL;
102 SEL SEL_autorelease = NULL;
103 SEL SEL_retainCount = NULL;
104 SEL SEL_alloc = NULL;
105 SEL SEL_allocWithZone = NULL;
106 SEL SEL_dealloc = NULL;
109 SEL SEL_forwardInvocation = NULL;
110 SEL SEL_tryRetain = NULL;
111 SEL SEL_isDeallocating = NULL;
112 SEL SEL_retainWeakReference = NULL;
113 SEL SEL_allowsWeakReference = NULL;
116 header_info *FirstHeader = 0; // NULL means empty list
117 header_info *LastHeader = 0; // NULL means invalid; recompute it
121 // Set to true on the child side of fork()
122 // if the parent process was multithreaded when fork() was called.
123 bool MultithreadedForkChild = false;
126 /***********************************************************************
127 * objc_noop_imp. Used when we need to install a do-nothing method somewhere.
128 **********************************************************************/
129 id objc_noop_imp(id self, SEL _cmd __unused) {
134 /***********************************************************************
135 * objc_getClass. Return the id of the named class. If the class does
136 * not exist, call _objc_classLoader and then objc_classHandler, either of
137 * which may create a new class.
138 * Warning: doesn't work if aClassName is the name of a posed-for class's isa!
139 **********************************************************************/
140 Class objc_getClass(const char *aClassName)
142 if (!aClassName) return Nil;
144 // NO unconnected, YES class handler
145 return look_up_class(aClassName, NO, YES);
149 /***********************************************************************
150 * objc_getRequiredClass.
151 * Same as objc_getClass, but kills the process if the class is not found.
152 * This is used by ZeroLink, where failing to find a class would be a
153 * compile-time link error without ZeroLink.
154 **********************************************************************/
155 Class objc_getRequiredClass(const char *aClassName)
157 Class cls = objc_getClass(aClassName);
158 if (!cls) _objc_fatal("link error: class '%s' not found.", aClassName);
163 /***********************************************************************
164 * objc_lookUpClass. Return the id of the named class.
165 * If the class does not exist, call _objc_classLoader, which may create
168 * Formerly objc_getClassWithoutWarning ()
169 **********************************************************************/
170 Class objc_lookUpClass(const char *aClassName)
172 if (!aClassName) return Nil;
174 // NO unconnected, NO class handler
175 return look_up_class(aClassName, NO, NO);
179 /***********************************************************************
180 * objc_getMetaClass. Return the id of the meta class the named class.
181 * Warning: doesn't work if aClassName is the name of a posed-for class's isa!
182 **********************************************************************/
183 Class objc_getMetaClass(const char *aClassName)
187 if (!aClassName) return Nil;
189 cls = objc_getClass (aClassName);
192 _objc_inform ("class `%s' not linked into application", aClassName);
200 /***********************************************************************
201 * appendHeader. Add a newly-constructed header_info to the list.
202 **********************************************************************/
203 void appendHeader(header_info *hi)
205 // Add the header to the header list.
206 // The header is appended to the list, to preserve the bottom-up order.
211 FirstHeader = LastHeader = hi;
214 // list is not empty, but LastHeader is invalid - recompute it
215 LastHeader = FirstHeader;
216 while (LastHeader->getNext()) LastHeader = LastHeader->getNext();
218 // LastHeader is now valid
219 LastHeader->setNext(hi);
225 /***********************************************************************
227 * Remove the given header from the header list.
228 * FirstHeader is updated.
229 * LastHeader is set to NULL. Any code that uses LastHeader must
230 * detect this NULL and recompute LastHeader by traversing the list.
231 **********************************************************************/
232 void removeHeader(header_info *hi)
234 header_info *prev = NULL;
235 header_info *current = NULL;
237 for (current = FirstHeader; current != NULL; current = current->getNext()) {
239 header_info *deadHead = current;
241 // Remove from the linked list.
243 prev->setNext(current->getNext());
245 FirstHeader = current->getNext(); // no prev so removing head
247 // Update LastHeader if necessary.
248 if (LastHeader == deadHead) {
249 LastHeader = NULL; // will be recomputed next time it's used
260 /***********************************************************************
262 * Read environment variables that affect the runtime.
263 * Also print environment variable help, if requested.
264 **********************************************************************/
265 void environ_init(void)
268 // All environment variables are silently ignored when setuid or setgid
269 // This includes OBJC_HELP and OBJC_PRINT_OPTIONS themselves.
273 bool PrintHelp = false;
274 bool PrintOptions = false;
275 bool maybeMallocDebugging = false;
277 // Scan environ[] directly instead of calling getenv() a lot.
278 // This optimizes the case where none are set.
279 for (char **p = *_NSGetEnviron(); *p != nil; p++) {
280 if (0 == strncmp(*p, "Malloc", 6) || 0 == strncmp(*p, "DYLD", 4) ||
281 0 == strncmp(*p, "NSZombiesEnabled", 16))
283 maybeMallocDebugging = true;
286 if (0 != strncmp(*p, "OBJC_", 5)) continue;
288 if (0 == strncmp(*p, "OBJC_HELP=", 10)) {
292 if (0 == strncmp(*p, "OBJC_PRINT_OPTIONS=", 19)) {
297 const char *value = strchr(*p, '=');
298 if (!*value) continue;
301 for (size_t i = 0; i < sizeof(Settings)/sizeof(Settings[0]); i++) {
302 const option_t *opt = &Settings[i];
303 if ((size_t)(value - *p) == 1+opt->envlen &&
304 0 == strncmp(*p, opt->env, opt->envlen))
306 *opt->var = (0 == strcmp(value, "YES"));
312 // Special case: enable some autorelease pool debugging
313 // when some malloc debugging is enabled
314 // and OBJC_DEBUG_POOL_ALLOCATION is not set to something other than NO.
315 if (maybeMallocDebugging) {
316 const char *insert = getenv("DYLD_INSERT_LIBRARIES");
317 const char *zombie = getenv("NSZombiesEnabled");
318 const char *pooldebug = getenv("OBJC_DEBUG_POOL_ALLOCATION");
319 if ((getenv("MallocStackLogging")
320 || getenv("MallocStackLoggingNoCompact")
321 || (zombie && (*zombie == 'Y' || *zombie == 'y'))
322 || (insert && strstr(insert, "libgmalloc")))
324 (!pooldebug || 0 == strcmp(pooldebug, "YES")))
326 DebugPoolAllocation = true;
330 // Print OBJC_HELP and OBJC_PRINT_OPTIONS output.
331 if (PrintHelp || PrintOptions) {
333 _objc_inform("Objective-C runtime debugging. Set variable=YES to enable.");
334 _objc_inform("OBJC_HELP: describe available environment variables");
336 _objc_inform("OBJC_HELP is set");
338 _objc_inform("OBJC_PRINT_OPTIONS: list which options are set");
341 _objc_inform("OBJC_PRINT_OPTIONS is set");
344 for (size_t i = 0; i < sizeof(Settings)/sizeof(Settings[0]); i++) {
345 const option_t *opt = &Settings[i];
346 if (PrintHelp) _objc_inform("%s: %s", opt->env, opt->help);
347 if (PrintOptions && *opt->var) _objc_inform("%s is set", opt->env);
353 /***********************************************************************
355 * OBJC_PRINT_REPLACED_METHODS implementation
356 **********************************************************************/
358 logReplacedMethod(const char *className, SEL s,
359 bool isMeta, const char *catName,
360 IMP oldImp, IMP newImp)
362 const char *oldImage = "??";
363 const char *newImage = "??";
365 // Silently ignore +load replacement because category +load is special
366 if (s == SEL_load) return;
369 // don't know dladdr()/dli_fname equivalent
373 if (dladdr((void*)oldImp, &dl) && dl.dli_fname) oldImage = dl.dli_fname;
374 if (dladdr((void*)newImp, &dl) && dl.dli_fname) newImage = dl.dli_fname;
377 _objc_inform("REPLACED: %c[%s %s] %s%s (IMP was %p (%s), now %p (%s))",
378 isMeta ? '+' : '-', className, sel_getName(s),
379 catName ? "by category " : "", catName ? catName : "",
380 oldImp, oldImage, newImp, newImage);
384 /***********************************************************************
385 * _objc_fetch_pthread_data
386 * Fetch objc's pthread data for this thread.
387 * If the data doesn't exist yet and create is NO, return NULL.
388 * If the data doesn't exist yet and create is YES, allocate and return it.
389 **********************************************************************/
390 _objc_pthread_data *_objc_fetch_pthread_data(bool create)
392 _objc_pthread_data *data;
394 data = (_objc_pthread_data *)tls_get(_objc_pthread_key);
395 if (!data && create) {
396 data = (_objc_pthread_data *)
397 calloc(1, sizeof(_objc_pthread_data));
398 tls_set(_objc_pthread_key, data);
405 /***********************************************************************
406 * _objc_pthread_destroyspecific
407 * Destructor for objc's per-thread data.
408 * arg shouldn't be NULL, but we check anyway.
409 **********************************************************************/
410 extern void _destroyInitializingClassList(struct _objc_initializing_classes *list);
411 void _objc_pthread_destroyspecific(void *arg)
413 _objc_pthread_data *data = (_objc_pthread_data *)arg;
415 _destroyInitializingClassList(data->initializingClasses);
416 _destroySyncCache(data->syncCache);
417 _destroyAltHandlerList(data->handlerList);
418 for (int i = 0; i < (int)countof(data->printableNames); i++) {
419 if (data->printableNames[i]) {
420 free(data->printableNames[i]);
424 // add further cleanup here...
433 #if SUPPORT_DIRECT_THREAD_KEYS
434 _objc_pthread_key = TLS_DIRECT_KEY;
435 pthread_key_init_np(TLS_DIRECT_KEY, &_objc_pthread_destroyspecific);
437 _objc_pthread_key = tls_create(&_objc_pthread_destroyspecific);
442 /***********************************************************************
444 * Former library initializer. This function is now merely a placeholder
445 * for external callers. All runtime initialization has now been moved
446 * to map_images() and _objc_init.
447 **********************************************************************/
454 /***********************************************************************
455 * objc_setForwardHandler
456 **********************************************************************/
460 // Default forward handler (nil) goes to forward:: dispatch.
461 void *_objc_forward_handler = nil;
462 void *_objc_forward_stret_handler = nil;
466 // Default forward handler halts the process.
467 __attribute__((noreturn)) void
468 objc_defaultForwardHandler(id self, SEL sel)
470 _objc_fatal("%c[%s %s]: unrecognized selector sent to instance %p "
471 "(no message forward handler is installed)",
472 class_isMetaClass(object_getClass(self)) ? '+' : '-',
473 object_getClassName(self), sel_getName(sel), self);
475 void *_objc_forward_handler = (void*)objc_defaultForwardHandler;
478 struct stret { int i[100]; };
479 __attribute__((noreturn)) struct stret
480 objc_defaultForwardStretHandler(id self, SEL sel)
482 objc_defaultForwardHandler(self, sel);
484 void *_objc_forward_stret_handler = (void*)objc_defaultForwardStretHandler;
489 void objc_setForwardHandler(void *fwd, void *fwd_stret)
491 _objc_forward_handler = fwd;
493 _objc_forward_stret_handler = fwd_stret;
500 extern "C" Class _objc_getOrigClass(const char *name);
503 static BOOL internal_class_getImageName(Class cls, const char **outName)
506 cls = _objc_getOrigClass(cls->demangledName());
508 auto result = dyld_image_path_containing_address(cls);
510 return (result != nil);
514 static ChainedHookFunction<objc_hook_getImageName>
515 GetImageNameHook{internal_class_getImageName};
517 void objc_setHook_getImageName(objc_hook_getImageName newValue,
518 objc_hook_getImageName *outOldValue)
520 GetImageNameHook.set(newValue, outOldValue);
523 const char *class_getImageName(Class cls)
525 if (!cls) return nil;
528 if (GetImageNameHook.get()(cls, &name)) return name;
533 /**********************************************************************
534 * Fast Enumeration Support
535 **********************************************************************/
537 static void (*enumerationMutationHandler)(id);
539 /**********************************************************************
540 * objc_enumerationMutation
541 * called by compiler when a mutation is detected during foreach iteration
542 **********************************************************************/
543 void objc_enumerationMutation(id object) {
544 if (enumerationMutationHandler == nil) {
545 _objc_fatal("mutation detected during 'for(... in ...)' enumeration of object %p.", (void*)object);
547 (*enumerationMutationHandler)(object);
551 /**********************************************************************
552 * objc_setEnumerationMutationHandler
553 * an entry point to customize mutation error handing
554 **********************************************************************/
555 void objc_setEnumerationMutationHandler(void (*handler)(id)) {
556 enumerationMutationHandler = handler;
560 /**********************************************************************
561 * Associative Reference Support
562 **********************************************************************/
564 id objc_getAssociatedObject(id object, const void *key) {
565 return _object_get_associative_reference(object, (void *)key);
569 void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy) {
570 _object_set_associative_reference(object, (void *)key, value, policy);
574 void objc_removeAssociatedObjects(id object)
576 if (object && object->hasAssociatedObjects()) {
577 _object_remove_assocations(object);
583 #if SUPPORT_GC_COMPAT
585 #include <mach-o/fat.h>
587 // GC preflight for an app executable.
595 // Overloaded template wrappers around clang's overflow-checked arithmetic.
597 template <typename T> bool uadd_overflow(T x, T y, T* sum);
598 template <typename T> bool usub_overflow(T x, T y, T* diff);
599 template <typename T> bool umul_overflow(T x, T y, T* prod);
601 template <typename T> bool sadd_overflow(T x, T y, T* sum);
602 template <typename T> bool ssub_overflow(T x, T y, T* diff);
603 template <typename T> bool smul_overflow(T x, T y, T* prod);
605 template <> bool uadd_overflow(unsigned x, unsigned y, unsigned* sum) { return __builtin_uadd_overflow(x, y, sum); }
606 template <> bool uadd_overflow(unsigned long x, unsigned long y, unsigned long* sum) { return __builtin_uaddl_overflow(x, y, sum); }
607 template <> bool uadd_overflow(unsigned long long x, unsigned long long y, unsigned long long* sum) { return __builtin_uaddll_overflow(x, y, sum); }
609 template <> bool usub_overflow(unsigned x, unsigned y, unsigned* diff) { return __builtin_usub_overflow(x, y, diff); }
610 template <> bool usub_overflow(unsigned long x, unsigned long y, unsigned long* diff) { return __builtin_usubl_overflow(x, y, diff); }
611 template <> bool usub_overflow(unsigned long long x, unsigned long long y, unsigned long long* diff) { return __builtin_usubll_overflow(x, y, diff); }
613 template <> bool umul_overflow(unsigned x, unsigned y, unsigned* prod) { return __builtin_umul_overflow(x, y, prod); }
614 template <> bool umul_overflow(unsigned long x, unsigned long y, unsigned long* prod) { return __builtin_umull_overflow(x, y, prod); }
615 template <> bool umul_overflow(unsigned long long x, unsigned long long y, unsigned long long* prod) { return __builtin_umulll_overflow(x, y, prod); }
617 template <> bool sadd_overflow(signed x, signed y, signed* sum) { return __builtin_sadd_overflow(x, y, sum); }
618 template <> bool sadd_overflow(signed long x, signed long y, signed long* sum) { return __builtin_saddl_overflow(x, y, sum); }
619 template <> bool sadd_overflow(signed long long x, signed long long y, signed long long* sum) { return __builtin_saddll_overflow(x, y, sum); }
621 template <> bool ssub_overflow(signed x, signed y, signed* diff) { return __builtin_ssub_overflow(x, y, diff); }
622 template <> bool ssub_overflow(signed long x, signed long y, signed long* diff) { return __builtin_ssubl_overflow(x, y, diff); }
623 template <> bool ssub_overflow(signed long long x, signed long long y, signed long long* diff) { return __builtin_ssubll_overflow(x, y, diff); }
625 template <> bool smul_overflow(signed x, signed y, signed* prod) { return __builtin_smul_overflow(x, y, prod); }
626 template <> bool smul_overflow(signed long x, signed long y, signed long* prod) { return __builtin_smull_overflow(x, y, prod); }
627 template <> bool smul_overflow(signed long long x, signed long long y, signed long long* prod) { return __builtin_smulll_overflow(x, y, prod); }
630 // Range-checking subview of a file.
633 uint64_t sliceOffset;
637 FileSlice() : fd(-1), sliceOffset(0), sliceSize(0) { }
639 FileSlice(int newfd, uint64_t newOffset, uint64_t newSize)
640 : fd(newfd) , sliceOffset(newOffset) , sliceSize(newSize) { }
642 // Read bytes from this slice.
643 // Returns YES if all bytes were read successfully.
644 bool pread(void *buf, uint64_t readSize, uint64_t readOffset = 0) {
646 if (uadd_overflow(readOffset, readSize, &readEnd)) return NO;
647 if (readEnd > sliceSize) return NO;
649 uint64_t preadOffset;
650 if (uadd_overflow(sliceOffset, readOffset, &preadOffset)) return NO;
652 int64_t readed = ::pread(fd, buf, (size_t)readSize, preadOffset);
653 if (readed < 0 || (uint64_t)readed != readSize) return NO;
657 // Create a new slice that is a subset of this slice.
658 // Returnes YES if successful.
659 bool slice(uint64_t newOffset, uint64_t newSize, FileSlice& result) {
660 // fixme arithmetic overflow
662 if (uadd_overflow(newOffset, newSize, &newEnd)) return NO;
663 if (newEnd > sliceSize) return NO;
665 if (uadd_overflow(sliceOffset, newOffset, &result.sliceOffset)) {
668 result.sliceSize = newSize;
673 // Shorten this slice in place by removing a range from the start.
674 bool advance(uint64_t distance) {
675 if (distance > sliceSize) return NO;
676 if (uadd_overflow(sliceOffset, distance, &sliceOffset)) return NO;
677 if (usub_overflow(sliceSize, distance, &sliceSize)) return NO;
683 // Arch32 and Arch64 are used to specialize sliceRequiresGC()
684 // to interrogate old-ABI i386 and new-ABI x86_64 files.
687 using mh_t = struct mach_header;
688 using segment_command_t = struct segment_command;
689 using section_t = struct section;
691 enum : cpu_type_t { cputype = CPU_TYPE_X86 };
692 enum : int { segment_cmd = LC_SEGMENT };
694 static bool isObjCSegment(const char *segname) {
695 return segnameEquals(segname, "__OBJC");
698 static bool isImageInfoSection(const char *sectname) {
699 return sectnameEquals(sectname, "__image_info");
702 static bool countClasses(FileSlice file, section_t& sect,
703 int& classCount, int& classrefCount)
705 if (sectnameEquals(sect.sectname, "__cls_refs")) {
706 classrefCount += sect.size / 4;
708 else if (sectnameEquals(sect.sectname, "__module_info")) {
712 uint32_t name; // not bound
713 uint32_t symtab; // not bound
715 size_t mod_count = sect.size / sizeof(module_t);
716 if (mod_count == 0) {
717 // no classes defined
718 } else if (mod_count > 1) {
719 // AppleScriptObjC apps only have one module.
720 // Disqualify this app by setting classCount to non-zero.
721 // We don't actually need an accurate count.
723 } else if (mod_count == 1) {
724 FileSlice moduleSlice;
725 if (!file.slice(sect.offset, sect.size, moduleSlice)) return NO;
727 if (!moduleSlice.pread(&module, sizeof(module))) return NO;
729 // AppleScriptObjC apps only have a module with no symtab.
730 // Disqualify this app by setting classCount to non-zero.
731 // We don't actually need an accurate count.
743 using mh_t = struct mach_header_64;
744 using segment_command_t = struct segment_command_64;
745 using section_t = struct section_64;
747 enum : cpu_type_t { cputype = CPU_TYPE_X86_64 };
748 enum : int { segment_cmd = LC_SEGMENT_64 };
750 static bool isObjCSegment(const char *segname) {
752 segnameEquals(segname, "__DATA") ||
753 segnameEquals(segname, "__DATA_CONST") ||
754 segnameEquals(segname, "__DATA_DIRTY");
757 static bool isImageInfoSection(const char *sectname) {
758 return sectnameEquals(sectname, "__objc_imageinfo");
761 static bool countClasses(FileSlice, section_t& sect,
762 int& classCount, int& classrefCount)
764 if (sectnameEquals(sect.sectname, "__objc_classlist")) {
765 classCount += sect.size / 8;
767 else if (sectnameEquals(sect.sectname, "__objc_classrefs")) {
768 classrefCount += sect.size / 8;
775 #define SANE_HEADER_SIZE (32*1024)
777 template <typename Arch>
778 static int sliceRequiresGC(typename Arch::mh_t mh, FileSlice file)
780 // We assume there is only one arch per pointer size that can support GC.
782 if (mh.cputype != Arch::cputype) return 0;
784 // We only check the main executable.
785 if (mh.filetype != MH_EXECUTE) return 0;
787 // Look for ObjC segment.
788 // Look for AppleScriptObjC linkage.
790 if (!file.slice(sizeof(mh), mh.sizeofcmds, cmds)) return Error;
792 // Exception: Some AppleScriptObjC apps built for GC can run without GC.
793 // 1. executable defines no classes
794 // 2. executable references NSBundle only
795 // 3. executable links to AppleScriptObjC.framework
796 // Note that shouldRejectGCApp() also knows about this.
798 bool linksToAppleScriptObjC = NO;
800 int classrefCount = 0;
802 // Disallow abusively-large executables that could hang this checker.
803 // dyld performs similar checks (MAX_MACH_O_HEADER_AND_LOAD_COMMANDS_SIZE)
804 if (mh.sizeofcmds > SANE_HEADER_SIZE) return Error;
805 if (mh.ncmds > mh.sizeofcmds / sizeof(struct load_command)) return Error;
807 for (uint32_t cmdindex = 0; cmdindex < mh.ncmds; cmdindex++) {
808 struct load_command lc;
809 if (!cmds.pread(&lc, sizeof(lc))) return Error;
811 // Disallow abusively-small load commands that could hang this checker.
812 // dyld performs a similar check.
813 if (lc.cmdsize < sizeof(lc)) return Error;
815 if (lc.cmd == LC_LOAD_DYLIB || lc.cmd == LC_LOAD_UPWARD_DYLIB ||
816 lc.cmd == LC_LOAD_WEAK_DYLIB || lc.cmd == LC_REEXPORT_DYLIB)
818 // Look for AppleScriptObjC linkage.
819 FileSlice dylibSlice;
820 if (!cmds.slice(0, lc.cmdsize, dylibSlice)) return Error;
821 struct dylib_command dylib;
822 if (!dylibSlice.pread(&dylib, sizeof(dylib))) return Error;
824 const char *asoFramework =
825 "/System/Library/Frameworks/AppleScriptObjC.framework"
826 "/Versions/A/AppleScriptObjC";
827 size_t asoLen = strlen(asoFramework);
830 if (dylibSlice.slice(dylib.dylib.name.offset, asoLen, nameSlice)) {
832 if (!nameSlice.pread(name, asoLen)) return Error;
833 if (0 == memcmp(name, asoFramework, asoLen)) {
834 linksToAppleScriptObjC = YES;
838 else if (lc.cmd == Arch::segment_cmd) {
839 typename Arch::segment_command_t seg;
840 if (!cmds.pread(&seg, sizeof(seg))) return Error;
842 if (Arch::isObjCSegment(seg.segname)) {
844 // Look for image info section.
845 // Look for class implementations and class references.
847 if (!cmds.slice(0, seg.cmdsize, sections)) return Error;
848 if (!sections.advance(sizeof(seg))) return Error;
850 for (uint32_t segindex = 0; segindex < seg.nsects; segindex++) {
851 typename Arch::section_t sect;
852 if (!sections.pread(§, sizeof(sect))) return Error;
853 if (!Arch::isObjCSegment(sect.segname)) return Error;
855 if (!Arch::countClasses(file, sect,
856 classCount, classrefCount))
861 if ((sect.flags & SECTION_TYPE) == S_REGULAR &&
862 Arch::isImageInfoSection(sect.sectname))
864 // ObjC image info section.
865 // Check its contents.
867 if (!file.slice(sect.offset, sect.size, section)) {
870 // The subset of objc_image_info that was in use for GC.
875 if (!section.pread(&ii, sizeof(ii))) return Error;
876 if (ii.flags & (1<<1)) {
878 // Don't return yet because we need to
879 // check the AppleScriptObjC exception.
884 if (!sections.advance(sizeof(sect))) return Error;
889 if (!cmds.advance(lc.cmdsize)) return Error;
896 else if (linksToAppleScriptObjC && classCount == 0 && classrefCount == 1) {
897 // Has GC bit but falls under the AppleScriptObjC exception.
901 // Has GC bit and is not AppleScriptObjC.
907 static int sliceRequiresGC(FileSlice file)
909 // Read mach-o header.
910 struct mach_header_64 mh;
911 if (!file.pread(&mh, sizeof(mh))) return Error;
913 // Check header magic. We assume only host-endian slices can support GC.
916 return sliceRequiresGC<Arch32>(*(struct mach_header *)&mh, file);
918 return sliceRequiresGC<Arch64>(mh, file);
925 // Returns 1 if any slice requires GC.
926 // Returns 0 if no slice requires GC.
927 // Returns -1 on any I/O or file format error.
928 int objc_appRequiresGC(int fd)
931 if (fstat(fd, &st) < 0) return Error;
933 FileSlice file(fd, 0, st.st_size);
935 // Read fat header, if any.
936 struct fat_header fh;
938 if (! file.pread(&fh, sizeof(fh))) return Error;
942 if (OSSwapBigToHostInt32(fh.magic) == FAT_MAGIC) {
945 size_t nfat_arch = OSSwapBigToHostInt32(fh.nfat_arch);
946 // Disallow abusively-large files that could hang this checker.
947 if (nfat_arch > SANE_HEADER_SIZE/sizeof(struct fat_arch)) return Error;
950 if (umul_overflow(nfat_arch, sizeof(struct fat_arch), &fat_size)) {
955 if (!file.slice(sizeof(fh), fat_size, archlist)) return Error;
958 for (size_t i = 0; i < nfat_arch; i++) {
960 if (!archlist.pread(&fa, sizeof(fa))) return Error;
961 if (!archlist.advance(sizeof(fa))) return Error;
964 if (!file.slice(OSSwapBigToHostInt32(fa.offset),
965 OSSwapBigToHostInt32(fa.size), thin))
969 switch (sliceRequiresGC(thin)) {
970 case WithoutGC: break; // no change
971 case WithGC: if (result != Error) result = WithGC; break;
972 case Error: result = Error; break;
977 // Thin header or not a header.
978 result = sliceRequiresGC(file);