1/* 2 * Copyright (c) 2011 Apple Inc. All rights reserved. 3 * 4 * @APPLE_APACHE_LICENSE_HEADER_START@ 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 * 18 * @APPLE_APACHE_LICENSE_HEADER_END@ 19 */ 20// 21// Radar5983285.m 22// Copyright (c) 2008-2011 Apple Inc. All rights reserved. 23// 24 25#import "WhiteBoxTest.h" 26 27@interface Radar5983285 : WhiteBoxTest { 28 BOOL _blockWasPended; 29 BOOL _blockWasScanned; 30 vm_address_t disguisedPointer; 31 BOOL testBlockCollected; 32 const unsigned char *correctLayout; 33 BOOL scannedWithBogusLayout; 34 BOOL scannedWithCorrectLayout; 35} 36 37@property(readwrite, nonatomic) vm_address_t disguisedPointer; 38@property(readwrite, nonatomic) BOOL testBlockCollected; 39@property(readwrite, nonatomic) const unsigned char *correctLayout; 40@property(readwrite, nonatomic) BOOL scannedWithBogusLayout; 41@property(readwrite, nonatomic) BOOL scannedWithCorrectLayout; 42 43@end 44 45// simple test class with nontrivial layout 46@interface Radar5983285_TestClass : NSObject 47{ 48 id foo; 49 int bar; 50 id cat; 51} 52@end 53@implementation Radar5983285_TestClass 54@end 55 56@implementation Radar5983285 57 58@synthesize disguisedPointer; 59@synthesize testBlockCollected; 60@synthesize correctLayout; 61@synthesize scannedWithBogusLayout; 62@synthesize scannedWithCorrectLayout; 63 64- (void)allocateTestBlock 65{ 66 // allocate a test block and fetch its layout 67 id testObject = [Radar5983285_TestClass new]; 68 auto_collection_control_t *control = auto_collection_parameters([self auto_zone]); 69 self.correctLayout = control->layout_for_address([self auto_zone], testObject); 70 [self setDisguisedPointer:[self disguise:testObject]]; 71 72 // keep a reference to the test block on the stack 73 [self testThreadStackBuffer][0] = testObject; 74} 75 76 77- (void)testResult 78{ 79 // check that our block was scanned with the correct layout 80 if (self.scannedWithBogusLayout) 81 [self fail:@"block was scanned with invalid layout"]; 82 else 83 [self passed]; 84 [self testFinished]; 85} 86 87- (void)performTest 88{ 89 [self performSelectorOnTestThread:@selector(allocateTestBlock)]; 90 91 // request a generational collection and go to sleep until our block gets pended 92 [self requestGenerationalCollectionWithCompletionCallback:^{ [self testResult]; }]; 93} 94 95- (void)blockWasPended 96{ 97 if (_blockWasPended) { 98 // The heap collector is about to pend our test block. 99 // Clear our local reference and run a local collection. 100 [self testThreadStackBuffer][0] = nil; 101 [self runThreadLocalCollection]; 102 103 if (!self.testBlockCollected) 104 [self fail:@"test block was not collected as expected during local collection"]; 105 106 // now wake up the heap collector 107 } else { 108 [self fail:@"test block was not pended as expected"]; 109 } 110} 111 112- (void)setPending:(void *)block 113{ 114 // wake up test thread once our block gets pended 115 if (block == [self undisguise:self.disguisedPointer]) { 116 _blockWasPended = YES; 117 [self performSelectorOnTestThread:@selector(blockWasPended)]; 118 } 119 [super setPending:block]; 120} 121 122- (void)scanBlock:(void *)block endAddress:(void *)end 123{ 124 // our block has layout info so should not be scanned conservatively 125 if (block == [self undisguise:self.disguisedPointer] && !self.scannedWithCorrectLayout) { 126 [self fail:@"test block scanned without layout"]; 127 } 128 [super scanBlock:block endAddress:end]; 129} 130 131- (void)scanBlock:(void *)block endAddress:(void *)end withLayout:(const unsigned char *)map 132{ 133 // verify the block's layout 134 if (block == [self undisguise:self.disguisedPointer]) { 135 if (map != self.correctLayout) 136 self.scannedWithBogusLayout = YES; 137 else 138 self.scannedWithCorrectLayout = YES; 139 } 140 [super scanBlock:block endAddress:end withLayout:map]; 141} 142 143- (void)endLocalScanWithGarbage:(void **)garbage_list count:(size_t)count 144{ 145 // monitor for our test block becoming garbage 146 if ([self block:[self undisguise:self.disguisedPointer] isInList:garbage_list count:count]) { 147 self.testBlockCollected = YES; 148 } 149 [super endLocalScanWithGarbage:garbage_list count:count]; 150} 151 152- (void)blockBecameGlobal:(void *)block withAge:(uint32_t)age 153{ 154 // monitor if our test block becomes global (it should not) 155 if (block == [self undisguise:self.disguisedPointer]) { 156 [self fail:@"test block became global unexpectedly"]; 157 } 158 [super blockBecameGlobal:block withAge:age]; 159} 160 161@end 162