]> git.saurik.com Git - apple/objc4.git/blob - test/customrr.m
8ad8a47536b3086cc8dac6a98b54b1ebac19e4a6
[apple/objc4.git] / test / customrr.m
1 // These options must match customrr2.m
2 // TEST_CONFIG MEM=mrc
3 /*
4 TEST_BUILD
5 $C{COMPILE} $DIR/customrr.m -fvisibility=default -o customrr.exe
6 $C{COMPILE} -bundle -bundle_loader customrr.exe $DIR/customrr-cat1.m -o customrr-cat1.bundle
7 $C{COMPILE} -bundle -bundle_loader customrr.exe $DIR/customrr-cat2.m -o customrr-cat2.bundle
8 END
9 */
10
11
12 #include "test.h"
13 #include <dlfcn.h>
14 #include <Foundation/NSObject.h>
15
16 static int Retains;
17 static int Releases;
18 static int Autoreleases;
19 static int RetainCounts;
20 static int PlusRetains;
21 static int PlusReleases;
22 static int PlusAutoreleases;
23 static int PlusRetainCounts;
24 static int Allocs;
25 static int AllocWithZones;
26
27 static int SubRetains;
28 static int SubReleases;
29 static int SubAutoreleases;
30 static int SubRetainCounts;
31 static int SubPlusRetains;
32 static int SubPlusReleases;
33 static int SubPlusAutoreleases;
34 static int SubPlusRetainCounts;
35 static int SubAllocs;
36 static int SubAllocWithZones;
37
38 static int Imps;
39
40 static id imp_fn(id self, SEL _cmd __unused, ...)
41 {
42 Imps++;
43 return self;
44 }
45
46 static void zero(void) {
47 Retains = 0;
48 Releases = 0;
49 Autoreleases = 0;
50 RetainCounts = 0;
51 PlusRetains = 0;
52 PlusReleases = 0;
53 PlusAutoreleases = 0;
54 PlusRetainCounts = 0;
55 Allocs = 0;
56 AllocWithZones = 0;
57
58 SubRetains = 0;
59 SubReleases = 0;
60 SubAutoreleases = 0;
61 SubRetainCounts = 0;
62 SubPlusRetains = 0;
63 SubPlusReleases = 0;
64 SubPlusAutoreleases = 0;
65 SubPlusRetainCounts = 0;
66 SubAllocs = 0;
67 SubAllocWithZones = 0;
68
69 Imps = 0;
70 }
71
72
73 id HackRetain(id self, SEL _cmd __unused) { Retains++; return self; }
74 void HackRelease(id self __unused, SEL _cmd __unused) { Releases++; }
75 id HackAutorelease(id self, SEL _cmd __unused) { Autoreleases++; return self; }
76 NSUInteger HackRetainCount(id self __unused, SEL _cmd __unused) { RetainCounts++; return 1; }
77 id HackPlusRetain(id self, SEL _cmd __unused) { PlusRetains++; return self; }
78 void HackPlusRelease(id self __unused, SEL _cmd __unused) { PlusReleases++; }
79 id HackPlusAutorelease(id self, SEL _cmd __unused) { PlusAutoreleases++; return self; }
80 NSUInteger HackPlusRetainCount(id self __unused, SEL _cmd __unused) { PlusRetainCounts++; return 1; }
81 id HackAlloc(Class self, SEL _cmd __unused) { Allocs++; return class_createInstance(self, 0); }
82 id HackAllocWithZone(Class self, SEL _cmd __unused) { AllocWithZones++; return class_createInstance(self, 0); }
83
84
85 @interface OverridingSub : NSObject @end
86 @implementation OverridingSub
87
88 -(id) retain { SubRetains++; return self; }
89 +(id) retain { SubPlusRetains++; return self; }
90 -(oneway void) release { SubReleases++; }
91 +(oneway void) release { SubPlusReleases++; }
92 -(id) autorelease { SubAutoreleases++; return self; }
93 +(id) autorelease { SubPlusAutoreleases++; return self; }
94 -(NSUInteger) retainCount { SubRetainCounts++; return 1; }
95 +(NSUInteger) retainCount { SubPlusRetainCounts++; return 1; }
96
97 @end
98
99 @interface OverridingASub : NSObject @end
100 @implementation OverridingASub
101 +(id) alloc { SubAllocs++; return class_createInstance(self, 0); }
102 @end
103
104 @interface OverridingAWZSub : NSObject @end
105 @implementation OverridingAWZSub
106 +(id) allocWithZone:(NSZone * __unused)z { SubAllocWithZones++; return class_createInstance(self, 0); }
107 @end
108
109 @interface OverridingAAWZSub : NSObject @end
110 @implementation OverridingAAWZSub
111 +(id) alloc { SubAllocs++; return class_createInstance(self, 0); }
112 +(id) allocWithZone:(NSZone * __unused)z { SubAllocWithZones++; return class_createInstance(self, 0); }
113 @end
114
115
116 @interface InheritingSub : NSObject @end
117 @implementation InheritingSub @end
118
119 @interface InheritingSub2 : NSObject @end
120 @implementation InheritingSub2 @end
121 @interface InheritingSub2_2 : InheritingSub2 @end
122 @implementation InheritingSub2_2 @end
123
124 @interface InheritingSub3 : NSObject @end
125 @implementation InheritingSub3 @end
126 @interface InheritingSub3_2 : InheritingSub3 @end
127 @implementation InheritingSub3_2 @end
128
129 @interface InheritingSub4 : NSObject @end
130 @implementation InheritingSub4 @end
131 @interface InheritingSub4_2 : InheritingSub4 @end
132 @implementation InheritingSub4_2 @end
133
134 @interface InheritingSub5 : NSObject @end
135 @implementation InheritingSub5 @end
136 @interface InheritingSub5_2 : InheritingSub5 @end
137 @implementation InheritingSub5_2 @end
138
139 @interface InheritingSub6 : NSObject @end
140 @implementation InheritingSub6 @end
141 @interface InheritingSub6_2 : InheritingSub6 @end
142 @implementation InheritingSub6_2 @end
143
144 @interface InheritingSub7 : NSObject @end
145 @implementation InheritingSub7 @end
146 @interface InheritingSub7_2 : InheritingSub7 @end
147 @implementation InheritingSub7_2 @end
148
149 @interface InheritingSubCat : NSObject @end
150 @implementation InheritingSubCat @end
151 @interface InheritingSubCat_2 : InheritingSubCat @end
152 @implementation InheritingSubCat_2 @end
153
154
155 extern uintptr_t OBJC_CLASS_$_UnrealizedSubA1;
156 @interface UnrealizedSubA1 : NSObject @end
157 @implementation UnrealizedSubA1 @end
158 extern uintptr_t OBJC_CLASS_$_UnrealizedSubA2;
159 @interface UnrealizedSubA2 : NSObject @end
160 @implementation UnrealizedSubA2 @end
161 extern uintptr_t OBJC_CLASS_$_UnrealizedSubA3;
162 @interface UnrealizedSubA3 : NSObject @end
163 @implementation UnrealizedSubA3 @end
164
165 extern uintptr_t OBJC_CLASS_$_UnrealizedSubB1;
166 @interface UnrealizedSubB1 : NSObject @end
167 @implementation UnrealizedSubB1 @end
168 extern uintptr_t OBJC_CLASS_$_UnrealizedSubB2;
169 @interface UnrealizedSubB2 : NSObject @end
170 @implementation UnrealizedSubB2 @end
171 extern uintptr_t OBJC_CLASS_$_UnrealizedSubB3;
172 @interface UnrealizedSubB3 : NSObject @end
173 @implementation UnrealizedSubB3 @end
174
175 extern uintptr_t OBJC_CLASS_$_UnrealizedSubC1;
176 @interface UnrealizedSubC1 : NSObject @end
177 @implementation UnrealizedSubC1 @end
178 extern uintptr_t OBJC_CLASS_$_UnrealizedSubC2;
179 @interface UnrealizedSubC2 : NSObject @end
180 @implementation UnrealizedSubC2 @end
181 extern uintptr_t OBJC_CLASS_$_UnrealizedSubC3;
182 @interface UnrealizedSubC3 : NSObject @end
183 @implementation UnrealizedSubC3 @end
184
185
186 int main(int argc __unused, char **argv)
187 {
188 objc_autoreleasePoolPush();
189
190 // Hack NSObject's RR methods.
191 // Don't use runtime functions to do this -
192 // we want the runtime to think that these are NSObject's real code
193 {
194 #if __has_feature(ptrauth_calls)
195 typedef IMP __ptrauth_objc_method_list_imp MethodListIMP;
196 #else
197 typedef IMP MethodListIMP;
198 #endif
199
200 Class cls = [NSObject class];
201 IMP imp = class_getMethodImplementation(cls, @selector(retain));
202 MethodListIMP *m = (MethodListIMP *)
203 class_getInstanceMethod(cls, @selector(retain));
204 testassert(m[2] == imp); // verify Method struct is as we expect
205
206 m = (MethodListIMP *)class_getInstanceMethod(cls, @selector(retain));
207 m[2] = (IMP)HackRetain;
208 m = (MethodListIMP *)class_getInstanceMethod(cls, @selector(release));
209 m[2] = (IMP)HackRelease;
210 m = (MethodListIMP *)class_getInstanceMethod(cls, @selector(autorelease));
211 m[2] = (IMP)HackAutorelease;
212 m = (MethodListIMP *)class_getInstanceMethod(cls, @selector(retainCount));
213 m[2] = (IMP)HackRetainCount;
214 m = (MethodListIMP *)class_getClassMethod(cls, @selector(retain));
215 m[2] = (IMP)HackPlusRetain;
216 m = (MethodListIMP *)class_getClassMethod(cls, @selector(release));
217 m[2] = (IMP)HackPlusRelease;
218 m = (MethodListIMP *)class_getClassMethod(cls, @selector(autorelease));
219 m[2] = (IMP)HackPlusAutorelease;
220 m = (MethodListIMP *)class_getClassMethod(cls, @selector(retainCount));
221 m[2] = (IMP)HackPlusRetainCount;
222 m = (MethodListIMP *)class_getClassMethod(cls, @selector(alloc));
223 m[2] = (IMP)HackAlloc;
224 m = (MethodListIMP *)class_getClassMethod(cls, @selector(allocWithZone:));
225 m[2] = (IMP)HackAllocWithZone;
226
227 _objc_flush_caches(cls);
228
229 imp = class_getMethodImplementation(cls, @selector(retain));
230 testassert(imp == (IMP)HackRetain); // verify hack worked
231 }
232
233 Class cls = [NSObject class];
234 Class icl = [InheritingSub class];
235 Class ocl = [OverridingSub class];
236 /*
237 Class oa1 = [OverridingASub class];
238 Class oa2 = [OverridingAWZSub class];
239 Class oa3 = [OverridingAAWZSub class];
240 */
241 NSObject *obj = [NSObject new];
242 InheritingSub *inh = [InheritingSub new];
243 OverridingSub *ovr = [OverridingSub new];
244
245 Class ccc;
246 id ooo;
247 Class cc2;
248 id oo2;
249
250 void *dlh;
251
252
253 #if __x86_64__
254 // vtable dispatch can introduce bypass just like the ARC entrypoints
255 #else
256 testprintf("method dispatch does not bypass\n");
257 zero();
258
259 [obj retain];
260 testassert(Retains == 1);
261 [obj release];
262 testassert(Releases == 1);
263 [obj autorelease];
264 testassert(Autoreleases == 1);
265
266 [cls retain];
267 testassert(PlusRetains == 1);
268 [cls release];
269 testassert(PlusReleases == 1);
270 [cls autorelease];
271 testassert(PlusAutoreleases == 1);
272
273 [inh retain];
274 testassert(Retains == 2);
275 [inh release];
276 testassert(Releases == 2);
277 [inh autorelease];
278 testassert(Autoreleases == 2);
279
280 [icl retain];
281 testassert(PlusRetains == 2);
282 [icl release];
283 testassert(PlusReleases == 2);
284 [icl autorelease];
285 testassert(PlusAutoreleases == 2);
286
287 [ovr retain];
288 testassert(SubRetains == 1);
289 [ovr release];
290 testassert(SubReleases == 1);
291 [ovr autorelease];
292 testassert(SubAutoreleases == 1);
293
294 [ocl retain];
295 testassert(SubPlusRetains == 1);
296 [ocl release];
297 testassert(SubPlusReleases == 1);
298 [ocl autorelease];
299 testassert(SubPlusAutoreleases == 1);
300
301 [UnrealizedSubA1 retain];
302 testassert(PlusRetains == 3);
303 [UnrealizedSubA2 release];
304 testassert(PlusReleases == 3);
305 [UnrealizedSubA3 autorelease];
306 testassert(PlusAutoreleases == 3);
307 #endif
308
309
310 testprintf("objc_msgSend() does not bypass\n");
311 zero();
312
313 id (*retain_fn)(id, SEL) = (id(*)(id, SEL))objc_msgSend;
314 void (*release_fn)(id, SEL) = (void(*)(id, SEL))objc_msgSend;
315 id (*autorelease_fn)(id, SEL) = (id(*)(id, SEL))objc_msgSend;
316
317 retain_fn(obj, @selector(retain));
318 testassert(Retains == 1);
319 release_fn(obj, @selector(release));
320 testassert(Releases == 1);
321 autorelease_fn(obj, @selector(autorelease));
322 testassert(Autoreleases == 1);
323
324 retain_fn(cls, @selector(retain));
325 testassert(PlusRetains == 1);
326 release_fn(cls, @selector(release));
327 testassert(PlusReleases == 1);
328 autorelease_fn(cls, @selector(autorelease));
329 testassert(PlusAutoreleases == 1);
330
331 retain_fn(inh, @selector(retain));
332 testassert(Retains == 2);
333 release_fn(inh, @selector(release));
334 testassert(Releases == 2);
335 autorelease_fn(inh, @selector(autorelease));
336 testassert(Autoreleases == 2);
337
338 retain_fn(icl, @selector(retain));
339 testassert(PlusRetains == 2);
340 release_fn(icl, @selector(release));
341 testassert(PlusReleases == 2);
342 autorelease_fn(icl, @selector(autorelease));
343 testassert(PlusAutoreleases == 2);
344
345 retain_fn(ovr, @selector(retain));
346 testassert(SubRetains == 1);
347 release_fn(ovr, @selector(release));
348 testassert(SubReleases == 1);
349 autorelease_fn(ovr, @selector(autorelease));
350 testassert(SubAutoreleases == 1);
351
352 retain_fn(ocl, @selector(retain));
353 testassert(SubPlusRetains == 1);
354 release_fn(ocl, @selector(release));
355 testassert(SubPlusReleases == 1);
356 autorelease_fn(ocl, @selector(autorelease));
357 testassert(SubPlusAutoreleases == 1);
358
359 retain_fn((Class)&OBJC_CLASS_$_UnrealizedSubB1, @selector(retain));
360 testassert(PlusRetains == 3);
361 release_fn((Class)&OBJC_CLASS_$_UnrealizedSubB2, @selector(release));
362 testassert(PlusReleases == 3);
363 autorelease_fn((Class)&OBJC_CLASS_$_UnrealizedSubB3, @selector(autorelease));
364 testassert(PlusAutoreleases == 3);
365
366
367 testprintf("arc function bypasses instance but not class or override\n");
368 zero();
369
370 objc_retain(obj);
371 testassert(Retains == 0);
372 objc_release(obj);
373 testassert(Releases == 0);
374 objc_autorelease(obj);
375 testassert(Autoreleases == 0);
376
377 objc_retain(cls);
378 testassert(PlusRetains == 1);
379 objc_release(cls);
380 testassert(PlusReleases == 1);
381 objc_autorelease(cls);
382 testassert(PlusAutoreleases == 1);
383
384 objc_retain(inh);
385 testassert(Retains == 0);
386 objc_release(inh);
387 testassert(Releases == 0);
388 objc_autorelease(inh);
389 testassert(Autoreleases == 0);
390
391 objc_retain(icl);
392 testassert(PlusRetains == 2);
393 objc_release(icl);
394 testassert(PlusReleases == 2);
395 objc_autorelease(icl);
396 testassert(PlusAutoreleases == 2);
397
398 objc_retain(ovr);
399 testassert(SubRetains == 1);
400 objc_release(ovr);
401 testassert(SubReleases == 1);
402 objc_autorelease(ovr);
403 testassert(SubAutoreleases == 1);
404
405 objc_retain(ocl);
406 testassert(SubPlusRetains == 1);
407 objc_release(ocl);
408 testassert(SubPlusReleases == 1);
409 objc_autorelease(ocl);
410 testassert(SubPlusAutoreleases == 1);
411
412 objc_retain((Class)&OBJC_CLASS_$_UnrealizedSubC1);
413 testassert(PlusRetains == 3);
414 objc_release((Class)&OBJC_CLASS_$_UnrealizedSubC2);
415 testassert(PlusReleases == 3);
416 objc_autorelease((Class)&OBJC_CLASS_$_UnrealizedSubC3);
417 testassert(PlusAutoreleases == 3);
418
419
420 testprintf("unrelated addMethod does not clobber\n");
421 zero();
422
423 class_addMethod(cls, @selector(unrelatedMethod), (IMP)imp_fn, "");
424
425 objc_retain(obj);
426 testassert(Retains == 0);
427 objc_release(obj);
428 testassert(Releases == 0);
429 objc_autorelease(obj);
430 testassert(Autoreleases == 0);
431
432
433 testprintf("add class method does not clobber\n");
434 zero();
435
436 objc_retain(obj);
437 testassert(Retains == 0);
438 objc_release(obj);
439 testassert(Releases == 0);
440 objc_autorelease(obj);
441 testassert(Autoreleases == 0);
442
443 class_addMethod(object_getClass(cls), @selector(retain), (IMP)imp_fn, "");
444
445 objc_retain(obj);
446 testassert(Retains == 0);
447 objc_release(obj);
448 testassert(Releases == 0);
449 objc_autorelease(obj);
450 testassert(Autoreleases == 0);
451
452
453 testprintf("addMethod clobbers (InheritingSub2, retain)\n");
454 zero();
455
456 ccc = [InheritingSub2 class];
457 ooo = [ccc new];
458 cc2 = [InheritingSub2_2 class];
459 oo2 = [cc2 new];
460
461 objc_retain(ooo);
462 testassert(Retains == 0);
463 objc_release(ooo);
464 testassert(Releases == 0);
465 objc_autorelease(ooo);
466 testassert(Autoreleases == 0);
467
468 objc_retain(oo2);
469 testassert(Retains == 0);
470 objc_release(oo2);
471 testassert(Releases == 0);
472 objc_autorelease(oo2);
473 testassert(Autoreleases == 0);
474
475 class_addMethod(ccc, @selector(retain), (IMP)imp_fn, "");
476
477 objc_retain(ooo);
478 testassert(Retains == 0);
479 testassert(Imps == 1);
480 objc_release(ooo);
481 testassert(Releases == 1);
482 objc_autorelease(ooo);
483 testassert(Autoreleases == 1);
484
485 objc_retain(oo2);
486 testassert(Retains == 0);
487 testassert(Imps == 2);
488 objc_release(oo2);
489 testassert(Releases == 2);
490 objc_autorelease(oo2);
491 testassert(Autoreleases == 2);
492
493
494 testprintf("addMethod clobbers (InheritingSub3, release)\n");
495 zero();
496
497 ccc = [InheritingSub3 class];
498 ooo = [ccc new];
499 cc2 = [InheritingSub3_2 class];
500 oo2 = [cc2 new];
501
502 objc_retain(ooo);
503 testassert(Retains == 0);
504 objc_release(ooo);
505 testassert(Releases == 0);
506 objc_autorelease(ooo);
507 testassert(Autoreleases == 0);
508
509 objc_retain(oo2);
510 testassert(Retains == 0);
511 objc_release(oo2);
512 testassert(Releases == 0);
513 objc_autorelease(oo2);
514 testassert(Autoreleases == 0);
515
516 class_addMethod(ccc, @selector(release), (IMP)imp_fn, "");
517
518 objc_retain(ooo);
519 testassert(Retains == 1);
520 objc_release(ooo);
521 testassert(Releases == 0);
522 testassert(Imps == 1);
523 objc_autorelease(ooo);
524 testassert(Autoreleases == 1);
525
526 objc_retain(oo2);
527 testassert(Retains == 2);
528 objc_release(oo2);
529 testassert(Releases == 0);
530 testassert(Imps == 2);
531 objc_autorelease(oo2);
532 testassert(Autoreleases == 2);
533
534
535 testprintf("addMethod clobbers (InheritingSub4, autorelease)\n");
536 zero();
537
538 ccc = [InheritingSub4 class];
539 ooo = [ccc new];
540 cc2 = [InheritingSub4_2 class];
541 oo2 = [cc2 new];
542
543 objc_retain(ooo);
544 testassert(Retains == 0);
545 objc_release(ooo);
546 testassert(Releases == 0);
547 objc_autorelease(ooo);
548 testassert(Autoreleases == 0);
549
550 objc_retain(oo2);
551 testassert(Retains == 0);
552 objc_release(oo2);
553 testassert(Releases == 0);
554 objc_autorelease(oo2);
555 testassert(Autoreleases == 0);
556
557 class_addMethod(ccc, @selector(autorelease), (IMP)imp_fn, "");
558
559 objc_retain(ooo);
560 testassert(Retains == 1);
561 objc_release(ooo);
562 testassert(Releases == 1);
563 objc_autorelease(ooo);
564 testassert(Autoreleases == 0);
565 testassert(Imps == 1);
566
567 objc_retain(oo2);
568 testassert(Retains == 2);
569 objc_release(oo2);
570 testassert(Releases == 2);
571 objc_autorelease(oo2);
572 testassert(Autoreleases == 0);
573 testassert(Imps == 2);
574
575
576 testprintf("addMethod clobbers (InheritingSub5, retainCount)\n");
577 zero();
578
579 ccc = [InheritingSub5 class];
580 ooo = [ccc new];
581 cc2 = [InheritingSub5_2 class];
582 oo2 = [cc2 new];
583
584 objc_retain(ooo);
585 testassert(Retains == 0);
586 objc_release(ooo);
587 testassert(Releases == 0);
588 objc_autorelease(ooo);
589 testassert(Autoreleases == 0);
590
591 objc_retain(oo2);
592 testassert(Retains == 0);
593 objc_release(oo2);
594 testassert(Releases == 0);
595 objc_autorelease(oo2);
596 testassert(Autoreleases == 0);
597
598 class_addMethod(ccc, @selector(retainCount), (IMP)imp_fn, "");
599
600 objc_retain(ooo);
601 testassert(Retains == 1);
602 objc_release(ooo);
603 testassert(Releases == 1);
604 objc_autorelease(ooo);
605 testassert(Autoreleases == 1);
606 // no bypassing call for -retainCount
607
608 objc_retain(oo2);
609 testassert(Retains == 2);
610 objc_release(oo2);
611 testassert(Releases == 2);
612 objc_autorelease(oo2);
613 testassert(Autoreleases == 2);
614 // no bypassing call for -retainCount
615
616
617 testprintf("setSuperclass to clean super does not clobber (InheritingSub6)\n");
618 zero();
619
620 ccc = [InheritingSub6 class];
621 ooo = [ccc new];
622 cc2 = [InheritingSub6_2 class];
623 oo2 = [cc2 new];
624
625 objc_retain(ooo);
626 testassert(Retains == 0);
627 objc_release(ooo);
628 testassert(Releases == 0);
629 objc_autorelease(ooo);
630 testassert(Autoreleases == 0);
631
632 objc_retain(oo2);
633 testassert(Retains == 0);
634 objc_release(oo2);
635 testassert(Releases == 0);
636 objc_autorelease(oo2);
637 testassert(Autoreleases == 0);
638
639 class_setSuperclass(ccc, [InheritingSub class]);
640
641 objc_retain(ooo);
642 testassert(Retains == 0);
643 objc_release(ooo);
644 testassert(Releases == 0);
645 objc_autorelease(ooo);
646 testassert(Autoreleases == 0);
647
648 objc_retain(oo2);
649 testassert(Retains == 0);
650 objc_release(oo2);
651 testassert(Releases == 0);
652 objc_autorelease(oo2);
653 testassert(Autoreleases == 0);
654
655
656 testprintf("setSuperclass to dirty super clobbers (InheritingSub7)\n");
657 zero();
658
659 ccc = [InheritingSub7 class];
660 ooo = [ccc new];
661 cc2 = [InheritingSub7_2 class];
662 oo2 = [cc2 new];
663
664 objc_retain(ooo);
665 testassert(Retains == 0);
666 objc_release(ooo);
667 testassert(Releases == 0);
668 objc_autorelease(ooo);
669 testassert(Autoreleases == 0);
670
671 objc_retain(oo2);
672 testassert(Retains == 0);
673 objc_release(oo2);
674 testassert(Releases == 0);
675 objc_autorelease(oo2);
676 testassert(Autoreleases == 0);
677
678 class_setSuperclass(ccc, [OverridingSub class]);
679
680 objc_retain(ooo);
681 testassert(SubRetains == 1);
682 objc_release(ooo);
683 testassert(SubReleases == 1);
684 objc_autorelease(ooo);
685 testassert(SubAutoreleases == 1);
686
687 objc_retain(oo2);
688 testassert(SubRetains == 2);
689 objc_release(oo2);
690 testassert(SubReleases == 2);
691 objc_autorelease(oo2);
692 testassert(SubAutoreleases == 2);
693
694
695 testprintf("category replacement of unrelated method does not clobber (InheritingSubCat)\n");
696 zero();
697
698 ccc = [InheritingSubCat class];
699 ooo = [ccc new];
700 cc2 = [InheritingSubCat_2 class];
701 oo2 = [cc2 new];
702
703 objc_retain(ooo);
704 testassert(Retains == 0);
705 objc_release(ooo);
706 testassert(Releases == 0);
707 objc_autorelease(ooo);
708 testassert(Autoreleases == 0);
709
710 objc_retain(oo2);
711 testassert(Retains == 0);
712 objc_release(oo2);
713 testassert(Releases == 0);
714 objc_autorelease(oo2);
715 testassert(Autoreleases == 0);
716
717 dlh = dlopen("customrr-cat1.bundle", RTLD_LAZY);
718 testassert(dlh);
719
720 objc_retain(ooo);
721 testassert(Retains == 0);
722 objc_release(ooo);
723 testassert(Releases == 0);
724 objc_autorelease(ooo);
725 testassert(Autoreleases == 0);
726
727 objc_retain(oo2);
728 testassert(Retains == 0);
729 objc_release(oo2);
730 testassert(Releases == 0);
731 objc_autorelease(oo2);
732 testassert(Autoreleases == 0);
733
734
735 testprintf("category replacement clobbers (InheritingSubCat)\n");
736 zero();
737
738 ccc = [InheritingSubCat class];
739 ooo = [ccc new];
740 cc2 = [InheritingSubCat_2 class];
741 oo2 = [cc2 new];
742
743 objc_retain(ooo);
744 testassert(Retains == 0);
745 objc_release(ooo);
746 testassert(Releases == 0);
747 objc_autorelease(ooo);
748 testassert(Autoreleases == 0);
749
750 objc_retain(oo2);
751 testassert(Retains == 0);
752 objc_release(oo2);
753 testassert(Releases == 0);
754 objc_autorelease(oo2);
755 testassert(Autoreleases == 0);
756
757 dlh = dlopen("customrr-cat2.bundle", RTLD_LAZY);
758 testassert(dlh);
759
760 objc_retain(ooo);
761 testassert(Retains == 1);
762 objc_release(ooo);
763 testassert(Releases == 1);
764 objc_autorelease(ooo);
765 testassert(Autoreleases == 1);
766
767 objc_retain(oo2);
768 testassert(Retains == 2);
769 objc_release(oo2);
770 testassert(Releases == 2);
771 objc_autorelease(oo2);
772 testassert(Autoreleases == 2);
773
774
775 testprintf("allocateClassPair with clean super does not clobber\n");
776 zero();
777
778 objc_retain(inh);
779 testassert(Retains == 0);
780 objc_release(inh);
781 testassert(Releases == 0);
782 objc_autorelease(inh);
783 testassert(Autoreleases == 0);
784
785 ccc = objc_allocateClassPair([InheritingSub class], "CleanClassPair", 0);
786 objc_registerClassPair(ccc);
787 ooo = [ccc new];
788
789 objc_retain(inh);
790 testassert(Retains == 0);
791 objc_release(inh);
792 testassert(Releases == 0);
793 objc_autorelease(inh);
794 testassert(Autoreleases == 0);
795
796 objc_retain(ooo);
797 testassert(Retains == 0);
798 objc_release(ooo);
799 testassert(Releases == 0);
800 objc_autorelease(ooo);
801 testassert(Autoreleases == 0);
802
803
804 testprintf("allocateClassPair with clobbered super clobbers\n");
805 zero();
806
807 ccc = objc_allocateClassPair([OverridingSub class], "DirtyClassPair", 0);
808 objc_registerClassPair(ccc);
809 ooo = [ccc new];
810
811 objc_retain(ooo);
812 testassert(SubRetains == 1);
813 objc_release(ooo);
814 testassert(SubReleases == 1);
815 objc_autorelease(ooo);
816 testassert(SubAutoreleases == 1);
817
818
819 testprintf("allocateClassPair with clean super and override clobbers\n");
820 zero();
821
822 ccc = objc_allocateClassPair([InheritingSub class], "Dirty2ClassPair", 0);
823 class_addMethod(ccc, @selector(autorelease), (IMP)imp_fn, "");
824 objc_registerClassPair(ccc);
825 ooo = [ccc new];
826
827 objc_retain(ooo);
828 testassert(Retains == 1);
829 objc_release(ooo);
830 testassert(Releases == 1);
831 objc_autorelease(ooo);
832 testassert(Autoreleases == 0);
833 testassert(Imps == 1);
834
835
836 // method_setImplementation and method_exchangeImplementations only
837 // clobber when manipulating NSObject. We can only test one at a time.
838 // To test both, we need two tests: customrr and customrr2.
839
840 // These tests also check recursive clobber.
841
842 #if TEST_EXCHANGEIMPLEMENTATIONS
843 testprintf("exchangeImplementations clobbers (recursive)\n");
844 #else
845 testprintf("setImplementation clobbers (recursive)\n");
846 #endif
847 zero();
848
849 objc_retain(obj);
850 testassert(Retains == 0);
851 objc_release(obj);
852 testassert(Releases == 0);
853 objc_autorelease(obj);
854 testassert(Autoreleases == 0);
855
856 objc_retain(inh);
857 testassert(Retains == 0);
858 objc_release(inh);
859 testassert(Releases == 0);
860 objc_autorelease(inh);
861 testassert(Autoreleases == 0);
862
863 Method meth = class_getInstanceMethod(cls, @selector(retainCount));
864 testassert(meth);
865 #if TEST_EXCHANGEIMPLEMENTATIONS
866 method_exchangeImplementations(meth, meth);
867 #else
868 method_setImplementation(meth, (IMP)imp_fn);
869 #endif
870
871 objc_retain(obj);
872 testassert(Retains == 1);
873 objc_release(obj);
874 testassert(Releases == 1);
875 objc_autorelease(obj);
876 testassert(Autoreleases == 1);
877
878 objc_retain(inh);
879 testassert(Retains == 2);
880 objc_release(inh);
881 testassert(Releases == 2);
882 objc_autorelease(inh);
883 testassert(Autoreleases == 2);
884
885
886 // do not add more tests here - the recursive test must be LAST
887
888 succeed(basename(argv[0]));
889 }