customrr.m 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915
  1. // These options must match customrr2.m
  2. // TEST_CONFIG MEM=mrc
  3. /*
  4. TEST_BUILD
  5. $C{COMPILE} $DIR/customrr.m -fvisibility=default -o customrr.exe -fno-objc-convert-messages-to-runtime-calls
  6. $C{COMPILE} -bundle -bundle_loader customrr.exe $DIR/customrr-cat1.m -o customrr-cat1.bundle
  7. $C{COMPILE} -bundle -bundle_loader customrr.exe $DIR/customrr-cat2.m -o customrr-cat2.bundle
  8. END
  9. */
  10. #include "test.h"
  11. #include <dlfcn.h>
  12. #include <Foundation/NSObject.h>
  13. static int Retains;
  14. static int Releases;
  15. static int Autoreleases;
  16. static int RetainCounts;
  17. static int PlusRetains;
  18. static int PlusReleases;
  19. static int PlusAutoreleases;
  20. static int PlusRetainCounts;
  21. static int Allocs;
  22. static int AllocWithZones;
  23. static int SubRetains;
  24. static int SubReleases;
  25. static int SubAutoreleases;
  26. static int SubRetainCounts;
  27. static int SubPlusRetains;
  28. static int SubPlusReleases;
  29. static int SubPlusAutoreleases;
  30. static int SubPlusRetainCounts;
  31. static int SubAllocs;
  32. static int SubAllocWithZones;
  33. static int Imps;
  34. static id imp_fn(id self, SEL _cmd __unused, ...)
  35. {
  36. Imps++;
  37. return self;
  38. }
  39. static void zero(void) {
  40. Retains = 0;
  41. Releases = 0;
  42. Autoreleases = 0;
  43. RetainCounts = 0;
  44. PlusRetains = 0;
  45. PlusReleases = 0;
  46. PlusAutoreleases = 0;
  47. PlusRetainCounts = 0;
  48. Allocs = 0;
  49. AllocWithZones = 0;
  50. SubRetains = 0;
  51. SubReleases = 0;
  52. SubAutoreleases = 0;
  53. SubRetainCounts = 0;
  54. SubPlusRetains = 0;
  55. SubPlusReleases = 0;
  56. SubPlusAutoreleases = 0;
  57. SubPlusRetainCounts = 0;
  58. SubAllocs = 0;
  59. SubAllocWithZones = 0;
  60. Imps = 0;
  61. }
  62. id HackRetain(id self, SEL _cmd __unused) { Retains++; return self; }
  63. void HackRelease(id self __unused, SEL _cmd __unused) { Releases++; }
  64. id HackAutorelease(id self, SEL _cmd __unused) { Autoreleases++; return self; }
  65. NSUInteger HackRetainCount(id self __unused, SEL _cmd __unused) { RetainCounts++; return 1; }
  66. id HackPlusRetain(id self, SEL _cmd __unused) { PlusRetains++; return self; }
  67. void HackPlusRelease(id self __unused, SEL _cmd __unused) { PlusReleases++; }
  68. id HackPlusAutorelease(id self, SEL _cmd __unused) { PlusAutoreleases++; return self; }
  69. NSUInteger HackPlusRetainCount(id self __unused, SEL _cmd __unused) { PlusRetainCounts++; return 1; }
  70. id HackAlloc(Class self, SEL _cmd __unused) { Allocs++; return class_createInstance(self, 0); }
  71. id HackAllocWithZone(Class self, SEL _cmd __unused) { AllocWithZones++; return class_createInstance(self, 0); }
  72. @interface OverridingSub : NSObject @end
  73. @implementation OverridingSub
  74. -(id) retain { SubRetains++; return self; }
  75. +(id) retain { SubPlusRetains++; return self; }
  76. -(oneway void) release { SubReleases++; }
  77. +(oneway void) release { SubPlusReleases++; }
  78. -(id) autorelease { SubAutoreleases++; return self; }
  79. +(id) autorelease { SubPlusAutoreleases++; return self; }
  80. -(NSUInteger) retainCount { SubRetainCounts++; return 1; }
  81. +(NSUInteger) retainCount { SubPlusRetainCounts++; return 1; }
  82. @end
  83. @interface OverridingASub : NSObject @end
  84. @implementation OverridingASub
  85. +(id) alloc { SubAllocs++; return class_createInstance(self, 0); }
  86. @end
  87. @interface OverridingAWZSub : NSObject @end
  88. @implementation OverridingAWZSub
  89. +(id) allocWithZone:(NSZone * __unused)z { SubAllocWithZones++; return class_createInstance(self, 0); }
  90. @end
  91. @interface OverridingAAWZSub : NSObject @end
  92. @implementation OverridingAAWZSub
  93. +(id) alloc { SubAllocs++; return class_createInstance(self, 0); }
  94. +(id) allocWithZone:(NSZone * __unused)z { SubAllocWithZones++; return class_createInstance(self, 0); }
  95. @end
  96. @interface InheritingSub : NSObject @end
  97. @implementation InheritingSub @end
  98. @interface InheritingSub2 : NSObject @end
  99. @implementation InheritingSub2 @end
  100. @interface InheritingSub2_2 : InheritingSub2 @end
  101. @implementation InheritingSub2_2 @end
  102. @interface InheritingSub3 : NSObject @end
  103. @implementation InheritingSub3 @end
  104. @interface InheritingSub3_2 : InheritingSub3 @end
  105. @implementation InheritingSub3_2 @end
  106. @interface InheritingSub4 : NSObject @end
  107. @implementation InheritingSub4 @end
  108. @interface InheritingSub4_2 : InheritingSub4 @end
  109. @implementation InheritingSub4_2 @end
  110. @interface InheritingSub5 : NSObject @end
  111. @implementation InheritingSub5 @end
  112. @interface InheritingSub5_2 : InheritingSub5 @end
  113. @implementation InheritingSub5_2 @end
  114. @interface InheritingSub6 : NSObject @end
  115. @implementation InheritingSub6 @end
  116. @interface InheritingSub6_2 : InheritingSub6 @end
  117. @implementation InheritingSub6_2 @end
  118. @interface InheritingSub7 : NSObject @end
  119. @implementation InheritingSub7 @end
  120. @interface InheritingSub7_2 : InheritingSub7 @end
  121. @implementation InheritingSub7_2 @end
  122. @interface InheritingSubCat : NSObject @end
  123. @implementation InheritingSubCat @end
  124. @interface InheritingSubCat_2 : InheritingSubCat @end
  125. @implementation InheritingSubCat_2 @end
  126. extern uintptr_t OBJC_CLASS_$_UnrealizedSubA1;
  127. @interface UnrealizedSubA1 : NSObject @end
  128. @implementation UnrealizedSubA1 @end
  129. extern uintptr_t OBJC_CLASS_$_UnrealizedSubA2;
  130. @interface UnrealizedSubA2 : NSObject @end
  131. @implementation UnrealizedSubA2 @end
  132. extern uintptr_t OBJC_CLASS_$_UnrealizedSubA3;
  133. @interface UnrealizedSubA3 : NSObject @end
  134. @implementation UnrealizedSubA3 @end
  135. extern uintptr_t OBJC_CLASS_$_UnrealizedSubB1;
  136. @interface UnrealizedSubB1 : NSObject @end
  137. @implementation UnrealizedSubB1 @end
  138. extern uintptr_t OBJC_CLASS_$_UnrealizedSubB2;
  139. @interface UnrealizedSubB2 : NSObject @end
  140. @implementation UnrealizedSubB2 @end
  141. extern uintptr_t OBJC_CLASS_$_UnrealizedSubB3;
  142. @interface UnrealizedSubB3 : NSObject @end
  143. @implementation UnrealizedSubB3 @end
  144. extern uintptr_t OBJC_CLASS_$_UnrealizedSubC1;
  145. @interface UnrealizedSubC1 : NSObject @end
  146. @implementation UnrealizedSubC1 @end
  147. extern uintptr_t OBJC_CLASS_$_UnrealizedSubC2;
  148. @interface UnrealizedSubC2 : NSObject @end
  149. @implementation UnrealizedSubC2 @end
  150. extern uintptr_t OBJC_CLASS_$_UnrealizedSubC3;
  151. @interface UnrealizedSubC3 : NSObject @end
  152. @implementation UnrealizedSubC3 @end
  153. int main(int argc __unused, char **argv)
  154. {
  155. objc_autoreleasePoolPush();
  156. // Hack NSObject's RR methods.
  157. // Don't use runtime functions to do this -
  158. // we want the runtime to think that these are NSObject's real code
  159. {
  160. #if __has_feature(ptrauth_calls)
  161. typedef IMP __ptrauth_objc_method_list_imp MethodListIMP;
  162. #else
  163. typedef IMP MethodListIMP;
  164. #endif
  165. Class cls = [NSObject class];
  166. IMP imp = class_getMethodImplementation(cls, @selector(retain));
  167. MethodListIMP *m = (MethodListIMP *)
  168. class_getInstanceMethod(cls, @selector(retain));
  169. testassert(m[2] == imp); // verify Method struct is as we expect
  170. m = (MethodListIMP *)class_getInstanceMethod(cls, @selector(retain));
  171. m[2] = (IMP)HackRetain;
  172. m = (MethodListIMP *)class_getInstanceMethod(cls, @selector(release));
  173. m[2] = (IMP)HackRelease;
  174. m = (MethodListIMP *)class_getInstanceMethod(cls, @selector(autorelease));
  175. m[2] = (IMP)HackAutorelease;
  176. m = (MethodListIMP *)class_getInstanceMethod(cls, @selector(retainCount));
  177. m[2] = (IMP)HackRetainCount;
  178. m = (MethodListIMP *)class_getClassMethod(cls, @selector(retain));
  179. m[2] = (IMP)HackPlusRetain;
  180. m = (MethodListIMP *)class_getClassMethod(cls, @selector(release));
  181. m[2] = (IMP)HackPlusRelease;
  182. m = (MethodListIMP *)class_getClassMethod(cls, @selector(autorelease));
  183. m[2] = (IMP)HackPlusAutorelease;
  184. m = (MethodListIMP *)class_getClassMethod(cls, @selector(retainCount));
  185. m[2] = (IMP)HackPlusRetainCount;
  186. m = (MethodListIMP *)class_getClassMethod(cls, @selector(alloc));
  187. m[2] = (IMP)HackAlloc;
  188. m = (MethodListIMP *)class_getClassMethod(cls, @selector(allocWithZone:));
  189. m[2] = (IMP)HackAllocWithZone;
  190. _objc_flush_caches(cls);
  191. imp = class_getMethodImplementation(cls, @selector(retain));
  192. testassert(imp == (IMP)HackRetain); // verify hack worked
  193. }
  194. Class cls = [NSObject class];
  195. Class icl = [InheritingSub class];
  196. Class ocl = [OverridingSub class];
  197. /*
  198. Class oa1 = [OverridingASub class];
  199. Class oa2 = [OverridingAWZSub class];
  200. Class oa3 = [OverridingAAWZSub class];
  201. */
  202. NSObject *obj = [NSObject new];
  203. InheritingSub *inh = [InheritingSub new];
  204. OverridingSub *ovr = [OverridingSub new];
  205. Class ccc;
  206. id ooo;
  207. Class cc2;
  208. id oo2;
  209. void *dlh;
  210. #if __x86_64__
  211. // vtable dispatch can introduce bypass just like the ARC entrypoints
  212. #else
  213. testprintf("method dispatch does not bypass\n");
  214. zero();
  215. [obj retain];
  216. testassert(Retains == 1);
  217. [obj release];
  218. testassert(Releases == 1);
  219. [obj autorelease];
  220. testassert(Autoreleases == 1);
  221. [cls retain];
  222. testassert(PlusRetains == 1);
  223. [cls release];
  224. testassert(PlusReleases == 1);
  225. [cls autorelease];
  226. testassert(PlusAutoreleases == 1);
  227. [inh retain];
  228. testassert(Retains == 2);
  229. [inh release];
  230. testassert(Releases == 2);
  231. [inh autorelease];
  232. testassert(Autoreleases == 2);
  233. [icl retain];
  234. testassert(PlusRetains == 2);
  235. [icl release];
  236. testassert(PlusReleases == 2);
  237. [icl autorelease];
  238. testassert(PlusAutoreleases == 2);
  239. [ovr retain];
  240. testassert(SubRetains == 1);
  241. [ovr release];
  242. testassert(SubReleases == 1);
  243. [ovr autorelease];
  244. testassert(SubAutoreleases == 1);
  245. [ocl retain];
  246. testassert(SubPlusRetains == 1);
  247. [ocl release];
  248. testassert(SubPlusReleases == 1);
  249. [ocl autorelease];
  250. testassert(SubPlusAutoreleases == 1);
  251. [UnrealizedSubA1 retain];
  252. testassert(PlusRetains == 3);
  253. [UnrealizedSubA2 release];
  254. testassert(PlusReleases == 3);
  255. [UnrealizedSubA3 autorelease];
  256. testassert(PlusAutoreleases == 3);
  257. #endif
  258. testprintf("objc_msgSend() does not bypass\n");
  259. zero();
  260. id (*retain_fn)(id, SEL) = (id(*)(id, SEL))objc_msgSend;
  261. void (*release_fn)(id, SEL) = (void(*)(id, SEL))objc_msgSend;
  262. id (*autorelease_fn)(id, SEL) = (id(*)(id, SEL))objc_msgSend;
  263. retain_fn(obj, @selector(retain));
  264. testassert(Retains == 1);
  265. release_fn(obj, @selector(release));
  266. testassert(Releases == 1);
  267. autorelease_fn(obj, @selector(autorelease));
  268. testassert(Autoreleases == 1);
  269. retain_fn(cls, @selector(retain));
  270. testassert(PlusRetains == 1);
  271. release_fn(cls, @selector(release));
  272. testassert(PlusReleases == 1);
  273. autorelease_fn(cls, @selector(autorelease));
  274. testassert(PlusAutoreleases == 1);
  275. retain_fn(inh, @selector(retain));
  276. testassert(Retains == 2);
  277. release_fn(inh, @selector(release));
  278. testassert(Releases == 2);
  279. autorelease_fn(inh, @selector(autorelease));
  280. testassert(Autoreleases == 2);
  281. retain_fn(icl, @selector(retain));
  282. testassert(PlusRetains == 2);
  283. release_fn(icl, @selector(release));
  284. testassert(PlusReleases == 2);
  285. autorelease_fn(icl, @selector(autorelease));
  286. testassert(PlusAutoreleases == 2);
  287. retain_fn(ovr, @selector(retain));
  288. testassert(SubRetains == 1);
  289. release_fn(ovr, @selector(release));
  290. testassert(SubReleases == 1);
  291. autorelease_fn(ovr, @selector(autorelease));
  292. testassert(SubAutoreleases == 1);
  293. retain_fn(ocl, @selector(retain));
  294. testassert(SubPlusRetains == 1);
  295. release_fn(ocl, @selector(release));
  296. testassert(SubPlusReleases == 1);
  297. autorelease_fn(ocl, @selector(autorelease));
  298. testassert(SubPlusAutoreleases == 1);
  299. retain_fn((Class)&OBJC_CLASS_$_UnrealizedSubB1, @selector(retain));
  300. testassert(PlusRetains == 3);
  301. release_fn((Class)&OBJC_CLASS_$_UnrealizedSubB2, @selector(release));
  302. testassert(PlusReleases == 3);
  303. autorelease_fn((Class)&OBJC_CLASS_$_UnrealizedSubB3, @selector(autorelease));
  304. testassert(PlusAutoreleases == 3);
  305. testprintf("arc function bypasses instance but not class or override\n");
  306. zero();
  307. objc_retain(obj);
  308. testassert(Retains == 0);
  309. objc_release(obj);
  310. testassert(Releases == 0);
  311. objc_autorelease(obj);
  312. testassert(Autoreleases == 0);
  313. #if SUPPORT_NONPOINTER_ISA
  314. objc_retain(cls);
  315. testassert(PlusRetains == 0);
  316. objc_release(cls);
  317. testassert(PlusReleases == 0);
  318. objc_autorelease(cls);
  319. testassert(PlusAutoreleases == 0);
  320. #else
  321. objc_retain(cls);
  322. testassert(PlusRetains == 1);
  323. objc_release(cls);
  324. testassert(PlusReleases == 1);
  325. objc_autorelease(cls);
  326. testassert(PlusAutoreleases == 1);
  327. #endif
  328. objc_retain(inh);
  329. testassert(Retains == 0);
  330. objc_release(inh);
  331. testassert(Releases == 0);
  332. objc_autorelease(inh);
  333. testassert(Autoreleases == 0);
  334. #if SUPPORT_NONPOINTER_ISA
  335. objc_retain(icl);
  336. testassert(PlusRetains == 0);
  337. objc_release(icl);
  338. testassert(PlusReleases == 0);
  339. objc_autorelease(icl);
  340. testassert(PlusAutoreleases == 0);
  341. #else
  342. objc_retain(icl);
  343. testassert(PlusRetains == 2);
  344. objc_release(icl);
  345. testassert(PlusReleases == 2);
  346. objc_autorelease(icl);
  347. testassert(PlusAutoreleases == 2);
  348. #endif
  349. objc_retain(ovr);
  350. testassert(SubRetains == 1);
  351. objc_release(ovr);
  352. testassert(SubReleases == 1);
  353. objc_autorelease(ovr);
  354. testassert(SubAutoreleases == 1);
  355. objc_retain(ocl);
  356. testassert(SubPlusRetains == 1);
  357. objc_release(ocl);
  358. testassert(SubPlusReleases == 1);
  359. objc_autorelease(ocl);
  360. testassert(SubPlusAutoreleases == 1);
  361. #if SUPPORT_NONPOINTER_ISA
  362. objc_retain((Class)&OBJC_CLASS_$_UnrealizedSubC1);
  363. testassert(PlusRetains == 1);
  364. objc_release((Class)&OBJC_CLASS_$_UnrealizedSubC2);
  365. testassert(PlusReleases == 1);
  366. objc_autorelease((Class)&OBJC_CLASS_$_UnrealizedSubC3);
  367. testassert(PlusAutoreleases == 1);
  368. #else
  369. objc_retain((Class)&OBJC_CLASS_$_UnrealizedSubC1);
  370. testassert(PlusRetains == 3);
  371. objc_release((Class)&OBJC_CLASS_$_UnrealizedSubC2);
  372. testassert(PlusReleases == 3);
  373. objc_autorelease((Class)&OBJC_CLASS_$_UnrealizedSubC3);
  374. testassert(PlusAutoreleases == 3);
  375. #endif
  376. testprintf("unrelated addMethod does not clobber\n");
  377. zero();
  378. class_addMethod(cls, @selector(unrelatedMethod), (IMP)imp_fn, "");
  379. objc_retain(obj);
  380. testassert(Retains == 0);
  381. objc_release(obj);
  382. testassert(Releases == 0);
  383. objc_autorelease(obj);
  384. testassert(Autoreleases == 0);
  385. testprintf("add class method does not clobber\n");
  386. zero();
  387. objc_retain(obj);
  388. testassert(Retains == 0);
  389. objc_release(obj);
  390. testassert(Releases == 0);
  391. objc_autorelease(obj);
  392. testassert(Autoreleases == 0);
  393. class_addMethod(object_getClass(cls), @selector(retain), (IMP)imp_fn, "");
  394. objc_retain(obj);
  395. testassert(Retains == 0);
  396. objc_release(obj);
  397. testassert(Releases == 0);
  398. objc_autorelease(obj);
  399. testassert(Autoreleases == 0);
  400. testprintf("addMethod clobbers (InheritingSub2, retain)\n");
  401. zero();
  402. ccc = [InheritingSub2 class];
  403. ooo = [ccc new];
  404. cc2 = [InheritingSub2_2 class];
  405. oo2 = [cc2 new];
  406. objc_retain(ooo);
  407. testassert(Retains == 0);
  408. objc_release(ooo);
  409. testassert(Releases == 0);
  410. objc_autorelease(ooo);
  411. testassert(Autoreleases == 0);
  412. objc_retain(oo2);
  413. testassert(Retains == 0);
  414. objc_release(oo2);
  415. testassert(Releases == 0);
  416. objc_autorelease(oo2);
  417. testassert(Autoreleases == 0);
  418. class_addMethod(ccc, @selector(retain), (IMP)imp_fn, "");
  419. objc_retain(ooo);
  420. testassert(Retains == 0);
  421. testassert(Imps == 1);
  422. objc_release(ooo);
  423. testassert(Releases == 1);
  424. objc_autorelease(ooo);
  425. testassert(Autoreleases == 1);
  426. objc_retain(oo2);
  427. testassert(Retains == 0);
  428. testassert(Imps == 2);
  429. objc_release(oo2);
  430. testassert(Releases == 2);
  431. objc_autorelease(oo2);
  432. testassert(Autoreleases == 2);
  433. testprintf("addMethod clobbers (InheritingSub3, release)\n");
  434. zero();
  435. ccc = [InheritingSub3 class];
  436. ooo = [ccc new];
  437. cc2 = [InheritingSub3_2 class];
  438. oo2 = [cc2 new];
  439. objc_retain(ooo);
  440. testassert(Retains == 0);
  441. objc_release(ooo);
  442. testassert(Releases == 0);
  443. objc_autorelease(ooo);
  444. testassert(Autoreleases == 0);
  445. objc_retain(oo2);
  446. testassert(Retains == 0);
  447. objc_release(oo2);
  448. testassert(Releases == 0);
  449. objc_autorelease(oo2);
  450. testassert(Autoreleases == 0);
  451. class_addMethod(ccc, @selector(release), (IMP)imp_fn, "");
  452. objc_retain(ooo);
  453. testassert(Retains == 1);
  454. objc_release(ooo);
  455. testassert(Releases == 0);
  456. testassert(Imps == 1);
  457. objc_autorelease(ooo);
  458. testassert(Autoreleases == 1);
  459. objc_retain(oo2);
  460. testassert(Retains == 2);
  461. objc_release(oo2);
  462. testassert(Releases == 0);
  463. testassert(Imps == 2);
  464. objc_autorelease(oo2);
  465. testassert(Autoreleases == 2);
  466. testprintf("addMethod clobbers (InheritingSub4, autorelease)\n");
  467. zero();
  468. ccc = [InheritingSub4 class];
  469. ooo = [ccc new];
  470. cc2 = [InheritingSub4_2 class];
  471. oo2 = [cc2 new];
  472. objc_retain(ooo);
  473. testassert(Retains == 0);
  474. objc_release(ooo);
  475. testassert(Releases == 0);
  476. objc_autorelease(ooo);
  477. testassert(Autoreleases == 0);
  478. objc_retain(oo2);
  479. testassert(Retains == 0);
  480. objc_release(oo2);
  481. testassert(Releases == 0);
  482. objc_autorelease(oo2);
  483. testassert(Autoreleases == 0);
  484. class_addMethod(ccc, @selector(autorelease), (IMP)imp_fn, "");
  485. objc_retain(ooo);
  486. testassert(Retains == 1);
  487. objc_release(ooo);
  488. testassert(Releases == 1);
  489. objc_autorelease(ooo);
  490. testassert(Autoreleases == 0);
  491. testassert(Imps == 1);
  492. objc_retain(oo2);
  493. testassert(Retains == 2);
  494. objc_release(oo2);
  495. testassert(Releases == 2);
  496. objc_autorelease(oo2);
  497. testassert(Autoreleases == 0);
  498. testassert(Imps == 2);
  499. testprintf("addMethod clobbers (InheritingSub5, retainCount)\n");
  500. zero();
  501. ccc = [InheritingSub5 class];
  502. ooo = [ccc new];
  503. cc2 = [InheritingSub5_2 class];
  504. oo2 = [cc2 new];
  505. objc_retain(ooo);
  506. testassert(Retains == 0);
  507. objc_release(ooo);
  508. testassert(Releases == 0);
  509. objc_autorelease(ooo);
  510. testassert(Autoreleases == 0);
  511. objc_retain(oo2);
  512. testassert(Retains == 0);
  513. objc_release(oo2);
  514. testassert(Releases == 0);
  515. objc_autorelease(oo2);
  516. testassert(Autoreleases == 0);
  517. class_addMethod(ccc, @selector(retainCount), (IMP)imp_fn, "");
  518. objc_retain(ooo);
  519. testassert(Retains == 1);
  520. objc_release(ooo);
  521. testassert(Releases == 1);
  522. objc_autorelease(ooo);
  523. testassert(Autoreleases == 1);
  524. // no bypassing call for -retainCount
  525. objc_retain(oo2);
  526. testassert(Retains == 2);
  527. objc_release(oo2);
  528. testassert(Releases == 2);
  529. objc_autorelease(oo2);
  530. testassert(Autoreleases == 2);
  531. // no bypassing call for -retainCount
  532. testprintf("setSuperclass to clean super does not clobber (InheritingSub6)\n");
  533. zero();
  534. ccc = [InheritingSub6 class];
  535. ooo = [ccc new];
  536. cc2 = [InheritingSub6_2 class];
  537. oo2 = [cc2 new];
  538. objc_retain(ooo);
  539. testassert(Retains == 0);
  540. objc_release(ooo);
  541. testassert(Releases == 0);
  542. objc_autorelease(ooo);
  543. testassert(Autoreleases == 0);
  544. objc_retain(oo2);
  545. testassert(Retains == 0);
  546. objc_release(oo2);
  547. testassert(Releases == 0);
  548. objc_autorelease(oo2);
  549. testassert(Autoreleases == 0);
  550. class_setSuperclass(ccc, [InheritingSub class]);
  551. objc_retain(ooo);
  552. testassert(Retains == 0);
  553. objc_release(ooo);
  554. testassert(Releases == 0);
  555. objc_autorelease(ooo);
  556. testassert(Autoreleases == 0);
  557. objc_retain(oo2);
  558. testassert(Retains == 0);
  559. objc_release(oo2);
  560. testassert(Releases == 0);
  561. objc_autorelease(oo2);
  562. testassert(Autoreleases == 0);
  563. testprintf("setSuperclass to dirty super clobbers (InheritingSub7)\n");
  564. zero();
  565. ccc = [InheritingSub7 class];
  566. ooo = [ccc new];
  567. cc2 = [InheritingSub7_2 class];
  568. oo2 = [cc2 new];
  569. objc_retain(ooo);
  570. testassert(Retains == 0);
  571. objc_release(ooo);
  572. testassert(Releases == 0);
  573. objc_autorelease(ooo);
  574. testassert(Autoreleases == 0);
  575. objc_retain(oo2);
  576. testassert(Retains == 0);
  577. objc_release(oo2);
  578. testassert(Releases == 0);
  579. objc_autorelease(oo2);
  580. testassert(Autoreleases == 0);
  581. class_setSuperclass(ccc, [OverridingSub class]);
  582. objc_retain(ooo);
  583. testassert(SubRetains == 1);
  584. objc_release(ooo);
  585. testassert(SubReleases == 1);
  586. objc_autorelease(ooo);
  587. testassert(SubAutoreleases == 1);
  588. objc_retain(oo2);
  589. testassert(SubRetains == 2);
  590. objc_release(oo2);
  591. testassert(SubReleases == 2);
  592. objc_autorelease(oo2);
  593. testassert(SubAutoreleases == 2);
  594. testprintf("category replacement of unrelated method does not clobber (InheritingSubCat)\n");
  595. zero();
  596. ccc = [InheritingSubCat class];
  597. ooo = [ccc new];
  598. cc2 = [InheritingSubCat_2 class];
  599. oo2 = [cc2 new];
  600. objc_retain(ooo);
  601. testassert(Retains == 0);
  602. objc_release(ooo);
  603. testassert(Releases == 0);
  604. objc_autorelease(ooo);
  605. testassert(Autoreleases == 0);
  606. objc_retain(oo2);
  607. testassert(Retains == 0);
  608. objc_release(oo2);
  609. testassert(Releases == 0);
  610. objc_autorelease(oo2);
  611. testassert(Autoreleases == 0);
  612. dlh = dlopen("customrr-cat1.bundle", RTLD_LAZY);
  613. testassert(dlh);
  614. objc_retain(ooo);
  615. testassert(Retains == 0);
  616. objc_release(ooo);
  617. testassert(Releases == 0);
  618. objc_autorelease(ooo);
  619. testassert(Autoreleases == 0);
  620. objc_retain(oo2);
  621. testassert(Retains == 0);
  622. objc_release(oo2);
  623. testassert(Releases == 0);
  624. objc_autorelease(oo2);
  625. testassert(Autoreleases == 0);
  626. testprintf("category replacement clobbers (InheritingSubCat)\n");
  627. zero();
  628. ccc = [InheritingSubCat class];
  629. ooo = [ccc new];
  630. cc2 = [InheritingSubCat_2 class];
  631. oo2 = [cc2 new];
  632. objc_retain(ooo);
  633. testassert(Retains == 0);
  634. objc_release(ooo);
  635. testassert(Releases == 0);
  636. objc_autorelease(ooo);
  637. testassert(Autoreleases == 0);
  638. objc_retain(oo2);
  639. testassert(Retains == 0);
  640. objc_release(oo2);
  641. testassert(Releases == 0);
  642. objc_autorelease(oo2);
  643. testassert(Autoreleases == 0);
  644. dlh = dlopen("customrr-cat2.bundle", RTLD_LAZY);
  645. testassert(dlh);
  646. objc_retain(ooo);
  647. testassert(Retains == 1);
  648. objc_release(ooo);
  649. testassert(Releases == 1);
  650. objc_autorelease(ooo);
  651. testassert(Autoreleases == 1);
  652. objc_retain(oo2);
  653. testassert(Retains == 2);
  654. objc_release(oo2);
  655. testassert(Releases == 2);
  656. objc_autorelease(oo2);
  657. testassert(Autoreleases == 2);
  658. testprintf("allocateClassPair with clean super does not clobber\n");
  659. zero();
  660. objc_retain(inh);
  661. testassert(Retains == 0);
  662. objc_release(inh);
  663. testassert(Releases == 0);
  664. objc_autorelease(inh);
  665. testassert(Autoreleases == 0);
  666. ccc = objc_allocateClassPair([InheritingSub class], "CleanClassPair", 0);
  667. objc_registerClassPair(ccc);
  668. ooo = [ccc new];
  669. objc_retain(inh);
  670. testassert(Retains == 0);
  671. objc_release(inh);
  672. testassert(Releases == 0);
  673. objc_autorelease(inh);
  674. testassert(Autoreleases == 0);
  675. objc_retain(ooo);
  676. testassert(Retains == 0);
  677. objc_release(ooo);
  678. testassert(Releases == 0);
  679. objc_autorelease(ooo);
  680. testassert(Autoreleases == 0);
  681. testprintf("allocateClassPair with clobbered super clobbers\n");
  682. zero();
  683. ccc = objc_allocateClassPair([OverridingSub class], "DirtyClassPair", 0);
  684. objc_registerClassPair(ccc);
  685. ooo = [ccc new];
  686. objc_retain(ooo);
  687. testassert(SubRetains == 1);
  688. objc_release(ooo);
  689. testassert(SubReleases == 1);
  690. objc_autorelease(ooo);
  691. testassert(SubAutoreleases == 1);
  692. testprintf("allocateClassPair with clean super and override clobbers\n");
  693. zero();
  694. ccc = objc_allocateClassPair([InheritingSub class], "Dirty2ClassPair", 0);
  695. class_addMethod(ccc, @selector(autorelease), (IMP)imp_fn, "");
  696. objc_registerClassPair(ccc);
  697. ooo = [ccc new];
  698. objc_retain(ooo);
  699. testassert(Retains == 1);
  700. objc_release(ooo);
  701. testassert(Releases == 1);
  702. objc_autorelease(ooo);
  703. testassert(Autoreleases == 0);
  704. testassert(Imps == 1);
  705. // method_setImplementation and method_exchangeImplementations only
  706. // clobber when manipulating NSObject. We can only test one at a time.
  707. // To test both, we need two tests: customrr and customrr2.
  708. // These tests also check recursive clobber.
  709. #if TEST_EXCHANGEIMPLEMENTATIONS
  710. testprintf("exchangeImplementations clobbers (recursive)\n");
  711. #else
  712. testprintf("setImplementation clobbers (recursive)\n");
  713. #endif
  714. zero();
  715. objc_retain(obj);
  716. testassert(Retains == 0);
  717. objc_release(obj);
  718. testassert(Releases == 0);
  719. objc_autorelease(obj);
  720. testassert(Autoreleases == 0);
  721. objc_retain(inh);
  722. testassert(Retains == 0);
  723. objc_release(inh);
  724. testassert(Releases == 0);
  725. objc_autorelease(inh);
  726. testassert(Autoreleases == 0);
  727. Method meth = class_getInstanceMethod(cls, @selector(retainCount));
  728. testassert(meth);
  729. #if TEST_EXCHANGEIMPLEMENTATIONS
  730. method_exchangeImplementations(meth, meth);
  731. #else
  732. method_setImplementation(meth, (IMP)imp_fn);
  733. #endif
  734. objc_retain(obj);
  735. testassert(Retains == 1);
  736. objc_release(obj);
  737. testassert(Releases == 1);
  738. objc_autorelease(obj);
  739. testassert(Autoreleases == 1);
  740. objc_retain(inh);
  741. testassert(Retains == 2);
  742. objc_release(inh);
  743. testassert(Releases == 2);
  744. objc_autorelease(inh);
  745. testassert(Autoreleases == 2);
  746. // do not add more tests here - the recursive test must be LAST
  747. succeed(basename(argv[0]));
  748. }