objc-runtime.mm 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084
  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 "objc-file.h"
  35. #include "message.h"
  36. /***********************************************************************
  37. * Exports.
  38. **********************************************************************/
  39. /* Linker metadata symbols */
  40. // NSObject was in Foundation/CF on macOS < 10.8.
  41. #if TARGET_OS_OSX
  42. #if __OBJC2__
  43. const char __objc_nsobject_class_10_5 = 0;
  44. const char __objc_nsobject_class_10_6 = 0;
  45. const char __objc_nsobject_class_10_7 = 0;
  46. const char __objc_nsobject_metaclass_10_5 = 0;
  47. const char __objc_nsobject_metaclass_10_6 = 0;
  48. const char __objc_nsobject_metaclass_10_7 = 0;
  49. const char __objc_nsobject_isa_10_5 = 0;
  50. const char __objc_nsobject_isa_10_6 = 0;
  51. const char __objc_nsobject_isa_10_7 = 0;
  52. #else
  53. const char __objc_nsobject_class_10_5 = 0;
  54. const char __objc_nsobject_class_10_6 = 0;
  55. const char __objc_nsobject_class_10_7 = 0;
  56. #endif
  57. #endif
  58. // Settings from environment variables
  59. #define OPTION(var, env, help) bool var = false;
  60. #include "objc-env.h"
  61. #undef OPTION
  62. struct option_t {
  63. bool* var;
  64. const char *env;
  65. const char *help;
  66. size_t envlen;
  67. };
  68. const option_t Settings[] = {
  69. #define OPTION(var, env, help) option_t{&var, #env, help, strlen(#env)},
  70. #include "objc-env.h"
  71. #undef OPTION
  72. };
  73. // objc's key for pthread_getspecific
  74. #if SUPPORT_DIRECT_THREAD_KEYS
  75. #define _objc_pthread_key TLS_DIRECT_KEY
  76. #else
  77. static tls_key_t _objc_pthread_key;
  78. #endif
  79. // Selectors
  80. SEL SEL_cxx_construct = NULL;
  81. SEL SEL_cxx_destruct = NULL;
  82. struct objc::SafeRanges objc::dataSegmentsRanges;
  83. header_info *FirstHeader = 0; // NULL means empty list
  84. header_info *LastHeader = 0; // NULL means invalid; recompute it
  85. // Set to true on the child side of fork()
  86. // if the parent process was multithreaded when fork() was called.
  87. bool MultithreadedForkChild = false;
  88. /***********************************************************************
  89. * objc_noop_imp. Used when we need to install a do-nothing method somewhere.
  90. **********************************************************************/
  91. id objc_noop_imp(id self, SEL _cmd __unused) {
  92. return self;
  93. }
  94. /***********************************************************************
  95. * _objc_isDebugBuild. Defined in debug builds only.
  96. * Some test code looks for the presence of this symbol.
  97. **********************************************************************/
  98. #if DEBUG != OBJC_IS_DEBUG_BUILD
  99. // #error mismatch in debug-ness macros
  100. // DEBUG is used in our code. OBJC_IS_DEBUG_BUILD is used in the
  101. // header declaration of _objc_isDebugBuild() because that header
  102. // is visible to other clients who might have their own DEBUG macro.
  103. #endif
  104. #if OBJC_IS_DEBUG_BUILD
  105. void _objc_isDebugBuild(void) { }
  106. #endif
  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. * objc::SafeRanges::find. Find an image data segment that contains address
  162. **********************************************************************/
  163. bool
  164. objc::SafeRanges::find(uintptr_t ptr, uint32_t &pos)
  165. {
  166. if (!sorted) {
  167. std::sort(ranges, ranges + count, [](const Range &s1, const Range &s2){
  168. return s1.start < s2.start;
  169. });
  170. sorted = true;
  171. }
  172. uint32_t l = 0, r = count;
  173. while (l < r) {
  174. uint32_t i = (l + r) / 2;
  175. if (ptr < ranges[i].start) {
  176. r = i;
  177. } else if (ptr >= ranges[i].end) {
  178. l = i + 1;
  179. } else {
  180. pos = i;
  181. return true;
  182. }
  183. }
  184. pos = UINT32_MAX;
  185. return false;
  186. }
  187. /***********************************************************************
  188. * objc::SafeRanges::add. Register a new well known data segment.
  189. **********************************************************************/
  190. void
  191. objc::SafeRanges::add(uintptr_t start, uintptr_t end)
  192. {
  193. if (count == size) {
  194. // Have a typical malloc growth:
  195. // - size <= 32: grow by 4
  196. // - size <= 64: grow by 8
  197. // - size <= 128: grow by 16
  198. // ... etc
  199. size += size < 16 ? 4 : 1 << (fls(size) - 3);
  200. ranges = (Range *)realloc(ranges, sizeof(Range) * size);
  201. }
  202. ranges[count++] = Range{ start, end };
  203. sorted = false;
  204. }
  205. /***********************************************************************
  206. * objc::SafeRanges::remove. Remove a previously known data segment.
  207. **********************************************************************/
  208. void
  209. objc::SafeRanges::remove(uintptr_t start, uintptr_t end)
  210. {
  211. uint32_t pos;
  212. if (!find(start, pos) || ranges[pos].end != end) {
  213. _objc_fatal("Cannot find range %#lx..%#lx", start, end);
  214. }
  215. if (pos < --count) {
  216. ranges[pos] = ranges[count];
  217. sorted = false;
  218. }
  219. }
  220. /***********************************************************************
  221. * appendHeader. Add a newly-constructed header_info to the list.
  222. **********************************************************************/
  223. void appendHeader(header_info *hi)
  224. {
  225. // Add the header to the header list.
  226. // The header is appended to the list, to preserve the bottom-up order.
  227. hi->setNext(NULL);
  228. if (!FirstHeader) {
  229. // list is empty
  230. FirstHeader = LastHeader = hi;
  231. } else {
  232. if (!LastHeader) {
  233. // list is not empty, but LastHeader is invalid - recompute it
  234. LastHeader = FirstHeader;
  235. while (LastHeader->getNext()) LastHeader = LastHeader->getNext();
  236. }
  237. // LastHeader is now valid
  238. LastHeader->setNext(hi);
  239. LastHeader = hi;
  240. }
  241. #if __OBJC2__
  242. if ((hi->mhdr()->flags & MH_DYLIB_IN_CACHE) == 0) {
  243. foreach_data_segment(hi->mhdr(), [](const segmentType *seg, intptr_t slide) {
  244. uintptr_t start = (uintptr_t)seg->vmaddr + slide;
  245. objc::dataSegmentsRanges.add(start, start + seg->vmsize);
  246. });
  247. }
  248. #endif
  249. }
  250. /***********************************************************************
  251. * removeHeader
  252. * Remove the given header from the header list.
  253. * FirstHeader is updated.
  254. * LastHeader is set to NULL. Any code that uses LastHeader must
  255. * detect this NULL and recompute LastHeader by traversing the list.
  256. **********************************************************************/
  257. void removeHeader(header_info *hi)
  258. {
  259. header_info *prev = NULL;
  260. header_info *current = NULL;
  261. for (current = FirstHeader; current != NULL; current = current->getNext()) {
  262. if (current == hi) {
  263. header_info *deadHead = current;
  264. // Remove from the linked list.
  265. if (prev)
  266. prev->setNext(current->getNext());
  267. else
  268. FirstHeader = current->getNext(); // no prev so removing head
  269. // Update LastHeader if necessary.
  270. if (LastHeader == deadHead) {
  271. LastHeader = NULL; // will be recomputed next time it's used
  272. }
  273. break;
  274. }
  275. prev = current;
  276. }
  277. #if __OBJC2__
  278. if ((hi->mhdr()->flags & MH_DYLIB_IN_CACHE) == 0) {
  279. foreach_data_segment(hi->mhdr(), [](const segmentType *seg, intptr_t slide) {
  280. uintptr_t start = (uintptr_t)seg->vmaddr + slide;
  281. objc::dataSegmentsRanges.remove(start, start + seg->vmsize);
  282. });
  283. }
  284. #endif
  285. }
  286. /***********************************************************************
  287. * environ_init
  288. * Read environment variables that affect the runtime.
  289. * Also print environment variable help, if requested.
  290. **********************************************************************/
  291. void environ_init(void)
  292. {
  293. if (issetugid()) {
  294. // All environment variables are silently ignored when setuid or setgid
  295. // This includes OBJC_HELP and OBJC_PRINT_OPTIONS themselves.
  296. return;
  297. }
  298. bool PrintHelp = false;
  299. bool PrintOptions = false;
  300. bool maybeMallocDebugging = false;
  301. // Scan environ[] directly instead of calling getenv() a lot.
  302. // This optimizes the case where none are set.
  303. for (char **p = *_NSGetEnviron(); *p != nil; p++) {
  304. if (0 == strncmp(*p, "Malloc", 6) || 0 == strncmp(*p, "DYLD", 4) ||
  305. 0 == strncmp(*p, "NSZombiesEnabled", 16))
  306. {
  307. maybeMallocDebugging = true;
  308. }
  309. if (0 != strncmp(*p, "OBJC_", 5)) continue;
  310. if (0 == strncmp(*p, "OBJC_HELP=", 10)) {
  311. PrintHelp = true;
  312. continue;
  313. }
  314. if (0 == strncmp(*p, "OBJC_PRINT_OPTIONS=", 19)) {
  315. PrintOptions = true;
  316. continue;
  317. }
  318. const char *value = strchr(*p, '=');
  319. if (!*value) continue;
  320. value++;
  321. for (size_t i = 0; i < sizeof(Settings)/sizeof(Settings[0]); i++) {
  322. const option_t *opt = &Settings[i];
  323. if ((size_t)(value - *p) == 1+opt->envlen &&
  324. 0 == strncmp(*p, opt->env, opt->envlen))
  325. {
  326. *opt->var = (0 == strcmp(value, "YES"));
  327. break;
  328. }
  329. }
  330. }
  331. // Special case: enable some autorelease pool debugging
  332. // when some malloc debugging is enabled
  333. // and OBJC_DEBUG_POOL_ALLOCATION is not set to something other than NO.
  334. if (maybeMallocDebugging) {
  335. const char *insert = getenv("DYLD_INSERT_LIBRARIES");
  336. const char *zombie = getenv("NSZombiesEnabled");
  337. const char *pooldebug = getenv("OBJC_DEBUG_POOL_ALLOCATION");
  338. if ((getenv("MallocStackLogging")
  339. || getenv("MallocStackLoggingNoCompact")
  340. || (zombie && (*zombie == 'Y' || *zombie == 'y'))
  341. || (insert && strstr(insert, "libgmalloc")))
  342. &&
  343. (!pooldebug || 0 == strcmp(pooldebug, "YES")))
  344. {
  345. DebugPoolAllocation = true;
  346. }
  347. }
  348. // Print OBJC_HELP and OBJC_PRINT_OPTIONS output.
  349. if (PrintHelp || PrintOptions) {
  350. if (PrintHelp) {
  351. _objc_inform("Objective-C runtime debugging. Set variable=YES to enable.");
  352. _objc_inform("OBJC_HELP: describe available environment variables");
  353. if (PrintOptions) {
  354. _objc_inform("OBJC_HELP is set");
  355. }
  356. _objc_inform("OBJC_PRINT_OPTIONS: list which options are set");
  357. }
  358. if (PrintOptions) {
  359. _objc_inform("OBJC_PRINT_OPTIONS is set");
  360. }
  361. for (size_t i = 0; i < sizeof(Settings)/sizeof(Settings[0]); i++) {
  362. const option_t *opt = &Settings[i];
  363. if (PrintHelp) _objc_inform("%s: %s", opt->env, opt->help);
  364. if (PrintOptions && *opt->var) _objc_inform("%s is set", opt->env);
  365. }
  366. }
  367. }
  368. /***********************************************************************
  369. * logReplacedMethod
  370. * OBJC_PRINT_REPLACED_METHODS implementation
  371. **********************************************************************/
  372. void
  373. logReplacedMethod(const char *className, SEL s,
  374. bool isMeta, const char *catName,
  375. IMP oldImp, IMP newImp)
  376. {
  377. const char *oldImage = "??";
  378. const char *newImage = "??";
  379. // Silently ignore +load replacement because category +load is special
  380. if (s == @selector(load)) return;
  381. #if TARGET_OS_WIN32
  382. // don't know dladdr()/dli_fname equivalent
  383. #else
  384. Dl_info dl;
  385. if (dladdr((void*)oldImp, &dl) && dl.dli_fname) oldImage = dl.dli_fname;
  386. if (dladdr((void*)newImp, &dl) && dl.dli_fname) newImage = dl.dli_fname;
  387. #endif
  388. _objc_inform("REPLACED: %c[%s %s] %s%s (IMP was %p (%s), now %p (%s))",
  389. isMeta ? '+' : '-', className, sel_getName(s),
  390. catName ? "by category " : "", catName ? catName : "",
  391. oldImp, oldImage, newImp, newImage);
  392. }
  393. /***********************************************************************
  394. * _objc_fetch_pthread_data
  395. * Fetch objc's pthread data for this thread.
  396. * If the data doesn't exist yet and create is NO, return NULL.
  397. * If the data doesn't exist yet and create is YES, allocate and return it.
  398. **********************************************************************/
  399. _objc_pthread_data *_objc_fetch_pthread_data(bool create)
  400. {
  401. _objc_pthread_data *data;
  402. data = (_objc_pthread_data *)tls_get(_objc_pthread_key);
  403. if (!data && create) {
  404. data = (_objc_pthread_data *)
  405. calloc(1, sizeof(_objc_pthread_data));
  406. tls_set(_objc_pthread_key, data);
  407. }
  408. return data;
  409. }
  410. /***********************************************************************
  411. * _objc_pthread_destroyspecific
  412. * Destructor for objc's per-thread data.
  413. * arg shouldn't be NULL, but we check anyway.
  414. **********************************************************************/
  415. extern void _destroyInitializingClassList(struct _objc_initializing_classes *list);
  416. void _objc_pthread_destroyspecific(void *arg)
  417. {
  418. _objc_pthread_data *data = (_objc_pthread_data *)arg;
  419. if (data != NULL) {
  420. _destroyInitializingClassList(data->initializingClasses);
  421. _destroySyncCache(data->syncCache);
  422. _destroyAltHandlerList(data->handlerList);
  423. for (int i = 0; i < (int)countof(data->printableNames); i++) {
  424. if (data->printableNames[i]) {
  425. free(data->printableNames[i]);
  426. }
  427. }
  428. free(data->classNameLookups);
  429. // add further cleanup here...
  430. free(data);
  431. }
  432. }
  433. void tls_init(void)
  434. {
  435. #if SUPPORT_DIRECT_THREAD_KEYS
  436. pthread_key_init_np(TLS_DIRECT_KEY, &_objc_pthread_destroyspecific);
  437. #else
  438. _objc_pthread_key = tls_create(&_objc_pthread_destroyspecific);
  439. #endif
  440. }
  441. /***********************************************************************
  442. * _objcInit
  443. * Former library initializer. This function is now merely a placeholder
  444. * for external callers. All runtime initialization has now been moved
  445. * to map_images() and _objc_init.
  446. **********************************************************************/
  447. void _objcInit(void)
  448. {
  449. // do nothing
  450. }
  451. /***********************************************************************
  452. * objc_setForwardHandler
  453. **********************************************************************/
  454. #if !__OBJC2__
  455. // Default forward handler (nil) goes to forward:: dispatch.
  456. void *_objc_forward_handler = nil;
  457. void *_objc_forward_stret_handler = nil;
  458. #else
  459. // Default forward handler halts the process.
  460. __attribute__((noreturn, cold)) void
  461. objc_defaultForwardHandler(id self, SEL sel)
  462. {
  463. _objc_fatal("%c[%s %s]: unrecognized selector sent to instance %p "
  464. "(no message forward handler is installed)",
  465. class_isMetaClass(object_getClass(self)) ? '+' : '-',
  466. object_getClassName(self), sel_getName(sel), self);
  467. }
  468. void *_objc_forward_handler = (void*)objc_defaultForwardHandler;
  469. #if SUPPORT_STRET
  470. struct stret { int i[100]; };
  471. __attribute__((noreturn, cold)) struct stret
  472. objc_defaultForwardStretHandler(id self, SEL sel)
  473. {
  474. objc_defaultForwardHandler(self, sel);
  475. }
  476. void *_objc_forward_stret_handler = (void*)objc_defaultForwardStretHandler;
  477. #endif
  478. #endif
  479. void objc_setForwardHandler(void *fwd, void *fwd_stret)
  480. {
  481. _objc_forward_handler = fwd;
  482. #if SUPPORT_STRET
  483. _objc_forward_stret_handler = fwd_stret;
  484. #endif
  485. }
  486. #if !__OBJC2__
  487. // GrP fixme
  488. extern "C" Class _objc_getOrigClass(const char *name);
  489. #endif
  490. static BOOL internal_class_getImageName(Class cls, const char **outName)
  491. {
  492. #if !__OBJC2__
  493. cls = _objc_getOrigClass(cls->demangledName());
  494. #endif
  495. auto result = dyld_image_path_containing_address(cls);
  496. *outName = result;
  497. return (result != nil);
  498. }
  499. static ChainedHookFunction<objc_hook_getImageName>
  500. GetImageNameHook{internal_class_getImageName};
  501. void objc_setHook_getImageName(objc_hook_getImageName newValue,
  502. objc_hook_getImageName *outOldValue)
  503. {
  504. GetImageNameHook.set(newValue, outOldValue);
  505. }
  506. const char *class_getImageName(Class cls)
  507. {
  508. if (!cls) return nil;
  509. const char *name;
  510. if (GetImageNameHook.get()(cls, &name)) return name;
  511. else return nil;
  512. }
  513. /**********************************************************************
  514. * Fast Enumeration Support
  515. **********************************************************************/
  516. static void (*enumerationMutationHandler)(id);
  517. /**********************************************************************
  518. * objc_enumerationMutation
  519. * called by compiler when a mutation is detected during foreach iteration
  520. **********************************************************************/
  521. void objc_enumerationMutation(id object) {
  522. if (enumerationMutationHandler == nil) {
  523. _objc_fatal("mutation detected during 'for(... in ...)' enumeration of object %p.", (void*)object);
  524. }
  525. (*enumerationMutationHandler)(object);
  526. }
  527. /**********************************************************************
  528. * objc_setEnumerationMutationHandler
  529. * an entry point to customize mutation error handing
  530. **********************************************************************/
  531. void objc_setEnumerationMutationHandler(void (*handler)(id)) {
  532. enumerationMutationHandler = handler;
  533. }
  534. /**********************************************************************
  535. * Associative Reference Support
  536. **********************************************************************/
  537. id
  538. objc_getAssociatedObject(id object, const void *key)
  539. {
  540. return _object_get_associative_reference(object, key);
  541. }
  542. static void
  543. _base_objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
  544. {
  545. _object_set_associative_reference(object, key, value, policy);
  546. }
  547. static ChainedHookFunction<objc_hook_setAssociatedObject> SetAssocHook{_base_objc_setAssociatedObject};
  548. void
  549. objc_setHook_setAssociatedObject(objc_hook_setAssociatedObject _Nonnull newValue,
  550. objc_hook_setAssociatedObject _Nullable * _Nonnull outOldValue) {
  551. SetAssocHook.set(newValue, outOldValue);
  552. }
  553. void
  554. objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
  555. {
  556. SetAssocHook.get()(object, key, value, policy);
  557. }
  558. void objc_removeAssociatedObjects(id object)
  559. {
  560. if (object && object->hasAssociatedObjects()) {
  561. _object_remove_assocations(object);
  562. }
  563. }
  564. #if SUPPORT_GC_COMPAT
  565. #include <mach-o/fat.h>
  566. // GC preflight for an app executable.
  567. enum GCness {
  568. WithGC = 1,
  569. WithoutGC = 0,
  570. Error = -1
  571. };
  572. // Overloaded template wrappers around clang's overflow-checked arithmetic.
  573. template <typename T> bool uadd_overflow(T x, T y, T* sum);
  574. template <typename T> bool usub_overflow(T x, T y, T* diff);
  575. template <typename T> bool umul_overflow(T x, T y, T* prod);
  576. template <typename T> bool sadd_overflow(T x, T y, T* sum);
  577. template <typename T> bool ssub_overflow(T x, T y, T* diff);
  578. template <typename T> bool smul_overflow(T x, T y, T* prod);
  579. template <> bool uadd_overflow(unsigned x, unsigned y, unsigned* sum) { return __builtin_uadd_overflow(x, y, sum); }
  580. template <> bool uadd_overflow(unsigned long x, unsigned long y, unsigned long* sum) { return __builtin_uaddl_overflow(x, y, sum); }
  581. template <> bool uadd_overflow(unsigned long long x, unsigned long long y, unsigned long long* sum) { return __builtin_uaddll_overflow(x, y, sum); }
  582. template <> bool usub_overflow(unsigned x, unsigned y, unsigned* diff) { return __builtin_usub_overflow(x, y, diff); }
  583. template <> bool usub_overflow(unsigned long x, unsigned long y, unsigned long* diff) { return __builtin_usubl_overflow(x, y, diff); }
  584. template <> bool usub_overflow(unsigned long long x, unsigned long long y, unsigned long long* diff) { return __builtin_usubll_overflow(x, y, diff); }
  585. template <> bool umul_overflow(unsigned x, unsigned y, unsigned* prod) { return __builtin_umul_overflow(x, y, prod); }
  586. template <> bool umul_overflow(unsigned long x, unsigned long y, unsigned long* prod) { return __builtin_umull_overflow(x, y, prod); }
  587. template <> bool umul_overflow(unsigned long long x, unsigned long long y, unsigned long long* prod) { return __builtin_umulll_overflow(x, y, prod); }
  588. template <> bool sadd_overflow(signed x, signed y, signed* sum) { return __builtin_sadd_overflow(x, y, sum); }
  589. template <> bool sadd_overflow(signed long x, signed long y, signed long* sum) { return __builtin_saddl_overflow(x, y, sum); }
  590. template <> bool sadd_overflow(signed long long x, signed long long y, signed long long* sum) { return __builtin_saddll_overflow(x, y, sum); }
  591. template <> bool ssub_overflow(signed x, signed y, signed* diff) { return __builtin_ssub_overflow(x, y, diff); }
  592. template <> bool ssub_overflow(signed long x, signed long y, signed long* diff) { return __builtin_ssubl_overflow(x, y, diff); }
  593. template <> bool ssub_overflow(signed long long x, signed long long y, signed long long* diff) { return __builtin_ssubll_overflow(x, y, diff); }
  594. template <> bool smul_overflow(signed x, signed y, signed* prod) { return __builtin_smul_overflow(x, y, prod); }
  595. template <> bool smul_overflow(signed long x, signed long y, signed long* prod) { return __builtin_smull_overflow(x, y, prod); }
  596. template <> bool smul_overflow(signed long long x, signed long long y, signed long long* prod) { return __builtin_smulll_overflow(x, y, prod); }
  597. // Range-checking subview of a file.
  598. class FileSlice {
  599. int fd;
  600. uint64_t sliceOffset;
  601. uint64_t sliceSize;
  602. public:
  603. FileSlice() : fd(-1), sliceOffset(0), sliceSize(0) { }
  604. FileSlice(int newfd, uint64_t newOffset, uint64_t newSize)
  605. : fd(newfd) , sliceOffset(newOffset) , sliceSize(newSize) { }
  606. // Read bytes from this slice.
  607. // Returns YES if all bytes were read successfully.
  608. bool pread(void *buf, uint64_t readSize, uint64_t readOffset = 0) {
  609. uint64_t readEnd;
  610. if (uadd_overflow(readOffset, readSize, &readEnd)) return NO;
  611. if (readEnd > sliceSize) return NO;
  612. uint64_t preadOffset;
  613. if (uadd_overflow(sliceOffset, readOffset, &preadOffset)) return NO;
  614. int64_t readed = ::pread(fd, buf, (size_t)readSize, preadOffset);
  615. if (readed < 0 || (uint64_t)readed != readSize) return NO;
  616. return YES;
  617. }
  618. // Create a new slice that is a subset of this slice.
  619. // Returnes YES if successful.
  620. bool slice(uint64_t newOffset, uint64_t newSize, FileSlice& result) {
  621. // fixme arithmetic overflow
  622. uint64_t newEnd;
  623. if (uadd_overflow(newOffset, newSize, &newEnd)) return NO;
  624. if (newEnd > sliceSize) return NO;
  625. if (uadd_overflow(sliceOffset, newOffset, &result.sliceOffset)) {
  626. return NO;
  627. }
  628. result.sliceSize = newSize;
  629. result.fd = fd;
  630. return YES;
  631. }
  632. // Shorten this slice in place by removing a range from the start.
  633. bool advance(uint64_t distance) {
  634. if (distance > sliceSize) return NO;
  635. if (uadd_overflow(sliceOffset, distance, &sliceOffset)) return NO;
  636. if (usub_overflow(sliceSize, distance, &sliceSize)) return NO;
  637. return YES;
  638. }
  639. };
  640. // Arch32 and Arch64 are used to specialize sliceRequiresGC()
  641. // to interrogate old-ABI i386 and new-ABI x86_64 files.
  642. struct Arch32 {
  643. using mh_t = struct mach_header;
  644. using segment_command_t = struct segment_command;
  645. using section_t = struct section;
  646. enum : cpu_type_t { cputype = CPU_TYPE_X86 };
  647. enum : int { segment_cmd = LC_SEGMENT };
  648. static bool isObjCSegment(const char *segname) {
  649. return segnameEquals(segname, "__OBJC");
  650. }
  651. static bool isImageInfoSection(const char *sectname) {
  652. return sectnameEquals(sectname, "__image_info");
  653. }
  654. static bool countClasses(FileSlice file, section_t& sect,
  655. int& classCount, int& classrefCount)
  656. {
  657. if (sectnameEquals(sect.sectname, "__cls_refs")) {
  658. classrefCount += sect.size / 4;
  659. }
  660. else if (sectnameEquals(sect.sectname, "__module_info")) {
  661. struct module_t {
  662. uint32_t version;
  663. uint32_t size;
  664. uint32_t name; // not bound
  665. uint32_t symtab; // not bound
  666. };
  667. size_t mod_count = sect.size / sizeof(module_t);
  668. if (mod_count == 0) {
  669. // no classes defined
  670. } else if (mod_count > 1) {
  671. // AppleScriptObjC apps only have one module.
  672. // Disqualify this app by setting classCount to non-zero.
  673. // We don't actually need an accurate count.
  674. classCount = 1;
  675. } else if (mod_count == 1) {
  676. FileSlice moduleSlice;
  677. if (!file.slice(sect.offset, sect.size, moduleSlice)) return NO;
  678. module_t module;
  679. if (!moduleSlice.pread(&module, sizeof(module))) return NO;
  680. if (module.symtab) {
  681. // AppleScriptObjC apps only have a module with no symtab.
  682. // Disqualify this app by setting classCount to non-zero.
  683. // We don't actually need an accurate count.
  684. classCount = 1;
  685. }
  686. }
  687. }
  688. return YES;
  689. }
  690. };
  691. struct Arch64 {
  692. using mh_t = struct mach_header_64;
  693. using segment_command_t = struct segment_command_64;
  694. using section_t = struct section_64;
  695. enum : cpu_type_t { cputype = CPU_TYPE_X86_64 };
  696. enum : int { segment_cmd = LC_SEGMENT_64 };
  697. static bool isObjCSegment(const char *segname) {
  698. return
  699. segnameEquals(segname, "__DATA") ||
  700. segnameEquals(segname, "__DATA_CONST") ||
  701. segnameEquals(segname, "__DATA_DIRTY");
  702. }
  703. static bool isImageInfoSection(const char *sectname) {
  704. return sectnameEquals(sectname, "__objc_imageinfo");
  705. }
  706. static bool countClasses(FileSlice, section_t& sect,
  707. int& classCount, int& classrefCount)
  708. {
  709. if (sectnameEquals(sect.sectname, "__objc_classlist")) {
  710. classCount += sect.size / 8;
  711. }
  712. else if (sectnameEquals(sect.sectname, "__objc_classrefs")) {
  713. classrefCount += sect.size / 8;
  714. }
  715. return YES;
  716. }
  717. };
  718. #define SANE_HEADER_SIZE (32*1024)
  719. template <typename Arch>
  720. static int sliceRequiresGC(typename Arch::mh_t mh, FileSlice file)
  721. {
  722. // We assume there is only one arch per pointer size that can support GC.
  723. // (i386 and x86_64)
  724. if (mh.cputype != Arch::cputype) return 0;
  725. // We only check the main executable.
  726. if (mh.filetype != MH_EXECUTE) return 0;
  727. // Look for ObjC segment.
  728. // Look for AppleScriptObjC linkage.
  729. FileSlice cmds;
  730. if (!file.slice(sizeof(mh), mh.sizeofcmds, cmds)) return Error;
  731. // Exception: Some AppleScriptObjC apps built for GC can run without GC.
  732. // 1. executable defines no classes
  733. // 2. executable references NSBundle only
  734. // 3. executable links to AppleScriptObjC.framework
  735. // Note that shouldRejectGCApp() also knows about this.
  736. bool wantsGC = NO;
  737. bool linksToAppleScriptObjC = NO;
  738. int classCount = 0;
  739. int classrefCount = 0;
  740. // Disallow abusively-large executables that could hang this checker.
  741. // dyld performs similar checks (MAX_MACH_O_HEADER_AND_LOAD_COMMANDS_SIZE)
  742. if (mh.sizeofcmds > SANE_HEADER_SIZE) return Error;
  743. if (mh.ncmds > mh.sizeofcmds / sizeof(struct load_command)) return Error;
  744. for (uint32_t cmdindex = 0; cmdindex < mh.ncmds; cmdindex++) {
  745. struct load_command lc;
  746. if (!cmds.pread(&lc, sizeof(lc))) return Error;
  747. // Disallow abusively-small load commands that could hang this checker.
  748. // dyld performs a similar check.
  749. if (lc.cmdsize < sizeof(lc)) return Error;
  750. if (lc.cmd == LC_LOAD_DYLIB || lc.cmd == LC_LOAD_UPWARD_DYLIB ||
  751. lc.cmd == LC_LOAD_WEAK_DYLIB || lc.cmd == LC_REEXPORT_DYLIB)
  752. {
  753. // Look for AppleScriptObjC linkage.
  754. FileSlice dylibSlice;
  755. if (!cmds.slice(0, lc.cmdsize, dylibSlice)) return Error;
  756. struct dylib_command dylib;
  757. if (!dylibSlice.pread(&dylib, sizeof(dylib))) return Error;
  758. const char *asoFramework =
  759. "/System/Library/Frameworks/AppleScriptObjC.framework"
  760. "/Versions/A/AppleScriptObjC";
  761. size_t asoLen = strlen(asoFramework);
  762. FileSlice nameSlice;
  763. if (dylibSlice.slice(dylib.dylib.name.offset, asoLen, nameSlice)) {
  764. char name[asoLen];
  765. if (!nameSlice.pread(name, asoLen)) return Error;
  766. if (0 == memcmp(name, asoFramework, asoLen)) {
  767. linksToAppleScriptObjC = YES;
  768. }
  769. }
  770. }
  771. else if (lc.cmd == Arch::segment_cmd) {
  772. typename Arch::segment_command_t seg;
  773. if (!cmds.pread(&seg, sizeof(seg))) return Error;
  774. if (Arch::isObjCSegment(seg.segname)) {
  775. // ObjC segment.
  776. // Look for image info section.
  777. // Look for class implementations and class references.
  778. FileSlice sections;
  779. if (!cmds.slice(0, seg.cmdsize, sections)) return Error;
  780. if (!sections.advance(sizeof(seg))) return Error;
  781. for (uint32_t segindex = 0; segindex < seg.nsects; segindex++) {
  782. typename Arch::section_t sect;
  783. if (!sections.pread(&sect, sizeof(sect))) return Error;
  784. if (!Arch::isObjCSegment(sect.segname)) return Error;
  785. if (!Arch::countClasses(file, sect,
  786. classCount, classrefCount))
  787. {
  788. return Error;
  789. }
  790. if ((sect.flags & SECTION_TYPE) == S_REGULAR &&
  791. Arch::isImageInfoSection(sect.sectname))
  792. {
  793. // ObjC image info section.
  794. // Check its contents.
  795. FileSlice section;
  796. if (!file.slice(sect.offset, sect.size, section)) {
  797. return Error;
  798. }
  799. // The subset of objc_image_info that was in use for GC.
  800. struct {
  801. uint32_t version;
  802. uint32_t flags;
  803. } ii;
  804. if (!section.pread(&ii, sizeof(ii))) return Error;
  805. if (ii.flags & (1<<1)) {
  806. // App wants GC.
  807. // Don't return yet because we need to
  808. // check the AppleScriptObjC exception.
  809. wantsGC = YES;
  810. }
  811. }
  812. if (!sections.advance(sizeof(sect))) return Error;
  813. }
  814. }
  815. }
  816. if (!cmds.advance(lc.cmdsize)) return Error;
  817. }
  818. if (!wantsGC) {
  819. // No GC bit set.
  820. return WithoutGC;
  821. }
  822. else if (linksToAppleScriptObjC && classCount == 0 && classrefCount == 1) {
  823. // Has GC bit but falls under the AppleScriptObjC exception.
  824. return WithoutGC;
  825. }
  826. else {
  827. // Has GC bit and is not AppleScriptObjC.
  828. return WithGC;
  829. }
  830. }
  831. static int sliceRequiresGC(FileSlice file)
  832. {
  833. // Read mach-o header.
  834. struct mach_header_64 mh;
  835. if (!file.pread(&mh, sizeof(mh))) return Error;
  836. // Check header magic. We assume only host-endian slices can support GC.
  837. switch (mh.magic) {
  838. case MH_MAGIC:
  839. return sliceRequiresGC<Arch32>(*(struct mach_header *)&mh, file);
  840. case MH_MAGIC_64:
  841. return sliceRequiresGC<Arch64>(mh, file);
  842. default:
  843. return WithoutGC;
  844. }
  845. }
  846. // Returns 1 if any slice requires GC.
  847. // Returns 0 if no slice requires GC.
  848. // Returns -1 on any I/O or file format error.
  849. int objc_appRequiresGC(int fd)
  850. {
  851. struct stat st;
  852. if (fstat(fd, &st) < 0) return Error;
  853. FileSlice file(fd, 0, st.st_size);
  854. // Read fat header, if any.
  855. struct fat_header fh;
  856. if (! file.pread(&fh, sizeof(fh))) return Error;
  857. int result;
  858. if (OSSwapBigToHostInt32(fh.magic) == FAT_MAGIC) {
  859. // Fat header.
  860. size_t nfat_arch = OSSwapBigToHostInt32(fh.nfat_arch);
  861. // Disallow abusively-large files that could hang this checker.
  862. if (nfat_arch > SANE_HEADER_SIZE/sizeof(struct fat_arch)) return Error;
  863. size_t fat_size;
  864. if (umul_overflow(nfat_arch, sizeof(struct fat_arch), &fat_size)) {
  865. return Error;
  866. }
  867. FileSlice archlist;
  868. if (!file.slice(sizeof(fh), fat_size, archlist)) return Error;
  869. result = WithoutGC;
  870. for (size_t i = 0; i < nfat_arch; i++) {
  871. struct fat_arch fa;
  872. if (!archlist.pread(&fa, sizeof(fa))) return Error;
  873. if (!archlist.advance(sizeof(fa))) return Error;
  874. FileSlice thin;
  875. if (!file.slice(OSSwapBigToHostInt32(fa.offset),
  876. OSSwapBigToHostInt32(fa.size), thin))
  877. {
  878. return Error;
  879. }
  880. switch (sliceRequiresGC(thin)) {
  881. case WithoutGC: break; // no change
  882. case WithGC: if (result != Error) result = WithGC; break;
  883. case Error: result = Error; break;
  884. }
  885. }
  886. }
  887. else {
  888. // Thin header or not a header.
  889. result = sliceRequiresGC(file);
  890. }
  891. return result;
  892. }
  893. // SUPPORT_GC_COMPAT
  894. #endif