1// These options must match customrr2.m 2// TEST_CONFIG MEM=mrc 3/* 4TEST_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 8END 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 19OBJC_ROOT_CLASS 20@interface InheritingSubCat @end 21@implementation InheritingSubCat @end 22 23int main(int argc __unused, char **argv) 24{ 25 succeed(basename(argv[0])); 26} 27 28#else 29 30static int Retains; 31static int Releases; 32static int Autoreleases; 33static int RetainCounts; 34static int PlusRetains; 35static int PlusReleases; 36static int PlusAutoreleases; 37static int PlusRetainCounts; 38static int Allocs; 39static int AllocWithZones; 40 41static int SubRetains; 42static int SubReleases; 43static int SubAutoreleases; 44static int SubRetainCounts; 45static int SubPlusRetains; 46static int SubPlusReleases; 47static int SubPlusAutoreleases; 48static int SubPlusRetainCounts; 49static int SubAllocs; 50static int SubAllocWithZones; 51 52static int Imps; 53 54static id imp_fn(id self, SEL _cmd __unused, ...) 55{ 56 Imps++; 57 return self; 58} 59 60static 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 87id HackRetain(id self, SEL _cmd __unused) { Retains++; return self; } 88void HackRelease(id self __unused, SEL _cmd __unused) { Releases++; } 89id HackAutorelease(id self, SEL _cmd __unused) { Autoreleases++; return self; } 90NSUInteger HackRetainCount(id self __unused, SEL _cmd __unused) { RetainCounts++; return 1; } 91id HackPlusRetain(id self, SEL _cmd __unused) { PlusRetains++; return self; } 92void HackPlusRelease(id self __unused, SEL _cmd __unused) { PlusReleases++; } 93id HackPlusAutorelease(id self, SEL _cmd __unused) { PlusAutoreleases++; return self; } 94NSUInteger HackPlusRetainCount(id self __unused, SEL _cmd __unused) { PlusRetainCounts++; return 1; } 95id HackAlloc(Class self, SEL _cmd __unused) { Allocs++; return class_createInstance(self, 0); } 96id 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 169extern uintptr_t OBJC_CLASS_$_UnrealizedSubA1; 170@interface UnrealizedSubA1 : NSObject @end 171@implementation UnrealizedSubA1 @end 172extern uintptr_t OBJC_CLASS_$_UnrealizedSubA2; 173@interface UnrealizedSubA2 : NSObject @end 174@implementation UnrealizedSubA2 @end 175extern uintptr_t OBJC_CLASS_$_UnrealizedSubA3; 176@interface UnrealizedSubA3 : NSObject @end 177@implementation UnrealizedSubA3 @end 178 179extern uintptr_t OBJC_CLASS_$_UnrealizedSubB1; 180@interface UnrealizedSubB1 : NSObject @end 181@implementation UnrealizedSubB1 @end 182extern uintptr_t OBJC_CLASS_$_UnrealizedSubB2; 183@interface UnrealizedSubB2 : NSObject @end 184@implementation UnrealizedSubB2 @end 185extern uintptr_t OBJC_CLASS_$_UnrealizedSubB3; 186@interface UnrealizedSubB3 : NSObject @end 187@implementation UnrealizedSubB3 @end 188 189extern uintptr_t OBJC_CLASS_$_UnrealizedSubC1; 190@interface UnrealizedSubC1 : NSObject @end 191@implementation UnrealizedSubC1 @end 192extern uintptr_t OBJC_CLASS_$_UnrealizedSubC2; 193@interface UnrealizedSubC2 : NSObject @end 194@implementation UnrealizedSubC2 @end 195extern uintptr_t OBJC_CLASS_$_UnrealizedSubC3; 196@interface UnrealizedSubC3 : NSObject @end 197@implementation UnrealizedSubC3 @end 198 199 200int 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 905