1 // These options must match customrr2.m
5 $C{COMPILE} $DIR/customrr.m '-Wl,-exported_symbol,.objc_class_name_InheritingSubCat' -o customrr.out
6 $C{COMPILE} -undefined dynamic_lookup -dynamiclib $DIR/customrr-cat1.m -o customrr-cat1.dylib
7 $C{COMPILE} -undefined dynamic_lookup -dynamiclib $DIR/customrr-cat2.m -o customrr-cat2.dylib
14 #include <Foundation/NSObject.h>
18 // pacify exported symbols list
19 @interface InheritingSubCat @end
20 @implementation InheritingSubCat @end
22 int main(int argc __unused, char **argv)
24 succeed(basename(argv[0]));
31 static int Autoreleases;
32 static int RetainCounts;
33 static int PlusRetains;
34 static int PlusReleases;
35 static int PlusAutoreleases;
36 static int PlusRetainCounts;
38 static int SubRetains;
39 static int SubReleases;
40 static int SubAutoreleases;
41 static int SubRetainCounts;
42 static int SubPlusRetains;
43 static int SubPlusReleases;
44 static int SubPlusAutoreleases;
45 static int SubPlusRetainCounts;
49 static id imp_fn(id self, SEL _cmd __unused, ...)
55 static void zero(void) {
71 SubPlusAutoreleases = 0;
72 SubPlusRetainCounts = 0;
78 id HackRetain(id self, SEL _cmd __unused) { Retains++; return self; }
79 void HackRelease(id self __unused, SEL _cmd __unused) { Releases++; }
80 id HackAutorelease(id self, SEL _cmd __unused) { Autoreleases++; return self; }
81 NSUInteger HackRetainCount(id self __unused, SEL _cmd __unused) { RetainCounts++; return 1; }
82 id HackPlusRetain(id self, SEL _cmd __unused) { PlusRetains++; return self; }
83 void HackPlusRelease(id self __unused, SEL _cmd __unused) { PlusReleases++; }
84 id HackPlusAutorelease(id self, SEL _cmd __unused) { PlusAutoreleases++; return self; }
85 NSUInteger HackPlusRetainCount(id self __unused, SEL _cmd __unused) { PlusRetainCounts++; return 1; }
88 @interface OverridingSub : NSObject @end
89 @implementation OverridingSub
91 -(id) retain { SubRetains++; return self; }
92 +(id) retain { SubPlusRetains++; return self; }
93 -(oneway void) release { SubReleases++; }
94 +(oneway void) release { SubPlusReleases++; }
95 -(id) autorelease { SubAutoreleases++; return self; }
96 +(id) autorelease { SubPlusAutoreleases++; return self; }
97 -(NSUInteger) retainCount { SubRetainCounts++; return 1; }
98 +(NSUInteger) retainCount { SubPlusRetainCounts++; return 1; }
102 @interface InheritingSub : NSObject @end
103 @implementation InheritingSub @end
105 @interface InheritingSub2 : NSObject @end
106 @implementation InheritingSub2 @end
107 @interface InheritingSub2_2 : InheritingSub2 @end
108 @implementation InheritingSub2_2 @end
110 @interface InheritingSub3 : NSObject @end
111 @implementation InheritingSub3 @end
112 @interface InheritingSub3_2 : InheritingSub3 @end
113 @implementation InheritingSub3_2 @end
115 @interface InheritingSub4 : NSObject @end
116 @implementation InheritingSub4 @end
117 @interface InheritingSub4_2 : InheritingSub4 @end
118 @implementation InheritingSub4_2 @end
120 @interface InheritingSub5 : NSObject @end
121 @implementation InheritingSub5 @end
122 @interface InheritingSub5_2 : InheritingSub5 @end
123 @implementation InheritingSub5_2 @end
125 @interface InheritingSub6 : NSObject @end
126 @implementation InheritingSub6 @end
127 @interface InheritingSub6_2 : InheritingSub6 @end
128 @implementation InheritingSub6_2 @end
130 @interface InheritingSub7 : NSObject @end
131 @implementation InheritingSub7 @end
132 @interface InheritingSub7_2 : InheritingSub7 @end
133 @implementation InheritingSub7_2 @end
135 @interface InheritingSubCat : NSObject @end
136 @implementation InheritingSubCat @end
137 @interface InheritingSubCat_2 : InheritingSubCat @end
138 @implementation InheritingSubCat_2 @end
141 int main(int argc __unused, char **argv)
143 objc_autoreleasePoolPush();
145 // Hack NSObject's RR methods.
146 // Don't use runtime functions to do this -
147 // we want the runtime to think that these are NSObject's real code
149 Class cls = [NSObject class];
152 imp = class_getMethodImplementation(cls, @selector(retain));
153 m = (IMP *)class_getInstanceMethod(cls, @selector(retain));
154 testassert(m[2] == imp); // verify Method struct is as we expect
156 m = (IMP *)class_getInstanceMethod(cls, @selector(retain));
157 m[2] = (IMP)HackRetain;
158 m = (IMP *)class_getInstanceMethod(cls, @selector(release));
159 m[2] = (IMP)HackRelease;
160 m = (IMP *)class_getInstanceMethod(cls, @selector(autorelease));
161 m[2] = (IMP)HackAutorelease;
162 m = (IMP *)class_getInstanceMethod(cls, @selector(retainCount));
163 m[2] = (IMP)HackRetainCount;
164 m = (IMP *)class_getClassMethod(cls, @selector(retain));
165 m[2] = (IMP)HackPlusRetain;
166 m = (IMP *)class_getClassMethod(cls, @selector(release));
167 m[2] = (IMP)HackPlusRelease;
168 m = (IMP *)class_getClassMethod(cls, @selector(autorelease));
169 m[2] = (IMP)HackPlusAutorelease;
170 m = (IMP *)class_getClassMethod(cls, @selector(retainCount));
171 m[2] = (IMP)HackPlusRetainCount;
173 _objc_flush_caches(cls);
175 imp = class_getMethodImplementation(cls, @selector(retain));
176 testassert(imp == (IMP)HackRetain); // verify hack worked
179 Class cls = [NSObject class];
180 Class icl = [InheritingSub class];
181 Class ocl = [OverridingSub class];
182 NSObject *obj = [NSObject new];
183 InheritingSub *inh = [InheritingSub new];
184 OverridingSub *ovr = [OverridingSub new];
194 testprintf("method dispatch does not bypass\n");
198 testassert(Retains == 1);
200 testassert(Releases == 1);
202 testassert(Autoreleases == 1);
205 testassert(PlusRetains == 1);
207 testassert(PlusReleases == 1);
209 testassert(PlusAutoreleases == 1);
212 testassert(Retains == 2);
214 testassert(Releases == 2);
216 testassert(Autoreleases == 2);
219 testassert(PlusRetains == 2);
221 testassert(PlusReleases == 2);
223 testassert(PlusAutoreleases == 2);
226 testassert(SubRetains == 1);
228 testassert(SubReleases == 1);
230 testassert(SubAutoreleases == 1);
233 testassert(SubPlusRetains == 1);
235 testassert(SubPlusReleases == 1);
237 testassert(SubPlusAutoreleases == 1);
240 testprintf("arc function bypasses instance but not class or override\n");
244 testassert(Retains == 0);
246 testassert(Releases == 0);
247 objc_autorelease(obj);
248 testassert(Autoreleases == 0);
251 testassert(PlusRetains == 1);
253 testassert(PlusReleases == 1);
254 objc_autorelease(cls);
255 testassert(PlusAutoreleases == 1);
258 testassert(Retains == 0);
260 testassert(Releases == 0);
261 objc_autorelease(inh);
262 testassert(Autoreleases == 0);
265 testassert(PlusRetains == 2);
267 testassert(PlusReleases == 2);
268 objc_autorelease(icl);
269 testassert(PlusAutoreleases == 2);
272 testassert(SubRetains == 1);
274 testassert(SubReleases == 1);
275 objc_autorelease(ovr);
276 testassert(SubAutoreleases == 1);
279 testassert(SubPlusRetains == 1);
281 testassert(SubPlusReleases == 1);
282 objc_autorelease(ocl);
283 testassert(SubPlusAutoreleases == 1);
286 testprintf("unrelated addMethod does not clobber\n");
289 class_addMethod(cls, @selector(unrelatedMethod), (IMP)imp_fn, "");
292 testassert(Retains == 0);
294 testassert(Releases == 0);
295 objc_autorelease(obj);
296 testassert(Autoreleases == 0);
299 testprintf("add class method does not clobber\n");
303 testassert(Retains == 0);
305 testassert(Releases == 0);
306 objc_autorelease(obj);
307 testassert(Autoreleases == 0);
309 class_addMethod(cls->isa, @selector(retain), (IMP)imp_fn, "");
312 testassert(Retains == 0);
314 testassert(Releases == 0);
315 objc_autorelease(obj);
316 testassert(Autoreleases == 0);
319 testprintf("addMethod clobbers (InheritingSub2, retain)\n");
322 ccc = [InheritingSub2 class];
324 cc2 = [InheritingSub2_2 class];
328 testassert(Retains == 0);
330 testassert(Releases == 0);
331 objc_autorelease(ooo);
332 testassert(Autoreleases == 0);
335 testassert(Retains == 0);
337 testassert(Releases == 0);
338 objc_autorelease(oo2);
339 testassert(Autoreleases == 0);
341 class_addMethod(ccc, @selector(retain), (IMP)imp_fn, "");
344 testassert(Retains == 0);
345 testassert(Imps == 1);
347 testassert(Releases == 1);
348 objc_autorelease(ooo);
349 testassert(Autoreleases == 1);
352 testassert(Retains == 0);
353 testassert(Imps == 2);
355 testassert(Releases == 2);
356 objc_autorelease(oo2);
357 testassert(Autoreleases == 2);
360 testprintf("addMethod clobbers (InheritingSub3, release)\n");
363 ccc = [InheritingSub3 class];
365 cc2 = [InheritingSub3_2 class];
369 testassert(Retains == 0);
371 testassert(Releases == 0);
372 objc_autorelease(ooo);
373 testassert(Autoreleases == 0);
376 testassert(Retains == 0);
378 testassert(Releases == 0);
379 objc_autorelease(oo2);
380 testassert(Autoreleases == 0);
382 class_addMethod(ccc, @selector(release), (IMP)imp_fn, "");
385 testassert(Retains == 1);
387 testassert(Releases == 0);
388 testassert(Imps == 1);
389 objc_autorelease(ooo);
390 testassert(Autoreleases == 1);
393 testassert(Retains == 2);
395 testassert(Releases == 0);
396 testassert(Imps == 2);
397 objc_autorelease(oo2);
398 testassert(Autoreleases == 2);
401 testprintf("addMethod clobbers (InheritingSub4, autorelease)\n");
404 ccc = [InheritingSub4 class];
406 cc2 = [InheritingSub4_2 class];
410 testassert(Retains == 0);
412 testassert(Releases == 0);
413 objc_autorelease(ooo);
414 testassert(Autoreleases == 0);
417 testassert(Retains == 0);
419 testassert(Releases == 0);
420 objc_autorelease(oo2);
421 testassert(Autoreleases == 0);
423 class_addMethod(ccc, @selector(autorelease), (IMP)imp_fn, "");
426 testassert(Retains == 1);
428 testassert(Releases == 1);
429 objc_autorelease(ooo);
430 testassert(Autoreleases == 0);
431 testassert(Imps == 1);
434 testassert(Retains == 2);
436 testassert(Releases == 2);
437 objc_autorelease(oo2);
438 testassert(Autoreleases == 0);
439 testassert(Imps == 2);
442 testprintf("addMethod clobbers (InheritingSub5, retainCount)\n");
445 ccc = [InheritingSub5 class];
447 cc2 = [InheritingSub5_2 class];
451 testassert(Retains == 0);
453 testassert(Releases == 0);
454 objc_autorelease(ooo);
455 testassert(Autoreleases == 0);
458 testassert(Retains == 0);
460 testassert(Releases == 0);
461 objc_autorelease(oo2);
462 testassert(Autoreleases == 0);
464 class_addMethod(ccc, @selector(retainCount), (IMP)imp_fn, "");
467 testassert(Retains == 1);
469 testassert(Releases == 1);
470 objc_autorelease(ooo);
471 testassert(Autoreleases == 1);
472 // no bypassing call for -retainCount
475 testassert(Retains == 2);
477 testassert(Releases == 2);
478 objc_autorelease(oo2);
479 testassert(Autoreleases == 2);
480 // no bypassing call for -retainCount
483 testprintf("setSuperclass to clean super does not clobber (InheritingSub6)\n");
486 ccc = [InheritingSub6 class];
488 cc2 = [InheritingSub6_2 class];
492 testassert(Retains == 0);
494 testassert(Releases == 0);
495 objc_autorelease(ooo);
496 testassert(Autoreleases == 0);
499 testassert(Retains == 0);
501 testassert(Releases == 0);
502 objc_autorelease(oo2);
503 testassert(Autoreleases == 0);
505 class_setSuperclass(ccc, [InheritingSub class]);
508 testassert(Retains == 0);
510 testassert(Releases == 0);
511 objc_autorelease(ooo);
512 testassert(Autoreleases == 0);
515 testassert(Retains == 0);
517 testassert(Releases == 0);
518 objc_autorelease(oo2);
519 testassert(Autoreleases == 0);
522 testprintf("setSuperclass to dirty super clobbers (InheritingSub7)\n");
525 ccc = [InheritingSub7 class];
527 cc2 = [InheritingSub7_2 class];
531 testassert(Retains == 0);
533 testassert(Releases == 0);
534 objc_autorelease(ooo);
535 testassert(Autoreleases == 0);
538 testassert(Retains == 0);
540 testassert(Releases == 0);
541 objc_autorelease(oo2);
542 testassert(Autoreleases == 0);
544 class_setSuperclass(ccc, [OverridingSub class]);
547 testassert(SubRetains == 1);
549 testassert(SubReleases == 1);
550 objc_autorelease(ooo);
551 testassert(SubAutoreleases == 1);
554 testassert(SubRetains == 2);
556 testassert(SubReleases == 2);
557 objc_autorelease(oo2);
558 testassert(SubAutoreleases == 2);
561 testprintf("category replacement of unrelated method does not clobber (InheritingSubCat)\n");
564 ccc = [InheritingSubCat class];
566 cc2 = [InheritingSubCat_2 class];
570 testassert(Retains == 0);
572 testassert(Releases == 0);
573 objc_autorelease(ooo);
574 testassert(Autoreleases == 0);
577 testassert(Retains == 0);
579 testassert(Releases == 0);
580 objc_autorelease(oo2);
581 testassert(Autoreleases == 0);
583 dlh = dlopen("customrr-cat1.dylib", RTLD_LAZY);
587 testassert(Retains == 0);
589 testassert(Releases == 0);
590 objc_autorelease(ooo);
591 testassert(Autoreleases == 0);
594 testassert(Retains == 0);
596 testassert(Releases == 0);
597 objc_autorelease(oo2);
598 testassert(Autoreleases == 0);
601 testprintf("category replacement clobbers (InheritingSubCat)\n");
604 ccc = [InheritingSubCat class];
606 cc2 = [InheritingSubCat_2 class];
610 testassert(Retains == 0);
612 testassert(Releases == 0);
613 objc_autorelease(ooo);
614 testassert(Autoreleases == 0);
617 testassert(Retains == 0);
619 testassert(Releases == 0);
620 objc_autorelease(oo2);
621 testassert(Autoreleases == 0);
623 dlh = dlopen("customrr-cat2.dylib", RTLD_LAZY);
627 testassert(Retains == 1);
629 testassert(Releases == 1);
630 objc_autorelease(ooo);
631 testassert(Autoreleases == 1);
634 testassert(Retains == 2);
636 testassert(Releases == 2);
637 objc_autorelease(oo2);
638 testassert(Autoreleases == 2);
641 testprintf("allocateClassPair with clean super does not clobber\n");
645 testassert(Retains == 0);
647 testassert(Releases == 0);
648 objc_autorelease(inh);
649 testassert(Autoreleases == 0);
651 ccc = objc_allocateClassPair([InheritingSub class], "CleanClassPair", 0);
652 objc_registerClassPair(ccc);
656 testassert(Retains == 0);
658 testassert(Releases == 0);
659 objc_autorelease(inh);
660 testassert(Autoreleases == 0);
663 testassert(Retains == 0);
665 testassert(Releases == 0);
666 objc_autorelease(ooo);
667 testassert(Autoreleases == 0);
670 testprintf("allocateClassPair with clobbered super clobbers\n");
673 ccc = objc_allocateClassPair([OverridingSub class], "DirtyClassPair", 0);
674 objc_registerClassPair(ccc);
678 testassert(SubRetains == 1);
680 testassert(SubReleases == 1);
681 objc_autorelease(ooo);
682 testassert(SubAutoreleases == 1);
685 testprintf("allocateClassPair with clean super and override clobbers\n");
688 ccc = objc_allocateClassPair([InheritingSub class], "Dirty2ClassPair", 0);
689 class_addMethod(ccc, @selector(autorelease), (IMP)imp_fn, "");
690 objc_registerClassPair(ccc);
694 testassert(Retains == 1);
696 testassert(Releases == 1);
697 objc_autorelease(ooo);
698 testassert(Autoreleases == 0);
699 testassert(Imps == 1);
702 // method_setImplementation and method_exchangeImplementations only
703 // clobber when manipulating NSObject. We can only test one at a time.
704 // To test both, we need two tests: customrr and customrr2.
706 // These tests also check recursive clobber.
708 #if TEST_EXCHANGEIMPLEMENTATIONS
709 testprintf("exchangeImplementations clobbers (recursive)\n");
711 testprintf("setImplementation clobbers (recursive)\n");
716 testassert(Retains == 0);
718 testassert(Releases == 0);
719 objc_autorelease(obj);
720 testassert(Autoreleases == 0);
723 testassert(Retains == 0);
725 testassert(Releases == 0);
726 objc_autorelease(inh);
727 testassert(Autoreleases == 0);
729 Method meth = class_getInstanceMethod(cls, @selector(retainCount));
731 #if TEST_EXCHANGEIMPLEMENTATIONS
732 method_exchangeImplementations(meth, meth);
734 method_setImplementation(meth, (IMP)imp_fn);
738 testassert(Retains == 1);
740 testassert(Releases == 1);
741 objc_autorelease(obj);
742 testassert(Autoreleases == 1);
745 testassert(Retains == 2);
747 testassert(Releases == 2);
748 objc_autorelease(inh);
749 testassert(Autoreleases == 2);
752 // do not add more tests here - the recursive test must be LAST
754 succeed(basename(argv[0]));