123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915 |
- // These options must match customrr2.m
- // TEST_CONFIG MEM=mrc
- /*
- TEST_BUILD
- $C{COMPILE} $DIR/customrr.m -fvisibility=default -o customrr.exe -fno-objc-convert-messages-to-runtime-calls
- $C{COMPILE} -bundle -bundle_loader customrr.exe $DIR/customrr-cat1.m -o customrr-cat1.bundle
- $C{COMPILE} -bundle -bundle_loader customrr.exe $DIR/customrr-cat2.m -o customrr-cat2.bundle
- END
- */
- #include "test.h"
- #include <dlfcn.h>
- #include <Foundation/NSObject.h>
- static int Retains;
- static int Releases;
- static int Autoreleases;
- static int RetainCounts;
- static int PlusRetains;
- static int PlusReleases;
- static int PlusAutoreleases;
- static int PlusRetainCounts;
- static int Allocs;
- static int AllocWithZones;
- static int SubRetains;
- static int SubReleases;
- static int SubAutoreleases;
- static int SubRetainCounts;
- static int SubPlusRetains;
- static int SubPlusReleases;
- static int SubPlusAutoreleases;
- static int SubPlusRetainCounts;
- static int SubAllocs;
- static int SubAllocWithZones;
- static int Imps;
- static id imp_fn(id self, SEL _cmd __unused, ...)
- {
- Imps++;
- return self;
- }
- static void zero(void) {
- Retains = 0;
- Releases = 0;
- Autoreleases = 0;
- RetainCounts = 0;
- PlusRetains = 0;
- PlusReleases = 0;
- PlusAutoreleases = 0;
- PlusRetainCounts = 0;
- Allocs = 0;
- AllocWithZones = 0;
- SubRetains = 0;
- SubReleases = 0;
- SubAutoreleases = 0;
- SubRetainCounts = 0;
- SubPlusRetains = 0;
- SubPlusReleases = 0;
- SubPlusAutoreleases = 0;
- SubPlusRetainCounts = 0;
- SubAllocs = 0;
- SubAllocWithZones = 0;
- Imps = 0;
- }
- id HackRetain(id self, SEL _cmd __unused) { Retains++; return self; }
- void HackRelease(id self __unused, SEL _cmd __unused) { Releases++; }
- id HackAutorelease(id self, SEL _cmd __unused) { Autoreleases++; return self; }
- NSUInteger HackRetainCount(id self __unused, SEL _cmd __unused) { RetainCounts++; return 1; }
- id HackPlusRetain(id self, SEL _cmd __unused) { PlusRetains++; return self; }
- void HackPlusRelease(id self __unused, SEL _cmd __unused) { PlusReleases++; }
- id HackPlusAutorelease(id self, SEL _cmd __unused) { PlusAutoreleases++; return self; }
- NSUInteger HackPlusRetainCount(id self __unused, SEL _cmd __unused) { PlusRetainCounts++; return 1; }
- id HackAlloc(Class self, SEL _cmd __unused) { Allocs++; return class_createInstance(self, 0); }
- id HackAllocWithZone(Class self, SEL _cmd __unused) { AllocWithZones++; return class_createInstance(self, 0); }
- @interface OverridingSub : NSObject @end
- @implementation OverridingSub
- -(id) retain { SubRetains++; return self; }
- +(id) retain { SubPlusRetains++; return self; }
- -(oneway void) release { SubReleases++; }
- +(oneway void) release { SubPlusReleases++; }
- -(id) autorelease { SubAutoreleases++; return self; }
- +(id) autorelease { SubPlusAutoreleases++; return self; }
- -(NSUInteger) retainCount { SubRetainCounts++; return 1; }
- +(NSUInteger) retainCount { SubPlusRetainCounts++; return 1; }
- @end
- @interface OverridingASub : NSObject @end
- @implementation OverridingASub
- +(id) alloc { SubAllocs++; return class_createInstance(self, 0); }
- @end
- @interface OverridingAWZSub : NSObject @end
- @implementation OverridingAWZSub
- +(id) allocWithZone:(NSZone * __unused)z { SubAllocWithZones++; return class_createInstance(self, 0); }
- @end
- @interface OverridingAAWZSub : NSObject @end
- @implementation OverridingAAWZSub
- +(id) alloc { SubAllocs++; return class_createInstance(self, 0); }
- +(id) allocWithZone:(NSZone * __unused)z { SubAllocWithZones++; return class_createInstance(self, 0); }
- @end
- @interface InheritingSub : NSObject @end
- @implementation InheritingSub @end
- @interface InheritingSub2 : NSObject @end
- @implementation InheritingSub2 @end
- @interface InheritingSub2_2 : InheritingSub2 @end
- @implementation InheritingSub2_2 @end
- @interface InheritingSub3 : NSObject @end
- @implementation InheritingSub3 @end
- @interface InheritingSub3_2 : InheritingSub3 @end
- @implementation InheritingSub3_2 @end
- @interface InheritingSub4 : NSObject @end
- @implementation InheritingSub4 @end
- @interface InheritingSub4_2 : InheritingSub4 @end
- @implementation InheritingSub4_2 @end
- @interface InheritingSub5 : NSObject @end
- @implementation InheritingSub5 @end
- @interface InheritingSub5_2 : InheritingSub5 @end
- @implementation InheritingSub5_2 @end
- @interface InheritingSub6 : NSObject @end
- @implementation InheritingSub6 @end
- @interface InheritingSub6_2 : InheritingSub6 @end
- @implementation InheritingSub6_2 @end
- @interface InheritingSub7 : NSObject @end
- @implementation InheritingSub7 @end
- @interface InheritingSub7_2 : InheritingSub7 @end
- @implementation InheritingSub7_2 @end
- @interface InheritingSubCat : NSObject @end
- @implementation InheritingSubCat @end
- @interface InheritingSubCat_2 : InheritingSubCat @end
- @implementation InheritingSubCat_2 @end
- extern uintptr_t OBJC_CLASS_$_UnrealizedSubA1;
- @interface UnrealizedSubA1 : NSObject @end
- @implementation UnrealizedSubA1 @end
- extern uintptr_t OBJC_CLASS_$_UnrealizedSubA2;
- @interface UnrealizedSubA2 : NSObject @end
- @implementation UnrealizedSubA2 @end
- extern uintptr_t OBJC_CLASS_$_UnrealizedSubA3;
- @interface UnrealizedSubA3 : NSObject @end
- @implementation UnrealizedSubA3 @end
- extern uintptr_t OBJC_CLASS_$_UnrealizedSubB1;
- @interface UnrealizedSubB1 : NSObject @end
- @implementation UnrealizedSubB1 @end
- extern uintptr_t OBJC_CLASS_$_UnrealizedSubB2;
- @interface UnrealizedSubB2 : NSObject @end
- @implementation UnrealizedSubB2 @end
- extern uintptr_t OBJC_CLASS_$_UnrealizedSubB3;
- @interface UnrealizedSubB3 : NSObject @end
- @implementation UnrealizedSubB3 @end
- extern uintptr_t OBJC_CLASS_$_UnrealizedSubC1;
- @interface UnrealizedSubC1 : NSObject @end
- @implementation UnrealizedSubC1 @end
- extern uintptr_t OBJC_CLASS_$_UnrealizedSubC2;
- @interface UnrealizedSubC2 : NSObject @end
- @implementation UnrealizedSubC2 @end
- extern uintptr_t OBJC_CLASS_$_UnrealizedSubC3;
- @interface UnrealizedSubC3 : NSObject @end
- @implementation UnrealizedSubC3 @end
- int main(int argc __unused, char **argv)
- {
- objc_autoreleasePoolPush();
- // Hack NSObject's RR methods.
- // Don't use runtime functions to do this -
- // we want the runtime to think that these are NSObject's real code
- {
- #if __has_feature(ptrauth_calls)
- typedef IMP __ptrauth_objc_method_list_imp MethodListIMP;
- #else
- typedef IMP MethodListIMP;
- #endif
- Class cls = [NSObject class];
- IMP imp = class_getMethodImplementation(cls, @selector(retain));
- MethodListIMP *m = (MethodListIMP *)
- class_getInstanceMethod(cls, @selector(retain));
- testassert(m[2] == imp); // verify Method struct is as we expect
- m = (MethodListIMP *)class_getInstanceMethod(cls, @selector(retain));
- m[2] = (IMP)HackRetain;
- m = (MethodListIMP *)class_getInstanceMethod(cls, @selector(release));
- m[2] = (IMP)HackRelease;
- m = (MethodListIMP *)class_getInstanceMethod(cls, @selector(autorelease));
- m[2] = (IMP)HackAutorelease;
- m = (MethodListIMP *)class_getInstanceMethod(cls, @selector(retainCount));
- m[2] = (IMP)HackRetainCount;
- m = (MethodListIMP *)class_getClassMethod(cls, @selector(retain));
- m[2] = (IMP)HackPlusRetain;
- m = (MethodListIMP *)class_getClassMethod(cls, @selector(release));
- m[2] = (IMP)HackPlusRelease;
- m = (MethodListIMP *)class_getClassMethod(cls, @selector(autorelease));
- m[2] = (IMP)HackPlusAutorelease;
- m = (MethodListIMP *)class_getClassMethod(cls, @selector(retainCount));
- m[2] = (IMP)HackPlusRetainCount;
- m = (MethodListIMP *)class_getClassMethod(cls, @selector(alloc));
- m[2] = (IMP)HackAlloc;
- m = (MethodListIMP *)class_getClassMethod(cls, @selector(allocWithZone:));
- m[2] = (IMP)HackAllocWithZone;
- _objc_flush_caches(cls);
- imp = class_getMethodImplementation(cls, @selector(retain));
- testassert(imp == (IMP)HackRetain); // verify hack worked
- }
- Class cls = [NSObject class];
- Class icl = [InheritingSub class];
- Class ocl = [OverridingSub class];
- /*
- Class oa1 = [OverridingASub class];
- Class oa2 = [OverridingAWZSub class];
- Class oa3 = [OverridingAAWZSub class];
- */
- NSObject *obj = [NSObject new];
- InheritingSub *inh = [InheritingSub new];
- OverridingSub *ovr = [OverridingSub new];
- Class ccc;
- id ooo;
- Class cc2;
- id oo2;
- void *dlh;
- #if __x86_64__
- // vtable dispatch can introduce bypass just like the ARC entrypoints
- #else
- testprintf("method dispatch does not bypass\n");
- zero();
-
- [obj retain];
- testassert(Retains == 1);
- [obj release];
- testassert(Releases == 1);
- [obj autorelease];
- testassert(Autoreleases == 1);
- [cls retain];
- testassert(PlusRetains == 1);
- [cls release];
- testassert(PlusReleases == 1);
- [cls autorelease];
- testassert(PlusAutoreleases == 1);
- [inh retain];
- testassert(Retains == 2);
- [inh release];
- testassert(Releases == 2);
- [inh autorelease];
- testassert(Autoreleases == 2);
- [icl retain];
- testassert(PlusRetains == 2);
- [icl release];
- testassert(PlusReleases == 2);
- [icl autorelease];
- testassert(PlusAutoreleases == 2);
-
- [ovr retain];
- testassert(SubRetains == 1);
- [ovr release];
- testassert(SubReleases == 1);
- [ovr autorelease];
- testassert(SubAutoreleases == 1);
- [ocl retain];
- testassert(SubPlusRetains == 1);
- [ocl release];
- testassert(SubPlusReleases == 1);
- [ocl autorelease];
- testassert(SubPlusAutoreleases == 1);
- [UnrealizedSubA1 retain];
- testassert(PlusRetains == 3);
- [UnrealizedSubA2 release];
- testassert(PlusReleases == 3);
- [UnrealizedSubA3 autorelease];
- testassert(PlusAutoreleases == 3);
- #endif
- testprintf("objc_msgSend() does not bypass\n");
- zero();
- id (*retain_fn)(id, SEL) = (id(*)(id, SEL))objc_msgSend;
- void (*release_fn)(id, SEL) = (void(*)(id, SEL))objc_msgSend;
- id (*autorelease_fn)(id, SEL) = (id(*)(id, SEL))objc_msgSend;
- retain_fn(obj, @selector(retain));
- testassert(Retains == 1);
- release_fn(obj, @selector(release));
- testassert(Releases == 1);
- autorelease_fn(obj, @selector(autorelease));
- testassert(Autoreleases == 1);
- retain_fn(cls, @selector(retain));
- testassert(PlusRetains == 1);
- release_fn(cls, @selector(release));
- testassert(PlusReleases == 1);
- autorelease_fn(cls, @selector(autorelease));
- testassert(PlusAutoreleases == 1);
- retain_fn(inh, @selector(retain));
- testassert(Retains == 2);
- release_fn(inh, @selector(release));
- testassert(Releases == 2);
- autorelease_fn(inh, @selector(autorelease));
- testassert(Autoreleases == 2);
- retain_fn(icl, @selector(retain));
- testassert(PlusRetains == 2);
- release_fn(icl, @selector(release));
- testassert(PlusReleases == 2);
- autorelease_fn(icl, @selector(autorelease));
- testassert(PlusAutoreleases == 2);
-
- retain_fn(ovr, @selector(retain));
- testassert(SubRetains == 1);
- release_fn(ovr, @selector(release));
- testassert(SubReleases == 1);
- autorelease_fn(ovr, @selector(autorelease));
- testassert(SubAutoreleases == 1);
- retain_fn(ocl, @selector(retain));
- testassert(SubPlusRetains == 1);
- release_fn(ocl, @selector(release));
- testassert(SubPlusReleases == 1);
- autorelease_fn(ocl, @selector(autorelease));
- testassert(SubPlusAutoreleases == 1);
- retain_fn((Class)&OBJC_CLASS_$_UnrealizedSubB1, @selector(retain));
- testassert(PlusRetains == 3);
- release_fn((Class)&OBJC_CLASS_$_UnrealizedSubB2, @selector(release));
- testassert(PlusReleases == 3);
- autorelease_fn((Class)&OBJC_CLASS_$_UnrealizedSubB3, @selector(autorelease));
- testassert(PlusAutoreleases == 3);
- testprintf("arc function bypasses instance but not class or override\n");
- zero();
-
- objc_retain(obj);
- testassert(Retains == 0);
- objc_release(obj);
- testassert(Releases == 0);
- objc_autorelease(obj);
- testassert(Autoreleases == 0);
- #if SUPPORT_NONPOINTER_ISA
- objc_retain(cls);
- testassert(PlusRetains == 0);
- objc_release(cls);
- testassert(PlusReleases == 0);
- objc_autorelease(cls);
- testassert(PlusAutoreleases == 0);
- #else
- objc_retain(cls);
- testassert(PlusRetains == 1);
- objc_release(cls);
- testassert(PlusReleases == 1);
- objc_autorelease(cls);
- testassert(PlusAutoreleases == 1);
- #endif
- objc_retain(inh);
- testassert(Retains == 0);
- objc_release(inh);
- testassert(Releases == 0);
- objc_autorelease(inh);
- testassert(Autoreleases == 0);
- #if SUPPORT_NONPOINTER_ISA
- objc_retain(icl);
- testassert(PlusRetains == 0);
- objc_release(icl);
- testassert(PlusReleases == 0);
- objc_autorelease(icl);
- testassert(PlusAutoreleases == 0);
- #else
- objc_retain(icl);
- testassert(PlusRetains == 2);
- objc_release(icl);
- testassert(PlusReleases == 2);
- objc_autorelease(icl);
- testassert(PlusAutoreleases == 2);
- #endif
-
- objc_retain(ovr);
- testassert(SubRetains == 1);
- objc_release(ovr);
- testassert(SubReleases == 1);
- objc_autorelease(ovr);
- testassert(SubAutoreleases == 1);
- objc_retain(ocl);
- testassert(SubPlusRetains == 1);
- objc_release(ocl);
- testassert(SubPlusReleases == 1);
- objc_autorelease(ocl);
- testassert(SubPlusAutoreleases == 1);
- #if SUPPORT_NONPOINTER_ISA
- objc_retain((Class)&OBJC_CLASS_$_UnrealizedSubC1);
- testassert(PlusRetains == 1);
- objc_release((Class)&OBJC_CLASS_$_UnrealizedSubC2);
- testassert(PlusReleases == 1);
- objc_autorelease((Class)&OBJC_CLASS_$_UnrealizedSubC3);
- testassert(PlusAutoreleases == 1);
- #else
- objc_retain((Class)&OBJC_CLASS_$_UnrealizedSubC1);
- testassert(PlusRetains == 3);
- objc_release((Class)&OBJC_CLASS_$_UnrealizedSubC2);
- testassert(PlusReleases == 3);
- objc_autorelease((Class)&OBJC_CLASS_$_UnrealizedSubC3);
- testassert(PlusAutoreleases == 3);
- #endif
- testprintf("unrelated addMethod does not clobber\n");
- zero();
- class_addMethod(cls, @selector(unrelatedMethod), (IMP)imp_fn, "");
-
- objc_retain(obj);
- testassert(Retains == 0);
- objc_release(obj);
- testassert(Releases == 0);
- objc_autorelease(obj);
- testassert(Autoreleases == 0);
- testprintf("add class method does not clobber\n");
- zero();
-
- objc_retain(obj);
- testassert(Retains == 0);
- objc_release(obj);
- testassert(Releases == 0);
- objc_autorelease(obj);
- testassert(Autoreleases == 0);
- class_addMethod(object_getClass(cls), @selector(retain), (IMP)imp_fn, "");
-
- objc_retain(obj);
- testassert(Retains == 0);
- objc_release(obj);
- testassert(Releases == 0);
- objc_autorelease(obj);
- testassert(Autoreleases == 0);
- testprintf("addMethod clobbers (InheritingSub2, retain)\n");
- zero();
- ccc = [InheritingSub2 class];
- ooo = [ccc new];
- cc2 = [InheritingSub2_2 class];
- oo2 = [cc2 new];
-
- objc_retain(ooo);
- testassert(Retains == 0);
- objc_release(ooo);
- testassert(Releases == 0);
- objc_autorelease(ooo);
- testassert(Autoreleases == 0);
- objc_retain(oo2);
- testassert(Retains == 0);
- objc_release(oo2);
- testassert(Releases == 0);
- objc_autorelease(oo2);
- testassert(Autoreleases == 0);
- class_addMethod(ccc, @selector(retain), (IMP)imp_fn, "");
- objc_retain(ooo);
- testassert(Retains == 0);
- testassert(Imps == 1);
- objc_release(ooo);
- testassert(Releases == 1);
- objc_autorelease(ooo);
- testassert(Autoreleases == 1);
- objc_retain(oo2);
- testassert(Retains == 0);
- testassert(Imps == 2);
- objc_release(oo2);
- testassert(Releases == 2);
- objc_autorelease(oo2);
- testassert(Autoreleases == 2);
- testprintf("addMethod clobbers (InheritingSub3, release)\n");
- zero();
- ccc = [InheritingSub3 class];
- ooo = [ccc new];
- cc2 = [InheritingSub3_2 class];
- oo2 = [cc2 new];
-
- objc_retain(ooo);
- testassert(Retains == 0);
- objc_release(ooo);
- testassert(Releases == 0);
- objc_autorelease(ooo);
- testassert(Autoreleases == 0);
-
- objc_retain(oo2);
- testassert(Retains == 0);
- objc_release(oo2);
- testassert(Releases == 0);
- objc_autorelease(oo2);
- testassert(Autoreleases == 0);
- class_addMethod(ccc, @selector(release), (IMP)imp_fn, "");
- objc_retain(ooo);
- testassert(Retains == 1);
- objc_release(ooo);
- testassert(Releases == 0);
- testassert(Imps == 1);
- objc_autorelease(ooo);
- testassert(Autoreleases == 1);
- objc_retain(oo2);
- testassert(Retains == 2);
- objc_release(oo2);
- testassert(Releases == 0);
- testassert(Imps == 2);
- objc_autorelease(oo2);
- testassert(Autoreleases == 2);
- testprintf("addMethod clobbers (InheritingSub4, autorelease)\n");
- zero();
- ccc = [InheritingSub4 class];
- ooo = [ccc new];
- cc2 = [InheritingSub4_2 class];
- oo2 = [cc2 new];
-
- objc_retain(ooo);
- testassert(Retains == 0);
- objc_release(ooo);
- testassert(Releases == 0);
- objc_autorelease(ooo);
- testassert(Autoreleases == 0);
-
- objc_retain(oo2);
- testassert(Retains == 0);
- objc_release(oo2);
- testassert(Releases == 0);
- objc_autorelease(oo2);
- testassert(Autoreleases == 0);
- class_addMethod(ccc, @selector(autorelease), (IMP)imp_fn, "");
- objc_retain(ooo);
- testassert(Retains == 1);
- objc_release(ooo);
- testassert(Releases == 1);
- objc_autorelease(ooo);
- testassert(Autoreleases == 0);
- testassert(Imps == 1);
- objc_retain(oo2);
- testassert(Retains == 2);
- objc_release(oo2);
- testassert(Releases == 2);
- objc_autorelease(oo2);
- testassert(Autoreleases == 0);
- testassert(Imps == 2);
- testprintf("addMethod clobbers (InheritingSub5, retainCount)\n");
- zero();
- ccc = [InheritingSub5 class];
- ooo = [ccc new];
- cc2 = [InheritingSub5_2 class];
- oo2 = [cc2 new];
-
- objc_retain(ooo);
- testassert(Retains == 0);
- objc_release(ooo);
- testassert(Releases == 0);
- objc_autorelease(ooo);
- testassert(Autoreleases == 0);
- objc_retain(oo2);
- testassert(Retains == 0);
- objc_release(oo2);
- testassert(Releases == 0);
- objc_autorelease(oo2);
- testassert(Autoreleases == 0);
- class_addMethod(ccc, @selector(retainCount), (IMP)imp_fn, "");
- objc_retain(ooo);
- testassert(Retains == 1);
- objc_release(ooo);
- testassert(Releases == 1);
- objc_autorelease(ooo);
- testassert(Autoreleases == 1);
- // no bypassing call for -retainCount
- objc_retain(oo2);
- testassert(Retains == 2);
- objc_release(oo2);
- testassert(Releases == 2);
- objc_autorelease(oo2);
- testassert(Autoreleases == 2);
- // no bypassing call for -retainCount
- testprintf("setSuperclass to clean super does not clobber (InheritingSub6)\n");
- zero();
- ccc = [InheritingSub6 class];
- ooo = [ccc new];
- cc2 = [InheritingSub6_2 class];
- oo2 = [cc2 new];
-
- objc_retain(ooo);
- testassert(Retains == 0);
- objc_release(ooo);
- testassert(Releases == 0);
- objc_autorelease(ooo);
- testassert(Autoreleases == 0);
- objc_retain(oo2);
- testassert(Retains == 0);
- objc_release(oo2);
- testassert(Releases == 0);
- objc_autorelease(oo2);
- testassert(Autoreleases == 0);
- class_setSuperclass(ccc, [InheritingSub class]);
-
- objc_retain(ooo);
- testassert(Retains == 0);
- objc_release(ooo);
- testassert(Releases == 0);
- objc_autorelease(ooo);
- testassert(Autoreleases == 0);
-
- objc_retain(oo2);
- testassert(Retains == 0);
- objc_release(oo2);
- testassert(Releases == 0);
- objc_autorelease(oo2);
- testassert(Autoreleases == 0);
- testprintf("setSuperclass to dirty super clobbers (InheritingSub7)\n");
- zero();
- ccc = [InheritingSub7 class];
- ooo = [ccc new];
- cc2 = [InheritingSub7_2 class];
- oo2 = [cc2 new];
-
- objc_retain(ooo);
- testassert(Retains == 0);
- objc_release(ooo);
- testassert(Releases == 0);
- objc_autorelease(ooo);
- testassert(Autoreleases == 0);
-
- objc_retain(oo2);
- testassert(Retains == 0);
- objc_release(oo2);
- testassert(Releases == 0);
- objc_autorelease(oo2);
- testassert(Autoreleases == 0);
- class_setSuperclass(ccc, [OverridingSub class]);
- objc_retain(ooo);
- testassert(SubRetains == 1);
- objc_release(ooo);
- testassert(SubReleases == 1);
- objc_autorelease(ooo);
- testassert(SubAutoreleases == 1);
- objc_retain(oo2);
- testassert(SubRetains == 2);
- objc_release(oo2);
- testassert(SubReleases == 2);
- objc_autorelease(oo2);
- testassert(SubAutoreleases == 2);
- testprintf("category replacement of unrelated method does not clobber (InheritingSubCat)\n");
- zero();
- ccc = [InheritingSubCat class];
- ooo = [ccc new];
- cc2 = [InheritingSubCat_2 class];
- oo2 = [cc2 new];
-
- objc_retain(ooo);
- testassert(Retains == 0);
- objc_release(ooo);
- testassert(Releases == 0);
- objc_autorelease(ooo);
- testassert(Autoreleases == 0);
- objc_retain(oo2);
- testassert(Retains == 0);
- objc_release(oo2);
- testassert(Releases == 0);
- objc_autorelease(oo2);
- testassert(Autoreleases == 0);
- dlh = dlopen("customrr-cat1.bundle", RTLD_LAZY);
- testassert(dlh);
- objc_retain(ooo);
- testassert(Retains == 0);
- objc_release(ooo);
- testassert(Releases == 0);
- objc_autorelease(ooo);
- testassert(Autoreleases == 0);
- objc_retain(oo2);
- testassert(Retains == 0);
- objc_release(oo2);
- testassert(Releases == 0);
- objc_autorelease(oo2);
- testassert(Autoreleases == 0);
- testprintf("category replacement clobbers (InheritingSubCat)\n");
- zero();
- ccc = [InheritingSubCat class];
- ooo = [ccc new];
- cc2 = [InheritingSubCat_2 class];
- oo2 = [cc2 new];
-
- objc_retain(ooo);
- testassert(Retains == 0);
- objc_release(ooo);
- testassert(Releases == 0);
- objc_autorelease(ooo);
- testassert(Autoreleases == 0);
- objc_retain(oo2);
- testassert(Retains == 0);
- objc_release(oo2);
- testassert(Releases == 0);
- objc_autorelease(oo2);
- testassert(Autoreleases == 0);
- dlh = dlopen("customrr-cat2.bundle", RTLD_LAZY);
- testassert(dlh);
- objc_retain(ooo);
- testassert(Retains == 1);
- objc_release(ooo);
- testassert(Releases == 1);
- objc_autorelease(ooo);
- testassert(Autoreleases == 1);
- objc_retain(oo2);
- testassert(Retains == 2);
- objc_release(oo2);
- testassert(Releases == 2);
- objc_autorelease(oo2);
- testassert(Autoreleases == 2);
- testprintf("allocateClassPair with clean super does not clobber\n");
- zero();
- objc_retain(inh);
- testassert(Retains == 0);
- objc_release(inh);
- testassert(Releases == 0);
- objc_autorelease(inh);
- testassert(Autoreleases == 0);
- ccc = objc_allocateClassPair([InheritingSub class], "CleanClassPair", 0);
- objc_registerClassPair(ccc);
- ooo = [ccc new];
- objc_retain(inh);
- testassert(Retains == 0);
- objc_release(inh);
- testassert(Releases == 0);
- objc_autorelease(inh);
- testassert(Autoreleases == 0);
-
- objc_retain(ooo);
- testassert(Retains == 0);
- objc_release(ooo);
- testassert(Releases == 0);
- objc_autorelease(ooo);
- testassert(Autoreleases == 0);
- testprintf("allocateClassPair with clobbered super clobbers\n");
- zero();
- ccc = objc_allocateClassPair([OverridingSub class], "DirtyClassPair", 0);
- objc_registerClassPair(ccc);
- ooo = [ccc new];
-
- objc_retain(ooo);
- testassert(SubRetains == 1);
- objc_release(ooo);
- testassert(SubReleases == 1);
- objc_autorelease(ooo);
- testassert(SubAutoreleases == 1);
- testprintf("allocateClassPair with clean super and override clobbers\n");
- zero();
- ccc = objc_allocateClassPair([InheritingSub class], "Dirty2ClassPair", 0);
- class_addMethod(ccc, @selector(autorelease), (IMP)imp_fn, "");
- objc_registerClassPair(ccc);
- ooo = [ccc new];
-
- objc_retain(ooo);
- testassert(Retains == 1);
- objc_release(ooo);
- testassert(Releases == 1);
- objc_autorelease(ooo);
- testassert(Autoreleases == 0);
- testassert(Imps == 1);
- // method_setImplementation and method_exchangeImplementations only
- // clobber when manipulating NSObject. We can only test one at a time.
- // To test both, we need two tests: customrr and customrr2.
- // These tests also check recursive clobber.
- #if TEST_EXCHANGEIMPLEMENTATIONS
- testprintf("exchangeImplementations clobbers (recursive)\n");
- #else
- testprintf("setImplementation clobbers (recursive)\n");
- #endif
- zero();
- objc_retain(obj);
- testassert(Retains == 0);
- objc_release(obj);
- testassert(Releases == 0);
- objc_autorelease(obj);
- testassert(Autoreleases == 0);
- objc_retain(inh);
- testassert(Retains == 0);
- objc_release(inh);
- testassert(Releases == 0);
- objc_autorelease(inh);
- testassert(Autoreleases == 0);
- Method meth = class_getInstanceMethod(cls, @selector(retainCount));
- testassert(meth);
- #if TEST_EXCHANGEIMPLEMENTATIONS
- method_exchangeImplementations(meth, meth);
- #else
- method_setImplementation(meth, (IMP)imp_fn);
- #endif
-
- objc_retain(obj);
- testassert(Retains == 1);
- objc_release(obj);
- testassert(Releases == 1);
- objc_autorelease(obj);
- testassert(Autoreleases == 1);
- objc_retain(inh);
- testassert(Retains == 2);
- objc_release(inh);
- testassert(Releases == 2);
- objc_autorelease(inh);
- testassert(Autoreleases == 2);
-
- // do not add more tests here - the recursive test must be LAST
- succeed(basename(argv[0]));
- }
|