objc-runtime.mm 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985
  1. /*
  2. * Copyright (c) 1999-2007 Apple Inc. All Rights Reserved.
  3. *
  4. * @APPLE_LICENSE_HEADER_START@
  5. *
  6. * This file contains Original Code and/or Modifications of Original Code
  7. * as defined in and that are subject to the Apple Public Source License
  8. * Version 2.0 (the 'License'). You may not use this file except in
  9. * compliance with the License. Please obtain a copy of the License at
  10. * http://www.opensource.apple.com/apsl/ and read it before using this
  11. * file.
  12. *
  13. * The Original Code and all software distributed under the License are
  14. * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  15. * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  16. * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
  17. * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  18. * Please see the License for the specific language governing rights and
  19. * limitations under the License.
  20. *
  21. * @APPLE_LICENSE_HEADER_END@
  22. */
  23. /***********************************************************************
  24. * objc-runtime.m
  25. * Copyright 1988-1996, NeXT Software, Inc.
  26. * Author: s. naroff
  27. *
  28. **********************************************************************/
  29. /***********************************************************************
  30. * Imports.
  31. **********************************************************************/
  32. #include "objc-private.h"
  33. #include "objc-loadmethod.h"
  34. #include "message.h"
  35. /***********************************************************************
  36. * Exports.
  37. **********************************************************************/
  38. /* Linker metadata symbols */
  39. // NSObject was in Foundation/CF on macOS < 10.8.
  40. #if TARGET_OS_OSX
  41. #if __OBJC2__
  42. const char __objc_nsobject_class_10_5 = 0;
  43. const char __objc_nsobject_class_10_6 = 0;
  44. const char __objc_nsobject_class_10_7 = 0;
  45. const char __objc_nsobject_metaclass_10_5 = 0;
  46. const char __objc_nsobject_metaclass_10_6 = 0;
  47. const char __objc_nsobject_metaclass_10_7 = 0;
  48. const char __objc_nsobject_isa_10_5 = 0;
  49. const char __objc_nsobject_isa_10_6 = 0;
  50. const char __objc_nsobject_isa_10_7 = 0;
  51. #else
  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;
  55. #endif
  56. #endif
  57. // Settings from environment variables
  58. #define OPTION(var, env, help) bool var = false;
  59. #include "objc-env.h"
  60. #undef OPTION
  61. struct option_t {
  62. bool* var;
  63. const char *env;
  64. const char *help;
  65. size_t envlen;
  66. };
  67. const option_t Settings[] = {
  68. #define OPTION(var, env, help) option_t{&var, #env, help, strlen(#env)},
  69. #include "objc-env.h"
  70. #undef OPTION
  71. };
  72. // objc's key for pthread_getspecific
  73. static tls_key_t _objc_pthread_key;
  74. // Selectors
  75. SEL SEL_load = NULL;
  76. SEL SEL_initialize = NULL;
  77. SEL SEL_resolveInstanceMethod = NULL;
  78. SEL SEL_resolveClassMethod = NULL;
  79. SEL SEL_cxx_construct = NULL;
  80. SEL SEL_cxx_destruct = NULL;
  81. SEL SEL_retain = NULL;
  82. SEL SEL_release = NULL;
  83. SEL SEL_autorelease = NULL;
  84. SEL SEL_retainCount = NULL;
  85. SEL SEL_alloc = NULL;
  86. SEL SEL_allocWithZone = NULL;
  87. SEL SEL_dealloc = NULL;
  88. SEL SEL_copy = NULL;
  89. SEL SEL_new = NULL;
  90. SEL SEL_forwardInvocation = NULL;
  91. SEL SEL_tryRetain = NULL;
  92. SEL SEL_isDeallocating = NULL;
  93. SEL SEL_retainWeakReference = NULL;
  94. SEL SEL_allowsWeakReference = NULL;
  95. header_info *FirstHeader = 0; // NULL means empty list
  96. header_info *LastHeader = 0; // NULL means invalid; recompute it
  97. int HeaderCount = 0;
  98. // Set to true on the child side of fork()
  99. // if the parent process was multithreaded when fork() was called.
  100. bool MultithreadedForkChild = false;
  101. /***********************************************************************
  102. * objc_noop_imp. Used when we need to install a do-nothing method somewhere.
  103. **********************************************************************/
  104. id objc_noop_imp(id self, SEL _cmd __unused) {
  105. return self;
  106. }
  107. /***********************************************************************
  108. * objc_getClass. Return the id of the named class. If the class does
  109. * not exist, call _objc_classLoader and then objc_classHandler, either of
  110. * which may create a new class.
  111. * Warning: doesn't work if aClassName is the name of a posed-for class's isa!
  112. **********************************************************************/
  113. Class objc_getClass(const char *aClassName)
  114. {
  115. if (!aClassName) return Nil;
  116. // NO unconnected, YES class handler
  117. return look_up_class(aClassName, NO, YES);
  118. }
  119. /***********************************************************************
  120. * objc_getRequiredClass.
  121. * Same as objc_getClass, but kills the process if the class is not found.
  122. * This is used by ZeroLink, where failing to find a class would be a
  123. * compile-time link error without ZeroLink.
  124. **********************************************************************/
  125. Class objc_getRequiredClass(const char *aClassName)
  126. {
  127. Class cls = objc_getClass(aClassName);
  128. if (!cls) _objc_fatal("link error: class '%s' not found.", aClassName);
  129. return cls;
  130. }
  131. /***********************************************************************
  132. * objc_lookUpClass. Return the id of the named class.
  133. * If the class does not exist, call _objc_classLoader, which may create
  134. * a new class.
  135. *
  136. * Formerly objc_getClassWithoutWarning ()
  137. **********************************************************************/
  138. Class objc_lookUpClass(const char *aClassName)
  139. {
  140. if (!aClassName) return Nil;
  141. // NO unconnected, NO class handler
  142. return look_up_class(aClassName, NO, NO);
  143. }
  144. /***********************************************************************
  145. * objc_getMetaClass. Return the id of the meta class the named class.
  146. * Warning: doesn't work if aClassName is the name of a posed-for class's isa!
  147. **********************************************************************/
  148. Class objc_getMetaClass(const char *aClassName)
  149. {
  150. Class cls;
  151. if (!aClassName) return Nil;
  152. cls = objc_getClass (aClassName);
  153. if (!cls)
  154. {
  155. _objc_inform ("class `%s' not linked into application", aClassName);
  156. return Nil;
  157. }
  158. return cls->ISA();
  159. }
  160. /***********************************************************************
  161. * appendHeader. Add a newly-constructed header_info to the list.
  162. **********************************************************************/
  163. void appendHeader(header_info *hi)
  164. {
  165. // Add the header to the header list.
  166. // The header is appended to the list, to preserve the bottom-up order.
  167. HeaderCount++;
  168. hi->setNext(NULL);
  169. if (!FirstHeader) {
  170. // list is empty
  171. FirstHeader = LastHeader = hi;
  172. } else {
  173. if (!LastHeader) {
  174. // list is not empty, but LastHeader is invalid - recompute it
  175. LastHeader = FirstHeader;
  176. while (LastHeader->getNext()) LastHeader = LastHeader->getNext();
  177. }
  178. // LastHeader is now valid
  179. LastHeader->setNext(hi);
  180. LastHeader = hi;
  181. }
  182. }
  183. /***********************************************************************
  184. * removeHeader
  185. * Remove the given header from the header list.
  186. * FirstHeader is updated.
  187. * LastHeader is set to NULL. Any code that uses LastHeader must
  188. * detect this NULL and recompute LastHeader by traversing the list.
  189. **********************************************************************/
  190. void removeHeader(header_info *hi)
  191. {
  192. header_info *prev = NULL;
  193. header_info *current = NULL;
  194. for (current = FirstHeader; current != NULL; current = current->getNext()) {
  195. if (current == hi) {
  196. header_info *deadHead = current;
  197. // Remove from the linked list.
  198. if (prev)
  199. prev->setNext(current->getNext());
  200. else
  201. FirstHeader = current->getNext(); // no prev so removing head
  202. // Update LastHeader if necessary.
  203. if (LastHeader == deadHead) {
  204. LastHeader = NULL; // will be recomputed next time it's used
  205. }
  206. HeaderCount--;
  207. break;
  208. }
  209. prev = current;
  210. }
  211. }
  212. /***********************************************************************
  213. * environ_init
  214. * Read environment variables that affect the runtime.
  215. * Also print environment variable help, if requested.
  216. **********************************************************************/
  217. void environ_init(void)
  218. {
  219. if (issetugid()) {
  220. // All environment variables are silently ignored when setuid or setgid
  221. // This includes OBJC_HELP and OBJC_PRINT_OPTIONS themselves.
  222. return;
  223. }
  224. bool PrintHelp = false;
  225. bool PrintOptions = false;
  226. bool maybeMallocDebugging = false;
  227. // Scan environ[] directly instead of calling getenv() a lot.
  228. // This optimizes the case where none are set.
  229. for (char **p = *_NSGetEnviron(); *p != nil; p++) {
  230. if (0 == strncmp(*p, "Malloc", 6) || 0 == strncmp(*p, "DYLD", 4) ||
  231. 0 == strncmp(*p, "NSZombiesEnabled", 16))
  232. {
  233. maybeMallocDebugging = true;
  234. }
  235. if (0 != strncmp(*p, "OBJC_", 5)) continue;
  236. if (0 == strncmp(*p, "OBJC_HELP=", 10)) {
  237. PrintHelp = true;
  238. continue;
  239. }
  240. if (0 == strncmp(*p, "OBJC_PRINT_OPTIONS=", 19)) {
  241. PrintOptions = true;
  242. continue;
  243. }
  244. const char *value = strchr(*p, '=');
  245. if (!*value) continue;
  246. value++;
  247. for (size_t i = 0; i < sizeof(Settings)/sizeof(Settings[0]); i++) {
  248. const option_t *opt = &Settings[i];
  249. if ((size_t)(value - *p) == 1+opt->envlen &&
  250. 0 == strncmp(*p, opt->env, opt->envlen))
  251. {
  252. *opt->var = (0 == strcmp(value, "YES"));
  253. break;
  254. }
  255. }
  256. }
  257. // Special case: enable some autorelease pool debugging
  258. // when some malloc debugging is enabled
  259. // and OBJC_DEBUG_POOL_ALLOCATION is not set to something other than NO.
  260. if (maybeMallocDebugging) {
  261. const char *insert = getenv("DYLD_INSERT_LIBRARIES");
  262. const char *zombie = getenv("NSZombiesEnabled");
  263. const char *pooldebug = getenv("OBJC_DEBUG_POOL_ALLOCATION");
  264. if ((getenv("MallocStackLogging")
  265. || getenv("MallocStackLoggingNoCompact")
  266. || (zombie && (*zombie == 'Y' || *zombie == 'y'))
  267. || (insert && strstr(insert, "libgmalloc")))
  268. &&
  269. (!pooldebug || 0 == strcmp(pooldebug, "YES")))
  270. {
  271. DebugPoolAllocation = true;
  272. }
  273. }
  274. // Print OBJC_HELP and OBJC_PRINT_OPTIONS output.
  275. if (PrintHelp || PrintOptions) {
  276. if (PrintHelp) {
  277. _objc_inform("Objective-C runtime debugging. Set variable=YES to enable.");
  278. _objc_inform("OBJC_HELP: describe available environment variables");
  279. if (PrintOptions) {
  280. _objc_inform("OBJC_HELP is set");
  281. }
  282. _objc_inform("OBJC_PRINT_OPTIONS: list which options are set");
  283. }
  284. if (PrintOptions) {
  285. _objc_inform("OBJC_PRINT_OPTIONS is set");
  286. }
  287. for (size_t i = 0; i < sizeof(Settings)/sizeof(Settings[0]); i++) {
  288. const option_t *opt = &Settings[i];
  289. if (PrintHelp) _objc_inform("%s: %s", opt->env, opt->help);
  290. if (PrintOptions && *opt->var) _objc_inform("%s is set", opt->env);
  291. }
  292. }
  293. }
  294. /***********************************************************************
  295. * logReplacedMethod
  296. * OBJC_PRINT_REPLACED_METHODS implementation
  297. **********************************************************************/
  298. void
  299. logReplacedMethod(const char *className, SEL s,
  300. bool isMeta, const char *catName,
  301. IMP oldImp, IMP newImp)
  302. {
  303. const char *oldImage = "??";
  304. const char *newImage = "??";
  305. // Silently ignore +load replacement because category +load is special
  306. if (s == SEL_load) return;
  307. #if TARGET_OS_WIN32
  308. // don't know dladdr()/dli_fname equivalent
  309. #else
  310. Dl_info dl;
  311. if (dladdr((void*)oldImp, &dl) && dl.dli_fname) oldImage = dl.dli_fname;
  312. if (dladdr((void*)newImp, &dl) && dl.dli_fname) newImage = dl.dli_fname;
  313. #endif
  314. _objc_inform("REPLACED: %c[%s %s] %s%s (IMP was %p (%s), now %p (%s))",
  315. isMeta ? '+' : '-', className, sel_getName(s),
  316. catName ? "by category " : "", catName ? catName : "",
  317. oldImp, oldImage, newImp, newImage);
  318. }
  319. /***********************************************************************
  320. * _objc_fetch_pthread_data
  321. * Fetch objc's pthread data for this thread.
  322. * If the data doesn't exist yet and create is NO, return NULL.
  323. * If the data doesn't exist yet and create is YES, allocate and return it.
  324. **********************************************************************/
  325. _objc_pthread_data *_objc_fetch_pthread_data(bool create)
  326. {
  327. _objc_pthread_data *data;
  328. data = (_objc_pthread_data *)tls_get(_objc_pthread_key);
  329. if (!data && create) {
  330. data = (_objc_pthread_data *)
  331. calloc(1, sizeof(_objc_pthread_data));
  332. tls_set(_objc_pthread_key, data);
  333. }
  334. return data;
  335. }
  336. /***********************************************************************
  337. * _objc_pthread_destroyspecific
  338. * Destructor for objc's per-thread data.
  339. * arg shouldn't be NULL, but we check anyway.
  340. **********************************************************************/
  341. extern void _destroyInitializingClassList(struct _objc_initializing_classes *list);
  342. void _objc_pthread_destroyspecific(void *arg)
  343. {
  344. _objc_pthread_data *data = (_objc_pthread_data *)arg;
  345. if (data != NULL) {
  346. _destroyInitializingClassList(data->initializingClasses);
  347. _destroySyncCache(data->syncCache);
  348. _destroyAltHandlerList(data->handlerList);
  349. for (int i = 0; i < (int)countof(data->printableNames); i++) {
  350. if (data->printableNames[i]) {
  351. free(data->printableNames[i]);
  352. }
  353. }
  354. // add further cleanup here...
  355. free(data);
  356. }
  357. }
  358. void tls_init(void)
  359. {
  360. #if SUPPORT_DIRECT_THREAD_KEYS
  361. _objc_pthread_key = TLS_DIRECT_KEY;
  362. pthread_key_init_np(TLS_DIRECT_KEY, &_objc_pthread_destroyspecific);
  363. #else
  364. _objc_pthread_key = tls_create(&_objc_pthread_destroyspecific);
  365. #endif
  366. }
  367. /***********************************************************************
  368. * _objcInit
  369. * Former library initializer. This function is now merely a placeholder
  370. * for external callers. All runtime initialization has now been moved
  371. * to map_images() and _objc_init.
  372. **********************************************************************/
  373. void _objcInit(void)
  374. {
  375. // do nothing
  376. }
  377. /***********************************************************************
  378. * objc_setForwardHandler
  379. **********************************************************************/
  380. #if !__OBJC2__
  381. // Default forward handler (nil) goes to forward:: dispatch.
  382. void *_objc_forward_handler = nil;
  383. void *_objc_forward_stret_handler = nil;
  384. #else
  385. // Default forward handler halts the process.
  386. __attribute__((noreturn)) void
  387. objc_defaultForwardHandler(id self, SEL sel)
  388. {
  389. _objc_fatal("%c[%s %s]: unrecognized selector sent to instance %p "
  390. "(no message forward handler is installed)",
  391. class_isMetaClass(object_getClass(self)) ? '+' : '-',
  392. object_getClassName(self), sel_getName(sel), self);
  393. }
  394. void *_objc_forward_handler = (void*)objc_defaultForwardHandler;
  395. #if SUPPORT_STRET
  396. struct stret { int i[100]; };
  397. __attribute__((noreturn)) struct stret
  398. objc_defaultForwardStretHandler(id self, SEL sel)
  399. {
  400. objc_defaultForwardHandler(self, sel);
  401. }
  402. void *_objc_forward_stret_handler = (void*)objc_defaultForwardStretHandler;
  403. #endif
  404. #endif
  405. void objc_setForwardHandler(void *fwd, void *fwd_stret)
  406. {
  407. _objc_forward_handler = fwd;
  408. #if SUPPORT_STRET
  409. _objc_forward_stret_handler = fwd_stret;
  410. #endif
  411. }
  412. #if !__OBJC2__
  413. // GrP fixme
  414. extern "C" Class _objc_getOrigClass(const char *name);
  415. #endif
  416. static BOOL internal_class_getImageName(Class cls, const char **outName)
  417. {
  418. #if !__OBJC2__
  419. cls = _objc_getOrigClass(cls->demangledName());
  420. #endif
  421. auto result = dyld_image_path_containing_address(cls);
  422. *outName = result;
  423. return (result != nil);
  424. }
  425. static ChainedHookFunction<objc_hook_getImageName>
  426. GetImageNameHook{internal_class_getImageName};
  427. void objc_setHook_getImageName(objc_hook_getImageName newValue,
  428. objc_hook_getImageName *outOldValue)
  429. {
  430. GetImageNameHook.set(newValue, outOldValue);
  431. }
  432. const char *class_getImageName(Class cls)
  433. {
  434. if (!cls) return nil;
  435. const char *name;
  436. if (GetImageNameHook.get()(cls, &name)) return name;
  437. else return nil;
  438. }
  439. /**********************************************************************
  440. * Fast Enumeration Support
  441. **********************************************************************/
  442. static void (*enumerationMutationHandler)(id);
  443. /**********************************************************************
  444. * objc_enumerationMutation
  445. * called by compiler when a mutation is detected during foreach iteration
  446. **********************************************************************/
  447. void objc_enumerationMutation(id object) {
  448. if (enumerationMutationHandler == nil) {
  449. _objc_fatal("mutation detected during 'for(... in ...)' enumeration of object %p.", (void*)object);
  450. }
  451. (*enumerationMutationHandler)(object);
  452. }
  453. /**********************************************************************
  454. * objc_setEnumerationMutationHandler
  455. * an entry point to customize mutation error handing
  456. **********************************************************************/
  457. void objc_setEnumerationMutationHandler(void (*handler)(id)) {
  458. enumerationMutationHandler = handler;
  459. }
  460. /**********************************************************************
  461. * Associative Reference Support
  462. **********************************************************************/
  463. id objc_getAssociatedObject(id object, const void *key) {
  464. return _object_get_associative_reference(object, (void *)key);
  465. }
  466. void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy) {
  467. _object_set_associative_reference(object, (void *)key, value, policy);
  468. }
  469. void objc_removeAssociatedObjects(id object)
  470. {
  471. if (object && object->hasAssociatedObjects()) {
  472. _object_remove_assocations(object);
  473. }
  474. }
  475. #if SUPPORT_GC_COMPAT
  476. #include <mach-o/fat.h>
  477. // GC preflight for an app executable.
  478. enum GCness {
  479. WithGC = 1,
  480. WithoutGC = 0,
  481. Error = -1
  482. };
  483. // Overloaded template wrappers around clang's overflow-checked arithmetic.
  484. template <typename T> bool uadd_overflow(T x, T y, T* sum);
  485. template <typename T> bool usub_overflow(T x, T y, T* diff);
  486. template <typename T> bool umul_overflow(T x, T y, T* prod);
  487. template <typename T> bool sadd_overflow(T x, T y, T* sum);
  488. template <typename T> bool ssub_overflow(T x, T y, T* diff);
  489. template <typename T> bool smul_overflow(T x, T y, T* prod);
  490. template <> bool uadd_overflow(unsigned x, unsigned y, unsigned* sum) { return __builtin_uadd_overflow(x, y, sum); }
  491. template <> bool uadd_overflow(unsigned long x, unsigned long y, unsigned long* sum) { return __builtin_uaddl_overflow(x, y, sum); }
  492. template <> bool uadd_overflow(unsigned long long x, unsigned long long y, unsigned long long* sum) { return __builtin_uaddll_overflow(x, y, sum); }
  493. template <> bool usub_overflow(unsigned x, unsigned y, unsigned* diff) { return __builtin_usub_overflow(x, y, diff); }
  494. template <> bool usub_overflow(unsigned long x, unsigned long y, unsigned long* diff) { return __builtin_usubl_overflow(x, y, diff); }
  495. template <> bool usub_overflow(unsigned long long x, unsigned long long y, unsigned long long* diff) { return __builtin_usubll_overflow(x, y, diff); }
  496. template <> bool umul_overflow(unsigned x, unsigned y, unsigned* prod) { return __builtin_umul_overflow(x, y, prod); }
  497. template <> bool umul_overflow(unsigned long x, unsigned long y, unsigned long* prod) { return __builtin_umull_overflow(x, y, prod); }
  498. template <> bool umul_overflow(unsigned long long x, unsigned long long y, unsigned long long* prod) { return __builtin_umulll_overflow(x, y, prod); }
  499. template <> bool sadd_overflow(signed x, signed y, signed* sum) { return __builtin_sadd_overflow(x, y, sum); }
  500. template <> bool sadd_overflow(signed long x, signed long y, signed long* sum) { return __builtin_saddl_overflow(x, y, sum); }
  501. template <> bool sadd_overflow(signed long long x, signed long long y, signed long long* sum) { return __builtin_saddll_overflow(x, y, sum); }
  502. template <> bool ssub_overflow(signed x, signed y, signed* diff) { return __builtin_ssub_overflow(x, y, diff); }
  503. template <> bool ssub_overflow(signed long x, signed long y, signed long* diff) { return __builtin_ssubl_overflow(x, y, diff); }
  504. template <> bool ssub_overflow(signed long long x, signed long long y, signed long long* diff) { return __builtin_ssubll_overflow(x, y, diff); }
  505. template <> bool smul_overflow(signed x, signed y, signed* prod) { return __builtin_smul_overflow(x, y, prod); }
  506. template <> bool smul_overflow(signed long x, signed long y, signed long* prod) { return __builtin_smull_overflow(x, y, prod); }
  507. template <> bool smul_overflow(signed long long x, signed long long y, signed long long* prod) { return __builtin_smulll_overflow(x, y, prod); }
  508. // Range-checking subview of a file.
  509. class FileSlice {
  510. int fd;
  511. uint64_t sliceOffset;
  512. uint64_t sliceSize;
  513. public:
  514. FileSlice() : fd(-1), sliceOffset(0), sliceSize(0) { }
  515. FileSlice(int newfd, uint64_t newOffset, uint64_t newSize)
  516. : fd(newfd) , sliceOffset(newOffset) , sliceSize(newSize) { }
  517. // Read bytes from this slice.
  518. // Returns YES if all bytes were read successfully.
  519. bool pread(void *buf, uint64_t readSize, uint64_t readOffset = 0) {
  520. uint64_t readEnd;
  521. if (uadd_overflow(readOffset, readSize, &readEnd)) return NO;
  522. if (readEnd > sliceSize) return NO;
  523. uint64_t preadOffset;
  524. if (uadd_overflow(sliceOffset, readOffset, &preadOffset)) return NO;
  525. int64_t readed = ::pread(fd, buf, (size_t)readSize, preadOffset);
  526. if (readed < 0 || (uint64_t)readed != readSize) return NO;
  527. return YES;
  528. }
  529. // Create a new slice that is a subset of this slice.
  530. // Returnes YES if successful.
  531. bool slice(uint64_t newOffset, uint64_t newSize, FileSlice& result) {
  532. // fixme arithmetic overflow
  533. uint64_t newEnd;
  534. if (uadd_overflow(newOffset, newSize, &newEnd)) return NO;
  535. if (newEnd > sliceSize) return NO;
  536. if (uadd_overflow(sliceOffset, newOffset, &result.sliceOffset)) {
  537. return NO;
  538. }
  539. result.sliceSize = newSize;
  540. result.fd = fd;
  541. return YES;
  542. }
  543. // Shorten this slice in place by removing a range from the start.
  544. bool advance(uint64_t distance) {
  545. if (distance > sliceSize) return NO;
  546. if (uadd_overflow(sliceOffset, distance, &sliceOffset)) return NO;
  547. if (usub_overflow(sliceSize, distance, &sliceSize)) return NO;
  548. return YES;
  549. }
  550. };
  551. // Arch32 and Arch64 are used to specialize sliceRequiresGC()
  552. // to interrogate old-ABI i386 and new-ABI x86_64 files.
  553. struct Arch32 {
  554. using mh_t = struct mach_header;
  555. using segment_command_t = struct segment_command;
  556. using section_t = struct section;
  557. enum : cpu_type_t { cputype = CPU_TYPE_X86 };
  558. enum : int { segment_cmd = LC_SEGMENT };
  559. static bool isObjCSegment(const char *segname) {
  560. return segnameEquals(segname, "__OBJC");
  561. }
  562. static bool isImageInfoSection(const char *sectname) {
  563. return sectnameEquals(sectname, "__image_info");
  564. }
  565. static bool countClasses(FileSlice file, section_t& sect,
  566. int& classCount, int& classrefCount)
  567. {
  568. if (sectnameEquals(sect.sectname, "__cls_refs")) {
  569. classrefCount += sect.size / 4;
  570. }
  571. else if (sectnameEquals(sect.sectname, "__module_info")) {
  572. struct module_t {
  573. uint32_t version;
  574. uint32_t size;
  575. uint32_t name; // not bound
  576. uint32_t symtab; // not bound
  577. };
  578. size_t mod_count = sect.size / sizeof(module_t);
  579. if (mod_count == 0) {
  580. // no classes defined
  581. } else if (mod_count > 1) {
  582. // AppleScriptObjC apps only have one module.
  583. // Disqualify this app by setting classCount to non-zero.
  584. // We don't actually need an accurate count.
  585. classCount = 1;
  586. } else if (mod_count == 1) {
  587. FileSlice moduleSlice;
  588. if (!file.slice(sect.offset, sect.size, moduleSlice)) return NO;
  589. module_t module;
  590. if (!moduleSlice.pread(&module, sizeof(module))) return NO;
  591. if (module.symtab) {
  592. // AppleScriptObjC apps only have a module with no symtab.
  593. // Disqualify this app by setting classCount to non-zero.
  594. // We don't actually need an accurate count.
  595. classCount = 1;
  596. }
  597. }
  598. }
  599. return YES;
  600. }
  601. };
  602. struct Arch64 {
  603. using mh_t = struct mach_header_64;
  604. using segment_command_t = struct segment_command_64;
  605. using section_t = struct section_64;
  606. enum : cpu_type_t { cputype = CPU_TYPE_X86_64 };
  607. enum : int { segment_cmd = LC_SEGMENT_64 };
  608. static bool isObjCSegment(const char *segname) {
  609. return
  610. segnameEquals(segname, "__DATA") ||
  611. segnameEquals(segname, "__DATA_CONST") ||
  612. segnameEquals(segname, "__DATA_DIRTY");
  613. }
  614. static bool isImageInfoSection(const char *sectname) {
  615. return sectnameEquals(sectname, "__objc_imageinfo");
  616. }
  617. static bool countClasses(FileSlice, section_t& sect,
  618. int& classCount, int& classrefCount)
  619. {
  620. if (sectnameEquals(sect.sectname, "__objc_classlist")) {
  621. classCount += sect.size / 8;
  622. }
  623. else if (sectnameEquals(sect.sectname, "__objc_classrefs")) {
  624. classrefCount += sect.size / 8;
  625. }
  626. return YES;
  627. }
  628. };
  629. #define SANE_HEADER_SIZE (32*1024)
  630. template <typename Arch>
  631. static int sliceRequiresGC(typename Arch::mh_t mh, FileSlice file)
  632. {
  633. // We assume there is only one arch per pointer size that can support GC.
  634. // (i386 and x86_64)
  635. if (mh.cputype != Arch::cputype) return 0;
  636. // We only check the main executable.
  637. if (mh.filetype != MH_EXECUTE) return 0;
  638. // Look for ObjC segment.
  639. // Look for AppleScriptObjC linkage.
  640. FileSlice cmds;
  641. if (!file.slice(sizeof(mh), mh.sizeofcmds, cmds)) return Error;
  642. // Exception: Some AppleScriptObjC apps built for GC can run without GC.
  643. // 1. executable defines no classes
  644. // 2. executable references NSBundle only
  645. // 3. executable links to AppleScriptObjC.framework
  646. // Note that shouldRejectGCApp() also knows about this.
  647. bool wantsGC = NO;
  648. bool linksToAppleScriptObjC = NO;
  649. int classCount = 0;
  650. int classrefCount = 0;
  651. // Disallow abusively-large executables that could hang this checker.
  652. // dyld performs similar checks (MAX_MACH_O_HEADER_AND_LOAD_COMMANDS_SIZE)
  653. if (mh.sizeofcmds > SANE_HEADER_SIZE) return Error;
  654. if (mh.ncmds > mh.sizeofcmds / sizeof(struct load_command)) return Error;
  655. for (uint32_t cmdindex = 0; cmdindex < mh.ncmds; cmdindex++) {
  656. struct load_command lc;
  657. if (!cmds.pread(&lc, sizeof(lc))) return Error;
  658. // Disallow abusively-small load commands that could hang this checker.
  659. // dyld performs a similar check.
  660. if (lc.cmdsize < sizeof(lc)) return Error;
  661. if (lc.cmd == LC_LOAD_DYLIB || lc.cmd == LC_LOAD_UPWARD_DYLIB ||
  662. lc.cmd == LC_LOAD_WEAK_DYLIB || lc.cmd == LC_REEXPORT_DYLIB)
  663. {
  664. // Look for AppleScriptObjC linkage.
  665. FileSlice dylibSlice;
  666. if (!cmds.slice(0, lc.cmdsize, dylibSlice)) return Error;
  667. struct dylib_command dylib;
  668. if (!dylibSlice.pread(&dylib, sizeof(dylib))) return Error;
  669. const char *asoFramework =
  670. "/System/Library/Frameworks/AppleScriptObjC.framework"
  671. "/Versions/A/AppleScriptObjC";
  672. size_t asoLen = strlen(asoFramework);
  673. FileSlice nameSlice;
  674. if (dylibSlice.slice(dylib.dylib.name.offset, asoLen, nameSlice)) {
  675. char name[asoLen];
  676. if (!nameSlice.pread(name, asoLen)) return Error;
  677. if (0 == memcmp(name, asoFramework, asoLen)) {
  678. linksToAppleScriptObjC = YES;
  679. }
  680. }
  681. }
  682. else if (lc.cmd == Arch::segment_cmd) {
  683. typename Arch::segment_command_t seg;
  684. if (!cmds.pread(&seg, sizeof(seg))) return Error;
  685. if (Arch::isObjCSegment(seg.segname)) {
  686. // ObjC segment.
  687. // Look for image info section.
  688. // Look for class implementations and class references.
  689. FileSlice sections;
  690. if (!cmds.slice(0, seg.cmdsize, sections)) return Error;
  691. if (!sections.advance(sizeof(seg))) return Error;
  692. for (uint32_t segindex = 0; segindex < seg.nsects; segindex++) {
  693. typename Arch::section_t sect;
  694. if (!sections.pread(&sect, sizeof(sect))) return Error;
  695. if (!Arch::isObjCSegment(sect.segname)) return Error;
  696. if (!Arch::countClasses(file, sect,
  697. classCount, classrefCount))
  698. {
  699. return Error;
  700. }
  701. if ((sect.flags & SECTION_TYPE) == S_REGULAR &&
  702. Arch::isImageInfoSection(sect.sectname))
  703. {
  704. // ObjC image info section.
  705. // Check its contents.
  706. FileSlice section;
  707. if (!file.slice(sect.offset, sect.size, section)) {
  708. return Error;
  709. }
  710. // The subset of objc_image_info that was in use for GC.
  711. struct {
  712. uint32_t version;
  713. uint32_t flags;
  714. } ii;
  715. if (!section.pread(&ii, sizeof(ii))) return Error;
  716. if (ii.flags & (1<<1)) {
  717. // App wants GC.
  718. // Don't return yet because we need to
  719. // check the AppleScriptObjC exception.
  720. wantsGC = YES;
  721. }
  722. }
  723. if (!sections.advance(sizeof(sect))) return Error;
  724. }
  725. }
  726. }
  727. if (!cmds.advance(lc.cmdsize)) return Error;
  728. }
  729. if (!wantsGC) {
  730. // No GC bit set.
  731. return WithoutGC;
  732. }
  733. else if (linksToAppleScriptObjC && classCount == 0 && classrefCount == 1) {
  734. // Has GC bit but falls under the AppleScriptObjC exception.
  735. return WithoutGC;
  736. }
  737. else {
  738. // Has GC bit and is not AppleScriptObjC.
  739. return WithGC;
  740. }
  741. }
  742. static int sliceRequiresGC(FileSlice file)
  743. {
  744. // Read mach-o header.
  745. struct mach_header_64 mh;
  746. if (!file.pread(&mh, sizeof(mh))) return Error;
  747. // Check header magic. We assume only host-endian slices can support GC.
  748. switch (mh.magic) {
  749. case MH_MAGIC:
  750. return sliceRequiresGC<Arch32>(*(struct mach_header *)&mh, file);
  751. case MH_MAGIC_64:
  752. return sliceRequiresGC<Arch64>(mh, file);
  753. default:
  754. return WithoutGC;
  755. }
  756. }
  757. // Returns 1 if any slice requires GC.
  758. // Returns 0 if no slice requires GC.
  759. // Returns -1 on any I/O or file format error.
  760. int objc_appRequiresGC(int fd)
  761. {
  762. struct stat st;
  763. if (fstat(fd, &st) < 0) return Error;
  764. FileSlice file(fd, 0, st.st_size);
  765. // Read fat header, if any.
  766. struct fat_header fh;
  767. if (! file.pread(&fh, sizeof(fh))) return Error;
  768. int result;
  769. if (OSSwapBigToHostInt32(fh.magic) == FAT_MAGIC) {
  770. // Fat header.
  771. size_t nfat_arch = OSSwapBigToHostInt32(fh.nfat_arch);
  772. // Disallow abusively-large files that could hang this checker.
  773. if (nfat_arch > SANE_HEADER_SIZE/sizeof(struct fat_arch)) return Error;
  774. size_t fat_size;
  775. if (umul_overflow(nfat_arch, sizeof(struct fat_arch), &fat_size)) {
  776. return Error;
  777. }
  778. FileSlice archlist;
  779. if (!file.slice(sizeof(fh), fat_size, archlist)) return Error;
  780. result = WithoutGC;
  781. for (size_t i = 0; i < nfat_arch; i++) {
  782. struct fat_arch fa;
  783. if (!archlist.pread(&fa, sizeof(fa))) return Error;
  784. if (!archlist.advance(sizeof(fa))) return Error;
  785. FileSlice thin;
  786. if (!file.slice(OSSwapBigToHostInt32(fa.offset),
  787. OSSwapBigToHostInt32(fa.size), thin))
  788. {
  789. return Error;
  790. }
  791. switch (sliceRequiresGC(thin)) {
  792. case WithoutGC: break; // no change
  793. case WithGC: if (result != Error) result = WithGC; break;
  794. case Error: result = Error; break;
  795. }
  796. }
  797. }
  798. else {
  799. // Thin header or not a header.
  800. result = sliceRequiresGC(file);
  801. }
  802. return result;
  803. }
  804. // SUPPORT_GC_COMPAT
  805. #endif