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//  slop.m
22//  Copyright (c) 2009-2011 Apple Inc. All rights reserved.
23//
24
25#import "BlackBoxTest.h"
26#import <objc/runtime.h>
27
28@interface SlopTester : TestFinalizer
29@end
30
31@implementation SlopTester
32- (id)init
33{
34    self = [super init];
35    if (self) {
36        size_t mySize = malloc_size(self);
37        size_t instanceSize = class_getInstanceSize([self class]);
38        char *slopPtr = (char *)self;
39        for (size_t slopIndex = instanceSize; slopIndex < mySize; slopIndex++) {
40            if (slopPtr[slopIndex])
41                [[TestCase currentTestCase] fail:@"detected nonzero byte in slop area"];
42        }
43
44        // store some nonzero bytes in the slop for the next iteration to check
45        for (size_t slopIndex = instanceSize; slopIndex < mySize; slopIndex++) {
46            slopPtr[slopIndex] = 0xff;
47        }
48    }
49    return self;
50}
51@end
52
53
54@interface Slop : BlackBoxTest
55{
56    int _iterations;
57    int _blockCount;
58    int _reusedCount;
59    NSHashTable *_usedBlocks;
60}
61- (void)iterate;
62@end
63
64@implementation Slop
65
66#define EXTRA_SIZE_MAX 1024
67#define MIN_ITERATIONS 5
68
69- (void)checkResult
70{
71    if (_blockCount > 0) {
72        [self fail:[NSString stringWithFormat:@"did not collect %d test blocks", _blockCount]];
73    } else {
74        if (_reusedCount < EXTRA_SIZE_MAX || _iterations < MIN_ITERATIONS) {
75            [self iterate];
76            return;
77        }
78    }
79    if (_reusedCount == 0) {
80        [self fail:@"did not reuse any blocks - slop may not be checked"];
81    }
82    [self passed];
83    [self testFinished];
84    _usedBlocks = nil;
85}
86
87- (void)allocate
88{
89    @synchronized(self) {
90        Class st = [SlopTester class];
91        for (size_t extra = 0; extra < EXTRA_SIZE_MAX; extra++) {
92            id o = [NSAllocateObject(st, extra, NULL) init];
93            if ([_usedBlocks member:(id)[self disguise:o]])
94                _reusedCount++;
95            else
96                [_usedBlocks addObject:(id)[self disguise:o]];
97            _blockCount++;
98        }
99    }
100}
101
102- (void)iterate
103{
104    _iterations++;
105    [self allocate];
106    [self clearStack];
107    [self runThreadLocalCollection];
108    [self requestFullCollectionWithCompletionCallback:^{ [self checkResult]; }];
109}
110
111- (void)performTest
112{
113    _usedBlocks = [NSHashTable hashTableWithOptions:NSPointerFunctionsOpaquePersonality];
114    [self iterate];
115}
116
117- (void)didFinalize:(TestFinalizer *)finalizer
118{
119    @synchronized(self) {
120        _blockCount--;
121    }
122}
123
124@end
125