1 // This file is used in the customrr-nsobject-*.m tests
4 #include <objc/NSObject.h>
5 #include <objc/objc-internal.h>
7 #if __has_feature(ptrauth_calls)
8 typedef IMP __ptrauth_objc_method_list_imp MethodListIMP;
10 typedef IMP MethodListIMP;
15 static int Autoreleases;
16 static int PlusInitializes;
18 static int AllocWithZones;
24 id (*RealRetain)(id self, SEL _cmd);
25 void (*RealRelease)(id self, SEL _cmd);
26 id (*RealAutorelease)(id self, SEL _cmd);
27 id (*RealAlloc)(id self, SEL _cmd);
28 id (*RealAllocWithZone)(id self, SEL _cmd, void *zone);
29 id (*RealPlusNew)(id self, SEL _cmd);
30 id (*RealSelf)(id self);
31 id (*RealPlusSelf)(id self);
33 id HackRetain(id self, SEL _cmd) { Retains++; return RealRetain(self, _cmd); }
34 void HackRelease(id self, SEL _cmd) { Releases++; return RealRelease(self, _cmd); }
35 id HackAutorelease(id self, SEL _cmd) { Autoreleases++; return RealAutorelease(self, _cmd); }
37 id HackAlloc(Class self, SEL _cmd) { Allocs++; return RealAlloc(self, _cmd); }
38 id HackAllocWithZone(Class self, SEL _cmd, void *zone) { AllocWithZones++; return RealAllocWithZone(self, _cmd, zone); }
40 void HackPlusInitialize(id self __unused, SEL _cmd __unused) { PlusInitializes++; }
42 id HackInit(id self, SEL _cmd __unused) { Inits++; return self; }
44 id HackPlusNew(id self, SEL _cmd __unused) { PlusNew++; return RealPlusNew(self, _cmd); }
45 id HackSelf(id self) { Self++; return RealSelf(self); }
46 id HackPlusSelf(id self) { PlusSelf++; return RealPlusSelf(self); }
49 int main(int argc __unused, char **argv)
51 Class cls = objc_getClass("NSObject");
54 meth = class_getClassMethod(cls, @selector(initialize));
55 method_setImplementation(meth, (IMP)HackPlusInitialize);
57 // We either swizzle the method normally (testing that it properly
58 // disables optimizations), or we hack the implementation into place
59 // behind objc's back (so we can see whether it got called with the
60 // optimizations still enabled).
62 meth = class_getClassMethod(cls, @selector(allocWithZone:));
63 RealAllocWithZone = (typeof(RealAllocWithZone))method_getImplementation(meth);
65 method_setImplementation(meth, (IMP)HackAllocWithZone);
67 ((MethodListIMP *)meth)[2] = (IMP)HackAllocWithZone;
70 meth = class_getClassMethod(cls, @selector(new));
71 RealPlusNew = (typeof(RealPlusNew))method_getImplementation(meth);
73 method_setImplementation(meth, (IMP)HackPlusNew);
75 ((MethodListIMP *)meth)[2] = (IMP)HackPlusNew;
78 meth = class_getClassMethod(cls, @selector(self));
79 RealPlusSelf = (typeof(RealPlusSelf))method_getImplementation(meth);
81 method_setImplementation(meth, (IMP)HackPlusSelf);
83 ((MethodListIMP *)meth)[2] = (IMP)HackPlusSelf;
86 meth = class_getInstanceMethod(cls, @selector(self));
87 RealSelf = (typeof(RealSelf))method_getImplementation(meth);
89 method_setImplementation(meth, (IMP)HackSelf);
91 ((MethodListIMP *)meth)[2] = (IMP)HackSelf;
94 meth = class_getInstanceMethod(cls, @selector(release));
95 RealRelease = (typeof(RealRelease))method_getImplementation(meth);
97 method_setImplementation(meth, (IMP)HackRelease);
99 ((MethodListIMP *)meth)[2] = (IMP)HackRelease;
102 // These other methods get hacked for counting purposes only
104 meth = class_getInstanceMethod(cls, @selector(retain));
105 RealRetain = (typeof(RealRetain))method_getImplementation(meth);
106 ((MethodListIMP *)meth)[2] = (IMP)HackRetain;
108 meth = class_getInstanceMethod(cls, @selector(autorelease));
109 RealAutorelease = (typeof(RealAutorelease))method_getImplementation(meth);
110 ((MethodListIMP *)meth)[2] = (IMP)HackAutorelease;
112 meth = class_getClassMethod(cls, @selector(alloc));
113 RealAlloc = (typeof(RealAlloc))method_getImplementation(meth);
114 ((MethodListIMP *)meth)[2] = (IMP)HackAlloc;
116 meth = class_getInstanceMethod(cls, @selector(init));
117 ((MethodListIMP *)meth)[2] = (IMP)HackInit;
119 // Verify that the swizzles occurred before +initialize by provoking it now
120 testassert(PlusInitializes == 0);
122 testassert(PlusInitializes == 1);
130 obj = objc_alloc(cls);
132 testprintf("swizzled AWZ should be called\n");
133 testassert(Allocs == 1);
134 testassert(AllocWithZones == 1);
135 testassert(Inits == 0);
137 testprintf("unswizzled AWZ should be bypassed\n");
138 testassert(Allocs == 0);
139 testassert(AllocWithZones == 0);
140 testassert(Inits == 0);
142 testassert([obj isKindOfClass:[NSObject class]]);
147 obj = [NSObject alloc];
149 testprintf("swizzled AWZ should be called\n");
150 testassert(Allocs == 1);
151 testassert(AllocWithZones == 1);
152 testassert(Inits == 0);
154 testprintf("unswizzled AWZ should be bypassed\n");
155 testassert(Allocs == 1);
156 testassert(AllocWithZones == 0);
157 testassert(Inits == 0);
159 testassert([obj isKindOfClass:[NSObject class]]);
164 obj = objc_alloc_init(cls);
166 testprintf("swizzled AWZ should be called\n");
167 testassert(Allocs == 1);
168 testassert(AllocWithZones == 1);
169 testassert(Inits == 1);
171 testprintf("unswizzled AWZ should be bypassed\n");
172 testassert(Allocs == 0);
173 testassert(AllocWithZones == 0);
174 testassert(Inits == 1); // swizzled init is still called
176 testassert([obj isKindOfClass:[NSObject class]]);
179 result = objc_retain(obj);
181 testprintf("swizzled release should force retain\n");
182 testassert(Retains == 1);
184 testprintf("unswizzled release should bypass retain\n");
185 testassert(Retains == 0);
187 testassert(result == obj);
192 result = objc_autorelease(obj);
194 testprintf("swizzled release should force autorelease\n");
195 testassert(Autoreleases == 1);
197 testprintf("unswizzled release should bypass autorelease\n");
198 testassert(Autoreleases == 0);
200 testassert(result == obj);
204 testprintf("swizzled release should be called\n");
205 testassert(Releases == 1);
207 testprintf("unswizzled release should be bypassed\n");
208 testassert(Releases == 0);
214 Class nso = objc_opt_self([NSObject class]);
215 obj = objc_opt_new(nso);
216 obj = objc_opt_self(obj);
218 testprintf("swizzled Core should be called\n");
219 testassert(PlusNew == 1);
220 testassert(Self == 1);
221 testassert(PlusSelf == 1);
223 testprintf("unswizzled CORE should be bypassed\n");
224 testassert(PlusNew == 0);
225 testassert(Self == 0);
226 testassert(PlusSelf == 0);
228 testassert([obj isKindOfClass:nso]);
230 succeed(basename(argv[0]));