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// malloc.m 22// Copyright (c) 2009-2011 Apple Inc. All rights reserved. 23// 24 25#include "WhiteBoxTest.h" 26 27// with dispatch we get occasional failures. dispatch_apply() bug? 28#define USE_DISPATCH 0 29 30#define BLOCK_SIZE_MAX 1024 31#define REALLOC_BLOCK_SIZE_INCREMENT 64 32#define REALLOC_NUM_BLOCKS (BLOCK_SIZE_MAX/REALLOC_BLOCK_SIZE_INCREMENT) 33 34@interface MallocTest : WhiteBoxTest 35{ 36 uint _block_count; 37 void **_test_blocks; 38 vm_address_t *_disguised_blocks; 39 uint _recoveredCount; 40} 41@end 42 43@implementation MallocTest 44 45- (id)initWithCount:(uint)count 46{ 47 self = [super init]; 48 if (self) { 49 _block_count = count; 50 _test_blocks = (void **)malloc(count * sizeof(void *)); 51 _disguised_blocks = (vm_address_t *)malloc(count * sizeof(vm_address_t)); 52 } 53 return self; 54} 55 56- (void)finalize 57{ 58 free(_test_blocks); 59 free(_disguised_blocks); 60 [super finalize]; 61} 62 63- (void)checkFreed 64{ 65 // we sometimes race and miss one block somehow, so don't fail the test if we're off by one 66 if (_recoveredCount >= _block_count-1) { 67 [self passed]; 68 } else { 69 int i = 0; 70 while (!_disguised_blocks[i] && i < _block_count) 71 i++; 72 if (i < _block_count) { 73 [self fail:[NSString stringWithFormat:@"recovered %d blocks, expected %d. missed block: %p", _recoveredCount, _block_count, [self undisguise:_disguised_blocks[i]]]]; 74 } else { 75 [self fail:[NSString stringWithFormat:@"recovered %d blocks, expected %d.", _recoveredCount, _block_count]]; 76 } 77 } 78} 79 80- (void)adminDeallocate:(void *)address 81{ 82 for (int i=0; i<_block_count; i++) { 83 if (address == [self undisguise:_disguised_blocks[i]]) { 84 _recoveredCount++; 85 _disguised_blocks[i] = 0; 86 break; 87 } 88 } 89} 90 91@end 92 93@interface Realloc : MallocTest 94@end 95 96 97@implementation Realloc 98 99- (id)init 100{ 101 return [super initWithCount:REALLOC_NUM_BLOCKS]; 102} 103 104- (void)allocate 105{ 106 // allocate a bunch of blocks 107 dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 108 dispatch_apply(_block_count, q, ^(size_t i){ 109 _test_blocks[i] = malloc_zone_malloc([self auto_zone], REALLOC_BLOCK_SIZE_INCREMENT*(i+1)); 110 _disguised_blocks[i] = [self disguise:_test_blocks[i]]; 111 }); 112 113 // now realloc all the blocks to a different (arbitrary) size 114 for (int i=0; i<_block_count; i++) { 115 _test_blocks[i] = malloc_zone_realloc([self auto_zone], _test_blocks[i], REALLOC_BLOCK_SIZE_INCREMENT*(i+2)); 116 if (_test_blocks[i] == NULL) 117 [self fail:@"malloc_zone_realloc() returned NULL"]; 118 } 119 120 // now free all the blocks 121#if USE_DISPATCH 122 for (int i=0; i<_block_count; i++) { 123 malloc_zone_free([self auto_zone], _test_blocks[i]); 124 _test_blocks[i] = NULL; 125 } 126#else 127 dispatch_apply(_block_count, q, ^(size_t i){ 128 malloc_zone_free([self auto_zone], _test_blocks[i]); 129 _test_blocks[i] = NULL; 130 }); 131#endif 132} 133 134- (void)performTest 135{ 136 [self allocate]; 137 [self clearStack]; 138 139 // at this point _test_blocks holds realloc'd blocks and _disguised_blocks holds disguised pointers to the original blocks 140 // run a collection and verify that all the blocks in _disguised_blocks get reaped 141 if ([self result] != FAILED) 142 [self requestFullCollectionWithCompletionCallback:^{ [self checkFreed]; [self testFinished]; }]; 143} 144 145 146@end 147 148#define MallocFreeBlockCount 1000 149@interface MallocFree : MallocTest 150@end 151 152@implementation MallocFree 153 154- (id)init 155{ 156 return [super initWithCount:MallocFreeBlockCount]; 157} 158 159- (void)performTest 160{ 161 // allocate a bunch of blocks 162 dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 163 dispatch_apply(_block_count, q, ^(size_t i){ 164 _test_blocks[i] = malloc_zone_malloc([self auto_zone], random()%BLOCK_SIZE_MAX + 1); 165 _disguised_blocks[i] = [self disguise:_test_blocks[i]]; 166 }); 167 168 // now free all the blocks 169#if USE_DISPATCH 170 for (int i=0; i<_block_count; i++) { 171 malloc_zone_free([self auto_zone], _test_blocks[i]); 172 _test_blocks[i] = NULL; 173 } 174#else 175 dispatch_apply(_block_count, q, ^(size_t i){ 176 malloc_zone_free([self auto_zone], _test_blocks[i]); 177 _test_blocks[i] = NULL; 178 }); 179#endif 180 181 // at this point _test_blocks holds realloc'd blocks and _disguised_blocks holds disguised pointers to the original blocks 182 // run a collection and verify that all the blocks in _disguised_blocks get reaped 183 if ([self result] != FAILED) 184 [self requestFullCollectionWithCompletionCallback:^{ [self checkFreed]; [self testFinished]; }]; 185} 186 187@end 188 189@interface BulkAllocate : MallocTest 190@end 191 192#define BulkAllocateBlockCount 30000 193@implementation BulkAllocate 194- (id)init 195{ 196 return [super initWithCount:BulkAllocateBlockCount]; 197} 198 199- (void)allocate 200{ 201 _block_count = auto_zone_batch_allocate([self auto_zone], 300, AUTO_MEMORY_UNSCANNED, false, true, _test_blocks, BulkAllocateBlockCount); 202 203 if (_block_count == 0) 204 [self fail:@"auto_zone_batch_allocate() returned no blocks"]; 205 206 for (int i=0; i<_block_count; i++) { 207 _disguised_blocks[i] = [self disguise:_test_blocks[i]]; 208 _test_blocks[i] = NULL; 209 } 210} 211 212- (void)performTest 213{ 214 [self allocate]; 215 [self clearStack]; 216 if ([self result] != FAILED) 217 [self requestFullCollectionWithCompletionCallback:^{ [self checkFreed]; [self testFinished]; }]; 218} 219 220 221@end 222 223