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;
13 EXTERN_C void _method_setImplementationRawUnsafe(Method m, IMP imp);
17 static int Autoreleases;
18 static int PlusInitializes;
20 static int AllocWithZones;
26 id (*RealRetain)(id self, SEL _cmd);
27 void (*RealRelease)(id self, SEL _cmd);
28 id (*RealAutorelease)(id self, SEL _cmd);
29 id (*RealAlloc)(id self, SEL _cmd);
30 id (*RealAllocWithZone)(id self, SEL _cmd, void *zone);
31 id (*RealPlusNew)(id self, SEL _cmd);
32 id (*RealSelf)(id self);
33 id (*RealPlusSelf)(id self);
35 id HackRetain(id self, SEL _cmd) { Retains++; return RealRetain(self, _cmd); }
36 void HackRelease(id self, SEL _cmd) { Releases++; return RealRelease(self, _cmd); }
37 id HackAutorelease(id self, SEL _cmd) { Autoreleases++; return RealAutorelease(self, _cmd); }
39 id HackAlloc(Class self, SEL _cmd) { Allocs++; return RealAlloc(self, _cmd); }
40 id HackAllocWithZone(Class self, SEL _cmd, void *zone) { AllocWithZones++; return RealAllocWithZone(self, _cmd, zone); }
42 void HackPlusInitialize(id self __unused, SEL _cmd __unused) { PlusInitializes++; }
44 id HackInit(id self, SEL _cmd __unused) { Inits++; return self; }
46 id HackPlusNew(id self, SEL _cmd __unused) { PlusNew++; return RealPlusNew(self, _cmd); }
47 id HackSelf(id self) { Self++; return RealSelf(self); }
48 id HackPlusSelf(id self) { PlusSelf++; return RealPlusSelf(self); }
51 int main(int argc __unused, char **argv)
53 Class cls = objc_getClass("NSObject");
56 meth = class_getClassMethod(cls, @selector(initialize));
57 method_setImplementation(meth, (IMP)HackPlusInitialize);
59 // We either swizzle the method normally (testing that it properly
60 // disables optimizations), or we hack the implementation into place
61 // behind objc's back (so we can see whether it got called with the
62 // optimizations still enabled).
64 meth = class_getClassMethod(cls, @selector(allocWithZone:));
65 RealAllocWithZone = (typeof(RealAllocWithZone))method_getImplementation(meth);
67 method_setImplementation(meth, (IMP)HackAllocWithZone);
69 _method_setImplementationRawUnsafe(meth, (IMP)HackAllocWithZone);
72 meth = class_getClassMethod(cls, @selector(new));
73 RealPlusNew = (typeof(RealPlusNew))method_getImplementation(meth);
75 method_setImplementation(meth, (IMP)HackPlusNew);
77 _method_setImplementationRawUnsafe(meth, (IMP)HackPlusNew);
80 meth = class_getClassMethod(cls, @selector(self));
81 RealPlusSelf = (typeof(RealPlusSelf))method_getImplementation(meth);
83 method_setImplementation(meth, (IMP)HackPlusSelf);
85 _method_setImplementationRawUnsafe(meth, (IMP)HackPlusSelf);
88 meth = class_getInstanceMethod(cls, @selector(self));
89 RealSelf = (typeof(RealSelf))method_getImplementation(meth);
91 method_setImplementation(meth, (IMP)HackSelf);
93 _method_setImplementationRawUnsafe(meth, (IMP)HackSelf);
96 meth = class_getInstanceMethod(cls, @selector(release));
97 RealRelease = (typeof(RealRelease))method_getImplementation(meth);
99 method_setImplementation(meth, (IMP)HackRelease);
101 _method_setImplementationRawUnsafe(meth, (IMP)HackRelease);
104 // These other methods get hacked for counting purposes only
106 meth = class_getInstanceMethod(cls, @selector(retain));
107 RealRetain = (typeof(RealRetain))method_getImplementation(meth);
108 _method_setImplementationRawUnsafe(meth, (IMP)HackRetain);
110 meth = class_getInstanceMethod(cls, @selector(autorelease));
111 RealAutorelease = (typeof(RealAutorelease))method_getImplementation(meth);
112 _method_setImplementationRawUnsafe(meth, (IMP)HackAutorelease);
114 meth = class_getClassMethod(cls, @selector(alloc));
115 RealAlloc = (typeof(RealAlloc))method_getImplementation(meth);
116 _method_setImplementationRawUnsafe(meth, (IMP)HackAlloc);
118 meth = class_getInstanceMethod(cls, @selector(init));
119 _method_setImplementationRawUnsafe(meth, (IMP)HackInit);
121 // Verify that the swizzles occurred before +initialize by provoking it now
122 testassert(PlusInitializes == 0);
124 testassert(PlusInitializes == 1);
132 obj = objc_alloc(cls);
134 testprintf("swizzled AWZ should be called\n");
135 testassert(Allocs == 1);
136 testassert(AllocWithZones == 1);
137 testassert(Inits == 0);
139 testprintf("unswizzled AWZ should be bypassed\n");
140 testassert(Allocs == 0);
141 testassert(AllocWithZones == 0);
142 testassert(Inits == 0);
144 testassert([obj isKindOfClass:[NSObject class]]);
149 obj = [NSObject alloc];
151 testprintf("swizzled AWZ should be called\n");
152 testassert(Allocs == 1);
153 testassert(AllocWithZones == 1);
154 testassert(Inits == 0);
156 testprintf("unswizzled AWZ should be bypassed\n");
157 testassert(Allocs == 1);
158 testassert(AllocWithZones == 0);
159 testassert(Inits == 0);
161 testassert([obj isKindOfClass:[NSObject class]]);
166 obj = objc_alloc_init(cls);
168 testprintf("swizzled AWZ should be called\n");
169 testassert(Allocs == 1);
170 testassert(AllocWithZones == 1);
171 testassert(Inits == 1);
173 testprintf("unswizzled AWZ should be bypassed\n");
174 testassert(Allocs == 0);
175 testassert(AllocWithZones == 0);
176 testassert(Inits == 1); // swizzled init is still called
178 testassert([obj isKindOfClass:[NSObject class]]);
181 result = objc_retain(obj);
183 testprintf("swizzled release should force retain\n");
184 testassert(Retains == 1);
186 testprintf("unswizzled release should bypass retain\n");
187 testassert(Retains == 0);
189 testassert(result == obj);
194 result = objc_autorelease(obj);
196 testprintf("swizzled release should force autorelease\n");
197 testassert(Autoreleases == 1);
199 testprintf("unswizzled release should bypass autorelease\n");
200 testassert(Autoreleases == 0);
202 testassert(result == obj);
206 testprintf("swizzled release should be called\n");
207 testassert(Releases == 1);
209 testprintf("unswizzled release should be bypassed\n");
210 testassert(Releases == 0);
216 Class nso = objc_opt_self([NSObject class]);
217 obj = objc_opt_new(nso);
218 obj = objc_opt_self(obj);
220 testprintf("swizzled Core should be called\n");
221 testassert(PlusNew == 1);
222 testassert(Self == 1);
223 testassert(PlusSelf == 1);
225 testprintf("unswizzled CORE should be bypassed\n");
226 testassert(PlusNew == 0);
227 testassert(Self == 0);
228 testassert(PlusSelf == 0);
230 testassert([obj isKindOfClass:nso]);
232 succeed(basename(argv[0]));