]> git.saurik.com Git - apple/objc4.git/blob - test/customrr.m
objc4-551.1.tar.gz
[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.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
8 END
9 */
10
11
12 #include "test.h"
13 #include <dlfcn.h>
14 #include <Foundation/NSObject.h>
15
16 #if !__OBJC2__
17
18 // pacify exported symbols list
19 OBJC_ROOT_CLASS
20 @interface InheritingSubCat @end
21 @implementation InheritingSubCat @end
22
23 int main(int argc __unused, char **argv)
24 {
25 succeed(basename(argv[0]));
26 }
27
28 #else
29
30 static int Retains;
31 static int Releases;
32 static int Autoreleases;
33 static int RetainCounts;
34 static int PlusRetains;
35 static int PlusReleases;
36 static int PlusAutoreleases;
37 static int PlusRetainCounts;
38 static int Allocs;
39 static int AllocWithZones;
40
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;
49 static int SubAllocs;
50 static int SubAllocWithZones;
51
52 static int Imps;
53
54 static id imp_fn(id self, SEL _cmd __unused, ...)
55 {
56 Imps++;
57 return self;
58 }
59
60 static void zero(void) {
61 Retains = 0;
62 Releases = 0;
63 Autoreleases = 0;
64 RetainCounts = 0;
65 PlusRetains = 0;
66 PlusReleases = 0;
67 PlusAutoreleases = 0;
68 PlusRetainCounts = 0;
69 Allocs = 0;
70 AllocWithZones = 0;
71
72 SubRetains = 0;
73 SubReleases = 0;
74 SubAutoreleases = 0;
75 SubRetainCounts = 0;
76 SubPlusRetains = 0;
77 SubPlusReleases = 0;
78 SubPlusAutoreleases = 0;
79 SubPlusRetainCounts = 0;
80 SubAllocs = 0;
81 SubAllocWithZones = 0;
82
83 Imps = 0;
84 }
85
86
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); }
97
98
99 @interface OverridingSub : NSObject @end
100 @implementation OverridingSub
101
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; }
110
111 @end
112
113 @interface OverridingASub : NSObject @end
114 @implementation OverridingASub
115 +(id) alloc { SubAllocs++; return class_createInstance(self, 0); }
116 @end
117
118 @interface OverridingAWZSub : NSObject @end
119 @implementation OverridingAWZSub
120 +(id) allocWithZone:(NSZone * __unused)z { SubAllocWithZones++; return class_createInstance(self, 0); }
121 @end
122
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); }
127 @end
128
129
130 @interface InheritingSub : NSObject @end
131 @implementation InheritingSub @end
132
133 @interface InheritingSub2 : NSObject @end
134 @implementation InheritingSub2 @end
135 @interface InheritingSub2_2 : InheritingSub2 @end
136 @implementation InheritingSub2_2 @end
137
138 @interface InheritingSub3 : NSObject @end
139 @implementation InheritingSub3 @end
140 @interface InheritingSub3_2 : InheritingSub3 @end
141 @implementation InheritingSub3_2 @end
142
143 @interface InheritingSub4 : NSObject @end
144 @implementation InheritingSub4 @end
145 @interface InheritingSub4_2 : InheritingSub4 @end
146 @implementation InheritingSub4_2 @end
147
148 @interface InheritingSub5 : NSObject @end
149 @implementation InheritingSub5 @end
150 @interface InheritingSub5_2 : InheritingSub5 @end
151 @implementation InheritingSub5_2 @end
152
153 @interface InheritingSub6 : NSObject @end
154 @implementation InheritingSub6 @end
155 @interface InheritingSub6_2 : InheritingSub6 @end
156 @implementation InheritingSub6_2 @end
157
158 @interface InheritingSub7 : NSObject @end
159 @implementation InheritingSub7 @end
160 @interface InheritingSub7_2 : InheritingSub7 @end
161 @implementation InheritingSub7_2 @end
162
163 @interface InheritingSubCat : NSObject @end
164 @implementation InheritingSubCat @end
165 @interface InheritingSubCat_2 : InheritingSubCat @end
166 @implementation InheritingSubCat_2 @end
167
168
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
178
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
188
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
198
199
200 int main(int argc __unused, char **argv)
201 {
202 objc_autoreleasePoolPush();
203
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
207 {
208 Class cls = [NSObject class];
209 IMP *m;
210 IMP imp;
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
214
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;
235
236 _objc_flush_caches(cls);
237
238 imp = class_getMethodImplementation(cls, @selector(retain));
239 testassert(imp == (IMP)HackRetain); // verify hack worked
240 }
241
242 Class cls = [NSObject class];
243 Class icl = [InheritingSub class];
244 Class ocl = [OverridingSub class];
245 /*
246 Class oa1 = [OverridingASub class];
247 Class oa2 = [OverridingAWZSub class];
248 Class oa3 = [OverridingAAWZSub class];
249 */
250 NSObject *obj = [NSObject new];
251 InheritingSub *inh = [InheritingSub new];
252 OverridingSub *ovr = [OverridingSub new];
253
254 Class ccc;
255 id ooo;
256 Class cc2;
257 id oo2;
258
259 void *dlh;
260
261
262 testprintf("method dispatch does not bypass\n");
263 zero();
264
265 [obj retain];
266 testassert(Retains == 1);
267 [obj release];
268 testassert(Releases == 1);
269 [obj autorelease];
270 testassert(Autoreleases == 1);
271
272 [cls retain];
273 testassert(PlusRetains == 1);
274 [cls release];
275 testassert(PlusReleases == 1);
276 [cls autorelease];
277 testassert(PlusAutoreleases == 1);
278
279 [inh retain];
280 testassert(Retains == 2);
281 [inh release];
282 testassert(Releases == 2);
283 [inh autorelease];
284 testassert(Autoreleases == 2);
285
286 [icl retain];
287 testassert(PlusRetains == 2);
288 [icl release];
289 testassert(PlusReleases == 2);
290 [icl autorelease];
291 testassert(PlusAutoreleases == 2);
292
293 [ovr retain];
294 testassert(SubRetains == 1);
295 [ovr release];
296 testassert(SubReleases == 1);
297 [ovr autorelease];
298 testassert(SubAutoreleases == 1);
299
300 [ocl retain];
301 testassert(SubPlusRetains == 1);
302 [ocl release];
303 testassert(SubPlusReleases == 1);
304 [ocl autorelease];
305 testassert(SubPlusAutoreleases == 1);
306
307 [UnrealizedSubA1 retain];
308 testassert(PlusRetains == 3);
309 [UnrealizedSubA2 release];
310 testassert(PlusReleases == 3);
311 [UnrealizedSubA3 autorelease];
312 testassert(PlusAutoreleases == 3);
313
314
315 testprintf("objc_msgSend() does not bypass\n");
316 zero();
317
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;
321
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);
328
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);
335
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);
342
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);
349
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);
356
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);
363
364 #if __OBJC2__
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);
371 #endif
372
373
374 testprintf("arc function bypasses instance but not class or override\n");
375 zero();
376
377 objc_retain(obj);
378 testassert(Retains == 0);
379 objc_release(obj);
380 testassert(Releases == 0);
381 objc_autorelease(obj);
382 testassert(Autoreleases == 0);
383
384 objc_retain(cls);
385 testassert(PlusRetains == 1);
386 objc_release(cls);
387 testassert(PlusReleases == 1);
388 objc_autorelease(cls);
389 testassert(PlusAutoreleases == 1);
390
391 objc_retain(inh);
392 testassert(Retains == 0);
393 objc_release(inh);
394 testassert(Releases == 0);
395 objc_autorelease(inh);
396 testassert(Autoreleases == 0);
397
398 objc_retain(icl);
399 testassert(PlusRetains == 2);
400 objc_release(icl);
401 testassert(PlusReleases == 2);
402 objc_autorelease(icl);
403 testassert(PlusAutoreleases == 2);
404
405 objc_retain(ovr);
406 testassert(SubRetains == 1);
407 objc_release(ovr);
408 testassert(SubReleases == 1);
409 objc_autorelease(ovr);
410 testassert(SubAutoreleases == 1);
411
412 objc_retain(ocl);
413 testassert(SubPlusRetains == 1);
414 objc_release(ocl);
415 testassert(SubPlusReleases == 1);
416 objc_autorelease(ocl);
417 testassert(SubPlusAutoreleases == 1);
418
419 #if __OBJC2__
420 #if 1
421 testwarn("rdar://12961688 CustomRR is wrong for unrealized classes");
422 #else
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);
429 #endif
430 #endif
431
432
433 testprintf("unrelated addMethod does not clobber\n");
434 zero();
435
436 class_addMethod(cls, @selector(unrelatedMethod), (IMP)imp_fn, "");
437
438 objc_retain(obj);
439 testassert(Retains == 0);
440 objc_release(obj);
441 testassert(Releases == 0);
442 objc_autorelease(obj);
443 testassert(Autoreleases == 0);
444
445
446 testprintf("add class method does not clobber\n");
447 zero();
448
449 objc_retain(obj);
450 testassert(Retains == 0);
451 objc_release(obj);
452 testassert(Releases == 0);
453 objc_autorelease(obj);
454 testassert(Autoreleases == 0);
455
456 class_addMethod(cls->isa, @selector(retain), (IMP)imp_fn, "");
457
458 objc_retain(obj);
459 testassert(Retains == 0);
460 objc_release(obj);
461 testassert(Releases == 0);
462 objc_autorelease(obj);
463 testassert(Autoreleases == 0);
464
465
466 testprintf("addMethod clobbers (InheritingSub2, retain)\n");
467 zero();
468
469 ccc = [InheritingSub2 class];
470 ooo = [ccc new];
471 cc2 = [InheritingSub2_2 class];
472 oo2 = [cc2 new];
473
474 objc_retain(ooo);
475 testassert(Retains == 0);
476 objc_release(ooo);
477 testassert(Releases == 0);
478 objc_autorelease(ooo);
479 testassert(Autoreleases == 0);
480
481 objc_retain(oo2);
482 testassert(Retains == 0);
483 objc_release(oo2);
484 testassert(Releases == 0);
485 objc_autorelease(oo2);
486 testassert(Autoreleases == 0);
487
488 class_addMethod(ccc, @selector(retain), (IMP)imp_fn, "");
489
490 objc_retain(ooo);
491 testassert(Retains == 0);
492 testassert(Imps == 1);
493 objc_release(ooo);
494 testassert(Releases == 1);
495 objc_autorelease(ooo);
496 testassert(Autoreleases == 1);
497
498 objc_retain(oo2);
499 testassert(Retains == 0);
500 testassert(Imps == 2);
501 objc_release(oo2);
502 testassert(Releases == 2);
503 objc_autorelease(oo2);
504 testassert(Autoreleases == 2);
505
506
507 testprintf("addMethod clobbers (InheritingSub3, release)\n");
508 zero();
509
510 ccc = [InheritingSub3 class];
511 ooo = [ccc new];
512 cc2 = [InheritingSub3_2 class];
513 oo2 = [cc2 new];
514
515 objc_retain(ooo);
516 testassert(Retains == 0);
517 objc_release(ooo);
518 testassert(Releases == 0);
519 objc_autorelease(ooo);
520 testassert(Autoreleases == 0);
521
522 objc_retain(oo2);
523 testassert(Retains == 0);
524 objc_release(oo2);
525 testassert(Releases == 0);
526 objc_autorelease(oo2);
527 testassert(Autoreleases == 0);
528
529 class_addMethod(ccc, @selector(release), (IMP)imp_fn, "");
530
531 objc_retain(ooo);
532 testassert(Retains == 1);
533 objc_release(ooo);
534 testassert(Releases == 0);
535 testassert(Imps == 1);
536 objc_autorelease(ooo);
537 testassert(Autoreleases == 1);
538
539 objc_retain(oo2);
540 testassert(Retains == 2);
541 objc_release(oo2);
542 testassert(Releases == 0);
543 testassert(Imps == 2);
544 objc_autorelease(oo2);
545 testassert(Autoreleases == 2);
546
547
548 testprintf("addMethod clobbers (InheritingSub4, autorelease)\n");
549 zero();
550
551 ccc = [InheritingSub4 class];
552 ooo = [ccc new];
553 cc2 = [InheritingSub4_2 class];
554 oo2 = [cc2 new];
555
556 objc_retain(ooo);
557 testassert(Retains == 0);
558 objc_release(ooo);
559 testassert(Releases == 0);
560 objc_autorelease(ooo);
561 testassert(Autoreleases == 0);
562
563 objc_retain(oo2);
564 testassert(Retains == 0);
565 objc_release(oo2);
566 testassert(Releases == 0);
567 objc_autorelease(oo2);
568 testassert(Autoreleases == 0);
569
570 class_addMethod(ccc, @selector(autorelease), (IMP)imp_fn, "");
571
572 objc_retain(ooo);
573 testassert(Retains == 1);
574 objc_release(ooo);
575 testassert(Releases == 1);
576 objc_autorelease(ooo);
577 testassert(Autoreleases == 0);
578 testassert(Imps == 1);
579
580 objc_retain(oo2);
581 testassert(Retains == 2);
582 objc_release(oo2);
583 testassert(Releases == 2);
584 objc_autorelease(oo2);
585 testassert(Autoreleases == 0);
586 testassert(Imps == 2);
587
588
589 testprintf("addMethod clobbers (InheritingSub5, retainCount)\n");
590 zero();
591
592 ccc = [InheritingSub5 class];
593 ooo = [ccc new];
594 cc2 = [InheritingSub5_2 class];
595 oo2 = [cc2 new];
596
597 objc_retain(ooo);
598 testassert(Retains == 0);
599 objc_release(ooo);
600 testassert(Releases == 0);
601 objc_autorelease(ooo);
602 testassert(Autoreleases == 0);
603
604 objc_retain(oo2);
605 testassert(Retains == 0);
606 objc_release(oo2);
607 testassert(Releases == 0);
608 objc_autorelease(oo2);
609 testassert(Autoreleases == 0);
610
611 class_addMethod(ccc, @selector(retainCount), (IMP)imp_fn, "");
612
613 objc_retain(ooo);
614 testassert(Retains == 1);
615 objc_release(ooo);
616 testassert(Releases == 1);
617 objc_autorelease(ooo);
618 testassert(Autoreleases == 1);
619 // no bypassing call for -retainCount
620
621 objc_retain(oo2);
622 testassert(Retains == 2);
623 objc_release(oo2);
624 testassert(Releases == 2);
625 objc_autorelease(oo2);
626 testassert(Autoreleases == 2);
627 // no bypassing call for -retainCount
628
629
630 testprintf("setSuperclass to clean super does not clobber (InheritingSub6)\n");
631 zero();
632
633 ccc = [InheritingSub6 class];
634 ooo = [ccc new];
635 cc2 = [InheritingSub6_2 class];
636 oo2 = [cc2 new];
637
638 objc_retain(ooo);
639 testassert(Retains == 0);
640 objc_release(ooo);
641 testassert(Releases == 0);
642 objc_autorelease(ooo);
643 testassert(Autoreleases == 0);
644
645 objc_retain(oo2);
646 testassert(Retains == 0);
647 objc_release(oo2);
648 testassert(Releases == 0);
649 objc_autorelease(oo2);
650 testassert(Autoreleases == 0);
651
652 class_setSuperclass(ccc, [InheritingSub class]);
653
654 objc_retain(ooo);
655 testassert(Retains == 0);
656 objc_release(ooo);
657 testassert(Releases == 0);
658 objc_autorelease(ooo);
659 testassert(Autoreleases == 0);
660
661 objc_retain(oo2);
662 testassert(Retains == 0);
663 objc_release(oo2);
664 testassert(Releases == 0);
665 objc_autorelease(oo2);
666 testassert(Autoreleases == 0);
667
668
669 testprintf("setSuperclass to dirty super clobbers (InheritingSub7)\n");
670 zero();
671
672 ccc = [InheritingSub7 class];
673 ooo = [ccc new];
674 cc2 = [InheritingSub7_2 class];
675 oo2 = [cc2 new];
676
677 objc_retain(ooo);
678 testassert(Retains == 0);
679 objc_release(ooo);
680 testassert(Releases == 0);
681 objc_autorelease(ooo);
682 testassert(Autoreleases == 0);
683
684 objc_retain(oo2);
685 testassert(Retains == 0);
686 objc_release(oo2);
687 testassert(Releases == 0);
688 objc_autorelease(oo2);
689 testassert(Autoreleases == 0);
690
691 class_setSuperclass(ccc, [OverridingSub class]);
692
693 objc_retain(ooo);
694 testassert(SubRetains == 1);
695 objc_release(ooo);
696 testassert(SubReleases == 1);
697 objc_autorelease(ooo);
698 testassert(SubAutoreleases == 1);
699
700 objc_retain(oo2);
701 testassert(SubRetains == 2);
702 objc_release(oo2);
703 testassert(SubReleases == 2);
704 objc_autorelease(oo2);
705 testassert(SubAutoreleases == 2);
706
707
708 testprintf("category replacement of unrelated method does not clobber (InheritingSubCat)\n");
709 zero();
710
711 ccc = [InheritingSubCat class];
712 ooo = [ccc new];
713 cc2 = [InheritingSubCat_2 class];
714 oo2 = [cc2 new];
715
716 objc_retain(ooo);
717 testassert(Retains == 0);
718 objc_release(ooo);
719 testassert(Releases == 0);
720 objc_autorelease(ooo);
721 testassert(Autoreleases == 0);
722
723 objc_retain(oo2);
724 testassert(Retains == 0);
725 objc_release(oo2);
726 testassert(Releases == 0);
727 objc_autorelease(oo2);
728 testassert(Autoreleases == 0);
729
730 dlh = dlopen("customrr-cat1.dylib", RTLD_LAZY);
731 testassert(dlh);
732
733 objc_retain(ooo);
734 testassert(Retains == 0);
735 objc_release(ooo);
736 testassert(Releases == 0);
737 objc_autorelease(ooo);
738 testassert(Autoreleases == 0);
739
740 objc_retain(oo2);
741 testassert(Retains == 0);
742 objc_release(oo2);
743 testassert(Releases == 0);
744 objc_autorelease(oo2);
745 testassert(Autoreleases == 0);
746
747
748 testprintf("category replacement clobbers (InheritingSubCat)\n");
749 zero();
750
751 ccc = [InheritingSubCat class];
752 ooo = [ccc new];
753 cc2 = [InheritingSubCat_2 class];
754 oo2 = [cc2 new];
755
756 objc_retain(ooo);
757 testassert(Retains == 0);
758 objc_release(ooo);
759 testassert(Releases == 0);
760 objc_autorelease(ooo);
761 testassert(Autoreleases == 0);
762
763 objc_retain(oo2);
764 testassert(Retains == 0);
765 objc_release(oo2);
766 testassert(Releases == 0);
767 objc_autorelease(oo2);
768 testassert(Autoreleases == 0);
769
770 dlh = dlopen("customrr-cat2.dylib", RTLD_LAZY);
771 testassert(dlh);
772
773 objc_retain(ooo);
774 testassert(Retains == 1);
775 objc_release(ooo);
776 testassert(Releases == 1);
777 objc_autorelease(ooo);
778 testassert(Autoreleases == 1);
779
780 objc_retain(oo2);
781 testassert(Retains == 2);
782 objc_release(oo2);
783 testassert(Releases == 2);
784 objc_autorelease(oo2);
785 testassert(Autoreleases == 2);
786
787
788 testprintf("allocateClassPair with clean super does not clobber\n");
789 zero();
790
791 objc_retain(inh);
792 testassert(Retains == 0);
793 objc_release(inh);
794 testassert(Releases == 0);
795 objc_autorelease(inh);
796 testassert(Autoreleases == 0);
797
798 ccc = objc_allocateClassPair([InheritingSub class], "CleanClassPair", 0);
799 objc_registerClassPair(ccc);
800 ooo = [ccc new];
801
802 objc_retain(inh);
803 testassert(Retains == 0);
804 objc_release(inh);
805 testassert(Releases == 0);
806 objc_autorelease(inh);
807 testassert(Autoreleases == 0);
808
809 objc_retain(ooo);
810 testassert(Retains == 0);
811 objc_release(ooo);
812 testassert(Releases == 0);
813 objc_autorelease(ooo);
814 testassert(Autoreleases == 0);
815
816
817 testprintf("allocateClassPair with clobbered super clobbers\n");
818 zero();
819
820 ccc = objc_allocateClassPair([OverridingSub class], "DirtyClassPair", 0);
821 objc_registerClassPair(ccc);
822 ooo = [ccc new];
823
824 objc_retain(ooo);
825 testassert(SubRetains == 1);
826 objc_release(ooo);
827 testassert(SubReleases == 1);
828 objc_autorelease(ooo);
829 testassert(SubAutoreleases == 1);
830
831
832 testprintf("allocateClassPair with clean super and override clobbers\n");
833 zero();
834
835 ccc = objc_allocateClassPair([InheritingSub class], "Dirty2ClassPair", 0);
836 class_addMethod(ccc, @selector(autorelease), (IMP)imp_fn, "");
837 objc_registerClassPair(ccc);
838 ooo = [ccc new];
839
840 objc_retain(ooo);
841 testassert(Retains == 1);
842 objc_release(ooo);
843 testassert(Releases == 1);
844 objc_autorelease(ooo);
845 testassert(Autoreleases == 0);
846 testassert(Imps == 1);
847
848
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.
852
853 // These tests also check recursive clobber.
854
855 #if TEST_EXCHANGEIMPLEMENTATIONS
856 testprintf("exchangeImplementations clobbers (recursive)\n");
857 #else
858 testprintf("setImplementation clobbers (recursive)\n");
859 #endif
860 zero();
861
862 objc_retain(obj);
863 testassert(Retains == 0);
864 objc_release(obj);
865 testassert(Releases == 0);
866 objc_autorelease(obj);
867 testassert(Autoreleases == 0);
868
869 objc_retain(inh);
870 testassert(Retains == 0);
871 objc_release(inh);
872 testassert(Releases == 0);
873 objc_autorelease(inh);
874 testassert(Autoreleases == 0);
875
876 Method meth = class_getInstanceMethod(cls, @selector(retainCount));
877 testassert(meth);
878 #if TEST_EXCHANGEIMPLEMENTATIONS
879 method_exchangeImplementations(meth, meth);
880 #else
881 method_setImplementation(meth, (IMP)imp_fn);
882 #endif
883
884 objc_retain(obj);
885 testassert(Retains == 1);
886 objc_release(obj);
887 testassert(Releases == 1);
888 objc_autorelease(obj);
889 testassert(Autoreleases == 1);
890
891 objc_retain(inh);
892 testassert(Retains == 2);
893 objc_release(inh);
894 testassert(Releases == 2);
895 objc_autorelease(inh);
896 testassert(Autoreleases == 2);
897
898
899 // do not add more tests here - the recursive test must be LAST
900
901 succeed(basename(argv[0]));
902 }
903
904 #endif