1 // Define FOUNDATION=1 for NSObject and NSAutoreleasePool
2 // Define FOUNDATION=0 for _objc_root* and _objc_autoreleasePool*
7 # define RR_PUSH() [[NSAutoreleasePool alloc] init]
8 # define RR_POP(p) [(id)p release]
9 # define RR_RETAIN(o) [o retain]
10 # define RR_RELEASE(o) [o release]
11 # define RR_AUTORELEASE(o) [o autorelease]
12 # define RR_RETAINCOUNT(o) [o retainCount]
14 # define RR_PUSH() _objc_autoreleasePoolPush()
15 # define RR_POP(p) _objc_autoreleasePoolPop(p)
16 # define RR_RETAIN(o) _objc_rootRetain((id)o)
17 # define RR_RELEASE(o) _objc_rootRelease((id)o)
18 # define RR_AUTORELEASE(o) _objc_rootAutorelease((id)o)
19 # define RR_RETAINCOUNT(o) _objc_rootRetainCount((id)o)
22 #include <objc/objc-internal.h>
23 #include <Foundation/Foundation.h>
26 static pthread_attr_t smallstack;
28 #define NESTED_COUNT 8
30 @interface Deallocator : NSObject @end
31 @implementation Deallocator
34 // testprintf("-[Deallocator %p dealloc]\n", self);
40 @interface AutoreleaseDuringDealloc : NSObject @end
41 @implementation AutoreleaseDuringDealloc
45 RR_AUTORELEASE([[Deallocator alloc] init]);
50 @interface AutoreleasePoolDuringDealloc : NSObject @end
51 @implementation AutoreleasePoolDuringDealloc
55 for (int i = 0; i < NESTED_COUNT; i++) {
56 RR_AUTORELEASE([[Deallocator alloc] init]);
60 void *pool = RR_PUSH();
61 for (int i = 0; i < NESTED_COUNT; i++) {
62 RR_AUTORELEASE([[Deallocator alloc] init]);
66 // caller's pool again
67 for (int i = 0; i < NESTED_COUNT; i++) {
68 RR_AUTORELEASE([[Deallocator alloc] init]);
74 if (!warned) testwarn("rdar://7138159 NSAutoreleasePool leaks");
77 state += NESTED_COUNT;
79 // local pool, not popped
81 for (int i = 0; i < NESTED_COUNT; i++) {
82 RR_AUTORELEASE([[Deallocator alloc] init]);
90 void *autorelease_lots_fn(void *singlePool)
92 // Enough to blow out the stack if AutoreleasePoolPage is recursive.
93 const int COUNT = 1024*1024;
97 void **pools = (void**)malloc((COUNT+1) * sizeof(void*));
98 pools[p++] = RR_PUSH();
100 id obj = RR_AUTORELEASE([[Deallocator alloc] init]);
102 // last pool has only 1 autorelease in it
103 pools[p++] = RR_PUSH();
105 for (int i = 0; i < COUNT; i++) {
106 if (rand() % 1000 == 0 && !singlePool) {
107 pools[p++] = RR_PUSH();
109 RR_AUTORELEASE(RR_RETAIN(obj));
113 testassert(state == 0);
117 testassert(state == 0);
118 testassert(RR_RETAINCOUNT(obj) == 1);
120 testassert(state == 1);
126 void *nsthread_fn(void *arg __unused)
128 [NSThread currentThread];
129 void *pool = RR_PUSH();
130 RR_AUTORELEASE([[Deallocator alloc] init]);
137 // Normal autorelease.
138 testprintf("-- Normal autorelease.\n");
140 void *pool = RR_PUSH();
142 RR_AUTORELEASE([[Deallocator alloc] init]);
143 testassert(state == 0);
145 testassert(state == 1);
148 // Autorelease during dealloc during autoreleasepool-pop.
149 // That autorelease is handled by the popping pool, not the one above it.
150 testprintf("-- Autorelease during dealloc during autoreleasepool-pop.\n");
152 void *pool = RR_PUSH();
154 RR_AUTORELEASE([[AutoreleaseDuringDealloc alloc] init]);
155 testassert(state == 0);
157 testassert(state == 2);
160 // Autorelease pool during dealloc during autoreleasepool-pop.
161 testprintf("-- Autorelease pool during dealloc during autoreleasepool-pop.\n");
163 void *pool = RR_PUSH();
165 RR_AUTORELEASE([[AutoreleasePoolDuringDealloc alloc] init]);
166 testassert(state == 0);
168 testassert(state == 4 * NESTED_COUNT);
171 // Top-level thread pool popped normally.
172 testprintf("-- Thread-level pool popped normally.\n");
176 void *pool = RR_PUSH();
177 RR_AUTORELEASE([[Deallocator alloc] init]);
180 testassert(state == 1);
184 // Autorelease with no pool.
185 testprintf("-- Autorelease with no pool.\n");
189 RR_AUTORELEASE([[Deallocator alloc] init]);
191 testassert(state == 1);
194 // Autorelease with no pool after popping the top-level pool.
195 testprintf("-- Autorelease with no pool after popping the last pool.\n");
199 void *pool = RR_PUSH();
200 RR_AUTORELEASE([[Deallocator alloc] init]);
202 RR_AUTORELEASE([[Deallocator alloc] init]);
204 testassert(state == 2);
207 // Top-level thread pool not popped.
208 // The runtime should clean it up.
212 if (!warned) testwarn("rdar://7138159 NSAutoreleasePool leaks");
216 testprintf("-- Thread-level pool not popped.\n");
221 RR_AUTORELEASE([[Deallocator alloc] init]);
224 testassert(state == 1);
228 // Intermediate pool not popped.
229 // Popping the containing pool should clean up the skipped pool first.
233 if (!warned) testwarn("rdar://7138159 NSAutoreleasePool leaks");
237 testprintf("-- Intermediate pool not popped.\n");
239 void *pool = RR_PUSH();
240 void *pool2 = RR_PUSH();
241 RR_AUTORELEASE([[Deallocator alloc] init]);
243 (void)pool2; // pool2 not popped
245 testassert(state == 1);
254 // Large autorelease stack.
255 // Do this only once because it's slow.
256 testprintf("-- Large autorelease stack.\n");
258 // limit stack size: autorelease pop should not be recursive
260 pthread_create(&th, &smallstack, &autorelease_lots_fn, NULL);
261 pthread_join(th, NULL);
264 // Single large autorelease pool.
265 // Do this only once because it's slow.
266 testprintf("-- Large autorelease pool.\n");
268 // limit stack size: autorelease pop should not be recursive
270 pthread_create(&th, &smallstack, &autorelease_lots_fn, (void*)1);
271 pthread_join(th, NULL);
278 pthread_attr_init(&smallstack);
279 pthread_attr_setstacksize(&smallstack, 16384);
281 // inflate the refcount side table so it doesn't show up in leak checks
284 id *objs = (id *)malloc(count*sizeof(id));
285 for (int i = 0; i < count; i++) {
286 objs[i] = RR_RETAIN([NSObject new]);
288 for (int i = 0; i < count; i++) {
296 // inflate NSAutoreleasePool's instance cache
299 id *objs = (id *)malloc(count * sizeof(id));
300 for (int i = 0; i < count; i++) {
301 objs[i] = [[NSAutoreleasePool alloc] init];
303 for (int i = 0; i < count; i++) {
304 [objs[count-i-1] release];
313 for (int i = 0; i < 100; i++) {
320 // check for leaks using top-level pools
324 for (int i = 0; i < 1000; i++) {
335 // check for leaks using pools not at top level
336 void *pool = RR_PUSH();
340 for (int i = 0; i < 1000; i++) {
353 // Can't leak check this because it's too noisy.
354 testprintf("-- NSThread.\n");
357 pthread_create(&th, &smallstack, &nsthread_fn, 0);
358 pthread_join(th, NULL);
361 // NO LEAK CHECK HERE