1 // These options must match customrr2.m
5 $C{COMPILE} $DIR/customrr.m -fvisibility=default -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
20 @interface InheritingSubCat @end
21 @implementation InheritingSubCat @end
23 int main(int argc __unused, char **argv)
25 succeed(basename(argv[0]));
32 static int Autoreleases;
33 static int RetainCounts;
34 static int PlusRetains;
35 static int PlusReleases;
36 static int PlusAutoreleases;
37 static int PlusRetainCounts;
39 static int AllocWithZones;
41 static int SubRetains;
42 static int SubReleases;
43 static int SubAutoreleases;
44 static int SubRetainCounts;
45 static int SubPlusRetains;
46 static int SubPlusReleases;
47 static int SubPlusAutoreleases;
48 static int SubPlusRetainCounts;
50 static int SubAllocWithZones;
54 static id imp_fn(id self, SEL _cmd __unused, ...)
60 static void zero(void) {
78 SubPlusAutoreleases = 0;
79 SubPlusRetainCounts = 0;
81 SubAllocWithZones = 0;
87 id HackRetain(id self, SEL _cmd __unused) { Retains++; return self; }
88 void HackRelease(id self __unused, SEL _cmd __unused) { Releases++; }
89 id HackAutorelease(id self, SEL _cmd __unused) { Autoreleases++; return self; }
90 NSUInteger HackRetainCount(id self __unused, SEL _cmd __unused) { RetainCounts++; return 1; }
91 id HackPlusRetain(id self, SEL _cmd __unused) { PlusRetains++; return self; }
92 void HackPlusRelease(id self __unused, SEL _cmd __unused) { PlusReleases++; }
93 id HackPlusAutorelease(id self, SEL _cmd __unused) { PlusAutoreleases++; return self; }
94 NSUInteger HackPlusRetainCount(id self __unused, SEL _cmd __unused) { PlusRetainCounts++; return 1; }
95 id HackAlloc(Class self, SEL _cmd __unused) { Allocs++; return class_createInstance(self, 0); }
96 id HackAllocWithZone(Class self, SEL _cmd __unused) { AllocWithZones++; return class_createInstance(self, 0); }
99 @interface OverridingSub : NSObject @end
100 @implementation OverridingSub
102 -(id) retain { SubRetains++; return self; }
103 +(id) retain { SubPlusRetains++; return self; }
104 -(oneway void) release { SubReleases++; }
105 +(oneway void) release { SubPlusReleases++; }
106 -(id) autorelease { SubAutoreleases++; return self; }
107 +(id) autorelease { SubPlusAutoreleases++; return self; }
108 -(NSUInteger) retainCount { SubRetainCounts++; return 1; }
109 +(NSUInteger) retainCount { SubPlusRetainCounts++; return 1; }
113 @interface OverridingASub : NSObject @end
114 @implementation OverridingASub
115 +(id) alloc { SubAllocs++; return class_createInstance(self, 0); }
118 @interface OverridingAWZSub : NSObject @end
119 @implementation OverridingAWZSub
120 +(id) allocWithZone:(NSZone * __unused)z { SubAllocWithZones++; return class_createInstance(self, 0); }
123 @interface OverridingAAWZSub : NSObject @end
124 @implementation OverridingAAWZSub
125 +(id) alloc { SubAllocs++; return class_createInstance(self, 0); }
126 +(id) allocWithZone:(NSZone * __unused)z { SubAllocWithZones++; return class_createInstance(self, 0); }
130 @interface InheritingSub : NSObject @end
131 @implementation InheritingSub @end
133 @interface InheritingSub2 : NSObject @end
134 @implementation InheritingSub2 @end
135 @interface InheritingSub2_2 : InheritingSub2 @end
136 @implementation InheritingSub2_2 @end
138 @interface InheritingSub3 : NSObject @end
139 @implementation InheritingSub3 @end
140 @interface InheritingSub3_2 : InheritingSub3 @end
141 @implementation InheritingSub3_2 @end
143 @interface InheritingSub4 : NSObject @end
144 @implementation InheritingSub4 @end
145 @interface InheritingSub4_2 : InheritingSub4 @end
146 @implementation InheritingSub4_2 @end
148 @interface InheritingSub5 : NSObject @end
149 @implementation InheritingSub5 @end
150 @interface InheritingSub5_2 : InheritingSub5 @end
151 @implementation InheritingSub5_2 @end
153 @interface InheritingSub6 : NSObject @end
154 @implementation InheritingSub6 @end
155 @interface InheritingSub6_2 : InheritingSub6 @end
156 @implementation InheritingSub6_2 @end
158 @interface InheritingSub7 : NSObject @end
159 @implementation InheritingSub7 @end
160 @interface InheritingSub7_2 : InheritingSub7 @end
161 @implementation InheritingSub7_2 @end
163 @interface InheritingSubCat : NSObject @end
164 @implementation InheritingSubCat @end
165 @interface InheritingSubCat_2 : InheritingSubCat @end
166 @implementation InheritingSubCat_2 @end
169 extern uintptr_t OBJC_CLASS_$_UnrealizedSubA1;
170 @interface UnrealizedSubA1 : NSObject @end
171 @implementation UnrealizedSubA1 @end
172 extern uintptr_t OBJC_CLASS_$_UnrealizedSubA2;
173 @interface UnrealizedSubA2 : NSObject @end
174 @implementation UnrealizedSubA2 @end
175 extern uintptr_t OBJC_CLASS_$_UnrealizedSubA3;
176 @interface UnrealizedSubA3 : NSObject @end
177 @implementation UnrealizedSubA3 @end
179 extern uintptr_t OBJC_CLASS_$_UnrealizedSubB1;
180 @interface UnrealizedSubB1 : NSObject @end
181 @implementation UnrealizedSubB1 @end
182 extern uintptr_t OBJC_CLASS_$_UnrealizedSubB2;
183 @interface UnrealizedSubB2 : NSObject @end
184 @implementation UnrealizedSubB2 @end
185 extern uintptr_t OBJC_CLASS_$_UnrealizedSubB3;
186 @interface UnrealizedSubB3 : NSObject @end
187 @implementation UnrealizedSubB3 @end
189 extern uintptr_t OBJC_CLASS_$_UnrealizedSubC1;
190 @interface UnrealizedSubC1 : NSObject @end
191 @implementation UnrealizedSubC1 @end
192 extern uintptr_t OBJC_CLASS_$_UnrealizedSubC2;
193 @interface UnrealizedSubC2 : NSObject @end
194 @implementation UnrealizedSubC2 @end
195 extern uintptr_t OBJC_CLASS_$_UnrealizedSubC3;
196 @interface UnrealizedSubC3 : NSObject @end
197 @implementation UnrealizedSubC3 @end
200 int main(int argc __unused, char **argv)
202 objc_autoreleasePoolPush();
204 // Hack NSObject's RR methods.
205 // Don't use runtime functions to do this -
206 // we want the runtime to think that these are NSObject's real code
208 Class cls = [NSObject class];
211 imp = class_getMethodImplementation(cls, @selector(retain));
212 m = (IMP *)class_getInstanceMethod(cls, @selector(retain));
213 testassert(m[2] == imp); // verify Method struct is as we expect
215 m = (IMP *)class_getInstanceMethod(cls, @selector(retain));
216 m[2] = (IMP)HackRetain;
217 m = (IMP *)class_getInstanceMethod(cls, @selector(release));
218 m[2] = (IMP)HackRelease;
219 m = (IMP *)class_getInstanceMethod(cls, @selector(autorelease));
220 m[2] = (IMP)HackAutorelease;
221 m = (IMP *)class_getInstanceMethod(cls, @selector(retainCount));
222 m[2] = (IMP)HackRetainCount;
223 m = (IMP *)class_getClassMethod(cls, @selector(retain));
224 m[2] = (IMP)HackPlusRetain;
225 m = (IMP *)class_getClassMethod(cls, @selector(release));
226 m[2] = (IMP)HackPlusRelease;
227 m = (IMP *)class_getClassMethod(cls, @selector(autorelease));
228 m[2] = (IMP)HackPlusAutorelease;
229 m = (IMP *)class_getClassMethod(cls, @selector(retainCount));
230 m[2] = (IMP)HackPlusRetainCount;
231 m = (IMP *)class_getClassMethod(cls, @selector(alloc));
232 m[2] = (IMP)HackAlloc;
233 m = (IMP *)class_getClassMethod(cls, @selector(allocWithZone:));
234 m[2] = (IMP)HackAllocWithZone;
236 _objc_flush_caches(cls);
238 imp = class_getMethodImplementation(cls, @selector(retain));
239 testassert(imp == (IMP)HackRetain); // verify hack worked
242 Class cls = [NSObject class];
243 Class icl = [InheritingSub class];
244 Class ocl = [OverridingSub class];
246 Class oa1 = [OverridingASub class];
247 Class oa2 = [OverridingAWZSub class];
248 Class oa3 = [OverridingAAWZSub class];
250 NSObject *obj = [NSObject new];
251 InheritingSub *inh = [InheritingSub new];
252 OverridingSub *ovr = [OverridingSub new];
262 testprintf("method dispatch does not bypass\n");
266 testassert(Retains == 1);
268 testassert(Releases == 1);
270 testassert(Autoreleases == 1);
273 testassert(PlusRetains == 1);
275 testassert(PlusReleases == 1);
277 testassert(PlusAutoreleases == 1);
280 testassert(Retains == 2);
282 testassert(Releases == 2);
284 testassert(Autoreleases == 2);
287 testassert(PlusRetains == 2);
289 testassert(PlusReleases == 2);
291 testassert(PlusAutoreleases == 2);
294 testassert(SubRetains == 1);
296 testassert(SubReleases == 1);
298 testassert(SubAutoreleases == 1);
301 testassert(SubPlusRetains == 1);
303 testassert(SubPlusReleases == 1);
305 testassert(SubPlusAutoreleases == 1);
307 [UnrealizedSubA1 retain];
308 testassert(PlusRetains == 3);
309 [UnrealizedSubA2 release];
310 testassert(PlusReleases == 3);
311 [UnrealizedSubA3 autorelease];
312 testassert(PlusAutoreleases == 3);
315 testprintf("objc_msgSend() does not bypass\n");
318 id (*retain_fn)(id, SEL) = (id(*)(id, SEL))objc_msgSend;
319 void (*release_fn)(id, SEL) = (void(*)(id, SEL))objc_msgSend;
320 id (*autorelease_fn)(id, SEL) = (id(*)(id, SEL))objc_msgSend;
322 retain_fn(obj, @selector(retain));
323 testassert(Retains == 1);
324 release_fn(obj, @selector(release));
325 testassert(Releases == 1);
326 autorelease_fn(obj, @selector(autorelease));
327 testassert(Autoreleases == 1);
329 retain_fn(cls, @selector(retain));
330 testassert(PlusRetains == 1);
331 release_fn(cls, @selector(release));
332 testassert(PlusReleases == 1);
333 autorelease_fn(cls, @selector(autorelease));
334 testassert(PlusAutoreleases == 1);
336 retain_fn(inh, @selector(retain));
337 testassert(Retains == 2);
338 release_fn(inh, @selector(release));
339 testassert(Releases == 2);
340 autorelease_fn(inh, @selector(autorelease));
341 testassert(Autoreleases == 2);
343 retain_fn(icl, @selector(retain));
344 testassert(PlusRetains == 2);
345 release_fn(icl, @selector(release));
346 testassert(PlusReleases == 2);
347 autorelease_fn(icl, @selector(autorelease));
348 testassert(PlusAutoreleases == 2);
350 retain_fn(ovr, @selector(retain));
351 testassert(SubRetains == 1);
352 release_fn(ovr, @selector(release));
353 testassert(SubReleases == 1);
354 autorelease_fn(ovr, @selector(autorelease));
355 testassert(SubAutoreleases == 1);
357 retain_fn(ocl, @selector(retain));
358 testassert(SubPlusRetains == 1);
359 release_fn(ocl, @selector(release));
360 testassert(SubPlusReleases == 1);
361 autorelease_fn(ocl, @selector(autorelease));
362 testassert(SubPlusAutoreleases == 1);
365 retain_fn((Class)&OBJC_CLASS_$_UnrealizedSubB1, @selector(retain));
366 testassert(PlusRetains == 3);
367 release_fn((Class)&OBJC_CLASS_$_UnrealizedSubB2, @selector(release));
368 testassert(PlusReleases == 3);
369 autorelease_fn((Class)&OBJC_CLASS_$_UnrealizedSubB3, @selector(autorelease));
370 testassert(PlusAutoreleases == 3);
374 testprintf("arc function bypasses instance but not class or override\n");
378 testassert(Retains == 0);
380 testassert(Releases == 0);
381 objc_autorelease(obj);
382 testassert(Autoreleases == 0);
385 testassert(PlusRetains == 1);
387 testassert(PlusReleases == 1);
388 objc_autorelease(cls);
389 testassert(PlusAutoreleases == 1);
392 testassert(Retains == 0);
394 testassert(Releases == 0);
395 objc_autorelease(inh);
396 testassert(Autoreleases == 0);
399 testassert(PlusRetains == 2);
401 testassert(PlusReleases == 2);
402 objc_autorelease(icl);
403 testassert(PlusAutoreleases == 2);
406 testassert(SubRetains == 1);
408 testassert(SubReleases == 1);
409 objc_autorelease(ovr);
410 testassert(SubAutoreleases == 1);
413 testassert(SubPlusRetains == 1);
415 testassert(SubPlusReleases == 1);
416 objc_autorelease(ocl);
417 testassert(SubPlusAutoreleases == 1);
421 testwarn("rdar://12961688 CustomRR is wrong for unrealized classes");
423 objc_retain((Class)&OBJC_CLASS_$_UnrealizedSubC1);
424 testassert(PlusRetains == 3);
425 objc_release((Class)&OBJC_CLASS_$_UnrealizedSubC2);
426 testassert(PlusReleases == 3);
427 objc_autorelease((Class)&OBJC_CLASS_$_UnrealizedSubC3);
428 testassert(PlusAutoreleases == 3);
433 testprintf("unrelated addMethod does not clobber\n");
436 class_addMethod(cls, @selector(unrelatedMethod), (IMP)imp_fn, "");
439 testassert(Retains == 0);
441 testassert(Releases == 0);
442 objc_autorelease(obj);
443 testassert(Autoreleases == 0);
446 testprintf("add class method does not clobber\n");
450 testassert(Retains == 0);
452 testassert(Releases == 0);
453 objc_autorelease(obj);
454 testassert(Autoreleases == 0);
456 class_addMethod(cls->isa, @selector(retain), (IMP)imp_fn, "");
459 testassert(Retains == 0);
461 testassert(Releases == 0);
462 objc_autorelease(obj);
463 testassert(Autoreleases == 0);
466 testprintf("addMethod clobbers (InheritingSub2, retain)\n");
469 ccc = [InheritingSub2 class];
471 cc2 = [InheritingSub2_2 class];
475 testassert(Retains == 0);
477 testassert(Releases == 0);
478 objc_autorelease(ooo);
479 testassert(Autoreleases == 0);
482 testassert(Retains == 0);
484 testassert(Releases == 0);
485 objc_autorelease(oo2);
486 testassert(Autoreleases == 0);
488 class_addMethod(ccc, @selector(retain), (IMP)imp_fn, "");
491 testassert(Retains == 0);
492 testassert(Imps == 1);
494 testassert(Releases == 1);
495 objc_autorelease(ooo);
496 testassert(Autoreleases == 1);
499 testassert(Retains == 0);
500 testassert(Imps == 2);
502 testassert(Releases == 2);
503 objc_autorelease(oo2);
504 testassert(Autoreleases == 2);
507 testprintf("addMethod clobbers (InheritingSub3, release)\n");
510 ccc = [InheritingSub3 class];
512 cc2 = [InheritingSub3_2 class];
516 testassert(Retains == 0);
518 testassert(Releases == 0);
519 objc_autorelease(ooo);
520 testassert(Autoreleases == 0);
523 testassert(Retains == 0);
525 testassert(Releases == 0);
526 objc_autorelease(oo2);
527 testassert(Autoreleases == 0);
529 class_addMethod(ccc, @selector(release), (IMP)imp_fn, "");
532 testassert(Retains == 1);
534 testassert(Releases == 0);
535 testassert(Imps == 1);
536 objc_autorelease(ooo);
537 testassert(Autoreleases == 1);
540 testassert(Retains == 2);
542 testassert(Releases == 0);
543 testassert(Imps == 2);
544 objc_autorelease(oo2);
545 testassert(Autoreleases == 2);
548 testprintf("addMethod clobbers (InheritingSub4, autorelease)\n");
551 ccc = [InheritingSub4 class];
553 cc2 = [InheritingSub4_2 class];
557 testassert(Retains == 0);
559 testassert(Releases == 0);
560 objc_autorelease(ooo);
561 testassert(Autoreleases == 0);
564 testassert(Retains == 0);
566 testassert(Releases == 0);
567 objc_autorelease(oo2);
568 testassert(Autoreleases == 0);
570 class_addMethod(ccc, @selector(autorelease), (IMP)imp_fn, "");
573 testassert(Retains == 1);
575 testassert(Releases == 1);
576 objc_autorelease(ooo);
577 testassert(Autoreleases == 0);
578 testassert(Imps == 1);
581 testassert(Retains == 2);
583 testassert(Releases == 2);
584 objc_autorelease(oo2);
585 testassert(Autoreleases == 0);
586 testassert(Imps == 2);
589 testprintf("addMethod clobbers (InheritingSub5, retainCount)\n");
592 ccc = [InheritingSub5 class];
594 cc2 = [InheritingSub5_2 class];
598 testassert(Retains == 0);
600 testassert(Releases == 0);
601 objc_autorelease(ooo);
602 testassert(Autoreleases == 0);
605 testassert(Retains == 0);
607 testassert(Releases == 0);
608 objc_autorelease(oo2);
609 testassert(Autoreleases == 0);
611 class_addMethod(ccc, @selector(retainCount), (IMP)imp_fn, "");
614 testassert(Retains == 1);
616 testassert(Releases == 1);
617 objc_autorelease(ooo);
618 testassert(Autoreleases == 1);
619 // no bypassing call for -retainCount
622 testassert(Retains == 2);
624 testassert(Releases == 2);
625 objc_autorelease(oo2);
626 testassert(Autoreleases == 2);
627 // no bypassing call for -retainCount
630 testprintf("setSuperclass to clean super does not clobber (InheritingSub6)\n");
633 ccc = [InheritingSub6 class];
635 cc2 = [InheritingSub6_2 class];
639 testassert(Retains == 0);
641 testassert(Releases == 0);
642 objc_autorelease(ooo);
643 testassert(Autoreleases == 0);
646 testassert(Retains == 0);
648 testassert(Releases == 0);
649 objc_autorelease(oo2);
650 testassert(Autoreleases == 0);
652 class_setSuperclass(ccc, [InheritingSub class]);
655 testassert(Retains == 0);
657 testassert(Releases == 0);
658 objc_autorelease(ooo);
659 testassert(Autoreleases == 0);
662 testassert(Retains == 0);
664 testassert(Releases == 0);
665 objc_autorelease(oo2);
666 testassert(Autoreleases == 0);
669 testprintf("setSuperclass to dirty super clobbers (InheritingSub7)\n");
672 ccc = [InheritingSub7 class];
674 cc2 = [InheritingSub7_2 class];
678 testassert(Retains == 0);
680 testassert(Releases == 0);
681 objc_autorelease(ooo);
682 testassert(Autoreleases == 0);
685 testassert(Retains == 0);
687 testassert(Releases == 0);
688 objc_autorelease(oo2);
689 testassert(Autoreleases == 0);
691 class_setSuperclass(ccc, [OverridingSub class]);
694 testassert(SubRetains == 1);
696 testassert(SubReleases == 1);
697 objc_autorelease(ooo);
698 testassert(SubAutoreleases == 1);
701 testassert(SubRetains == 2);
703 testassert(SubReleases == 2);
704 objc_autorelease(oo2);
705 testassert(SubAutoreleases == 2);
708 testprintf("category replacement of unrelated method does not clobber (InheritingSubCat)\n");
711 ccc = [InheritingSubCat class];
713 cc2 = [InheritingSubCat_2 class];
717 testassert(Retains == 0);
719 testassert(Releases == 0);
720 objc_autorelease(ooo);
721 testassert(Autoreleases == 0);
724 testassert(Retains == 0);
726 testassert(Releases == 0);
727 objc_autorelease(oo2);
728 testassert(Autoreleases == 0);
730 dlh = dlopen("customrr-cat1.dylib", RTLD_LAZY);
734 testassert(Retains == 0);
736 testassert(Releases == 0);
737 objc_autorelease(ooo);
738 testassert(Autoreleases == 0);
741 testassert(Retains == 0);
743 testassert(Releases == 0);
744 objc_autorelease(oo2);
745 testassert(Autoreleases == 0);
748 testprintf("category replacement clobbers (InheritingSubCat)\n");
751 ccc = [InheritingSubCat class];
753 cc2 = [InheritingSubCat_2 class];
757 testassert(Retains == 0);
759 testassert(Releases == 0);
760 objc_autorelease(ooo);
761 testassert(Autoreleases == 0);
764 testassert(Retains == 0);
766 testassert(Releases == 0);
767 objc_autorelease(oo2);
768 testassert(Autoreleases == 0);
770 dlh = dlopen("customrr-cat2.dylib", RTLD_LAZY);
774 testassert(Retains == 1);
776 testassert(Releases == 1);
777 objc_autorelease(ooo);
778 testassert(Autoreleases == 1);
781 testassert(Retains == 2);
783 testassert(Releases == 2);
784 objc_autorelease(oo2);
785 testassert(Autoreleases == 2);
788 testprintf("allocateClassPair with clean super does not clobber\n");
792 testassert(Retains == 0);
794 testassert(Releases == 0);
795 objc_autorelease(inh);
796 testassert(Autoreleases == 0);
798 ccc = objc_allocateClassPair([InheritingSub class], "CleanClassPair", 0);
799 objc_registerClassPair(ccc);
803 testassert(Retains == 0);
805 testassert(Releases == 0);
806 objc_autorelease(inh);
807 testassert(Autoreleases == 0);
810 testassert(Retains == 0);
812 testassert(Releases == 0);
813 objc_autorelease(ooo);
814 testassert(Autoreleases == 0);
817 testprintf("allocateClassPair with clobbered super clobbers\n");
820 ccc = objc_allocateClassPair([OverridingSub class], "DirtyClassPair", 0);
821 objc_registerClassPair(ccc);
825 testassert(SubRetains == 1);
827 testassert(SubReleases == 1);
828 objc_autorelease(ooo);
829 testassert(SubAutoreleases == 1);
832 testprintf("allocateClassPair with clean super and override clobbers\n");
835 ccc = objc_allocateClassPair([InheritingSub class], "Dirty2ClassPair", 0);
836 class_addMethod(ccc, @selector(autorelease), (IMP)imp_fn, "");
837 objc_registerClassPair(ccc);
841 testassert(Retains == 1);
843 testassert(Releases == 1);
844 objc_autorelease(ooo);
845 testassert(Autoreleases == 0);
846 testassert(Imps == 1);
849 // method_setImplementation and method_exchangeImplementations only
850 // clobber when manipulating NSObject. We can only test one at a time.
851 // To test both, we need two tests: customrr and customrr2.
853 // These tests also check recursive clobber.
855 #if TEST_EXCHANGEIMPLEMENTATIONS
856 testprintf("exchangeImplementations clobbers (recursive)\n");
858 testprintf("setImplementation clobbers (recursive)\n");
863 testassert(Retains == 0);
865 testassert(Releases == 0);
866 objc_autorelease(obj);
867 testassert(Autoreleases == 0);
870 testassert(Retains == 0);
872 testassert(Releases == 0);
873 objc_autorelease(inh);
874 testassert(Autoreleases == 0);
876 Method meth = class_getInstanceMethod(cls, @selector(retainCount));
878 #if TEST_EXCHANGEIMPLEMENTATIONS
879 method_exchangeImplementations(meth, meth);
881 method_setImplementation(meth, (IMP)imp_fn);
885 testassert(Retains == 1);
887 testassert(Releases == 1);
888 objc_autorelease(obj);
889 testassert(Autoreleases == 1);
892 testassert(Retains == 2);
894 testassert(Releases == 2);
895 objc_autorelease(inh);
896 testassert(Autoreleases == 2);
899 // do not add more tests here - the recursive test must be LAST
901 succeed(basename(argv[0]));