]> git.saurik.com Git - apple/objc4.git/blob - test/arr-weak.m
objc4-647.tar.gz
[apple/objc4.git] / test / arr-weak.m
1 // TEST_CONFIG MEM=mrc
2 // TEST_CRASHES
3 /*
4 TEST_RUN_OUTPUT
5 objc\[\d+\]: Cannot form weak reference to instance \(0x[0-9a-f]+\) of class Crash. It is possible that this object was over-released, or is in the process of deallocation.
6 CRASHED: SIG(ILL|TRAP)
7 END
8 */
9
10 #include "test.h"
11
12 #include <Foundation/NSObject.h>
13
14 static id weak;
15 static id weak2;
16 static bool did_dealloc;
17
18 static int state;
19
20 @interface NSObject (WeakInternals)
21 -(BOOL)_tryRetain;
22 -(BOOL)_isDeallocating;
23 @end
24
25 @interface Test : NSObject @end
26 @implementation Test
27 -(void)dealloc {
28 // The value returned by objc_loadWeak() is now nil,
29 // but the storage is not yet cleared.
30 testassert(weak == self);
31 testassert(weak2 == self);
32
33 // objc_loadWeak() does not eagerly clear the storage.
34 testassert(objc_loadWeakRetained(&weak) == nil);
35 testassert(weak != nil);
36
37 // dealloc clears the storage.
38 testprintf("Weak references clear during super dealloc\n");
39 testassert(weak2 != nil);
40 [super dealloc];
41 testassert(weak == nil);
42 testassert(weak2 == nil);
43
44 did_dealloc = true;
45 }
46 @end
47
48 @interface CustomTryRetain : Test @end
49 @implementation CustomTryRetain
50 -(BOOL)_tryRetain { state++; return [super _tryRetain]; }
51 @end
52
53 @interface CustomIsDeallocating : Test @end
54 @implementation CustomIsDeallocating
55 -(BOOL)_isDeallocating { state++; return [super _isDeallocating]; }
56 @end
57
58 @interface CustomAllowsWeakReference : Test @end
59 @implementation CustomAllowsWeakReference
60 -(BOOL)allowsWeakReference { state++; return [super allowsWeakReference]; }
61 @end
62
63 @interface CustomRetainWeakReference : Test @end
64 @implementation CustomRetainWeakReference
65 -(BOOL)retainWeakReference { state++; return [super retainWeakReference]; }
66 @end
67
68 @interface Crash : NSObject @end
69 @implementation Crash
70 -(void)dealloc {
71 testassert(weak == self);
72 testassert(weak2 == self);
73 testassert(objc_loadWeakRetained(&weak) == nil);
74 testassert(objc_loadWeakRetained(&weak2) == nil);
75
76 testprintf("Weak store crashes while deallocating\n");
77 objc_storeWeak(&weak, self);
78 fail("objc_storeWeak of deallocating value should have crashed");
79 [super dealloc];
80 }
81 @end
82
83
84 void cycle(Class cls, Test *obj, Test *obj2)
85 {
86 testprintf("Cycling class %s\n", class_getName(cls));
87
88 id result;
89
90 // state counts calls to custom weak methods
91 // Difference test classes have different expected values.
92 int storeTarget;
93 int loadTarget;
94 if (cls == [Test class]) {
95 storeTarget = 0;
96 loadTarget = 0;
97 }
98 else if (cls == [CustomTryRetain class] ||
99 cls == [CustomRetainWeakReference class])
100 {
101 storeTarget = 0;
102 loadTarget = 1;
103 }
104 else if (cls == [CustomIsDeallocating class] ||
105 cls == [CustomAllowsWeakReference class])
106 {
107 storeTarget = 1;
108 loadTarget = 0;
109 }
110 else fail("wut");
111
112 testprintf("Weak assignment\n");
113 state = 0;
114 result = objc_storeWeak(&weak, obj);
115 testassert(state == storeTarget);
116 testassert(result == obj);
117 testassert(weak == obj);
118
119 testprintf("Weak assignment to the same value\n");
120 state = 0;
121 result = objc_storeWeak(&weak, obj);
122 testassert(state == storeTarget);
123 testassert(result == obj);
124 testassert(weak == obj);
125
126 testprintf("Weak load\n");
127 state = 0;
128 result = objc_loadWeakRetained(&weak);
129 if (state != loadTarget) testprintf("state %d target %d\n", state, loadTarget);
130 testassert(state == loadTarget);
131 testassert(result == obj);
132 testassert(result == weak);
133 [result release];
134
135 testprintf("Weak assignment to different value\n");
136 state = 0;
137 result = objc_storeWeak(&weak, obj2);
138 testassert(state == storeTarget);
139 testassert(result == obj2);
140 testassert(weak == obj2);
141
142 testprintf("Weak assignment to NULL\n");
143 state = 0;
144 result = objc_storeWeak(&weak, NULL);
145 testassert(state == 0);
146 testassert(result == NULL);
147 testassert(weak == NULL);
148
149 testprintf("Weak re-assignment to NULL\n");
150 state = 0;
151 result = objc_storeWeak(&weak, NULL);
152 testassert(state == 0);
153 testassert(result == NULL);
154 testassert(weak == NULL);
155
156 testprintf("Weak move\n");
157 state = 0;
158 result = objc_storeWeak(&weak, obj);
159 testassert(state == storeTarget);
160 testassert(result == obj);
161 testassert(weak == obj);
162 weak2 = (id)(PAGE_MAX_SIZE-16);
163 objc_moveWeak(&weak2, &weak);
164 testassert(weak == nil);
165 testassert(weak2 == obj);
166 objc_storeWeak(&weak2, NULL);
167
168 testprintf("Weak copy\n");
169 state = 0;
170 result = objc_storeWeak(&weak, obj);
171 testassert(state == storeTarget);
172 testassert(result == obj);
173 testassert(weak == obj);
174 weak2 = (id)(PAGE_MAX_SIZE-16);
175 objc_copyWeak(&weak2, &weak);
176 testassert(weak == obj);
177 testassert(weak2 == obj);
178 objc_storeWeak(&weak, NULL);
179 objc_storeWeak(&weak2, NULL);
180
181 testprintf("Weak clear\n");
182
183 id obj3 = [cls new];
184
185 state = 0;
186 result = objc_storeWeak(&weak, obj3);
187 testassert(state == storeTarget);
188 testassert(result == obj3);
189 testassert(weak == obj3);
190
191 state = 0;
192 result = objc_storeWeak(&weak2, obj3);
193 testassert(state == storeTarget);
194 testassert(result == obj3);
195 testassert(weak2 == obj3);
196
197 did_dealloc = false;
198 [obj3 release];
199 testassert(did_dealloc);
200 testassert(weak == NULL);
201 testassert(weak2 == NULL);
202 }
203
204
205 void test_class(Class cls)
206 {
207 Test *obj = [cls new];
208 Test *obj2 = [cls new];
209
210 for (int i = 0; i < 100000; i++) {
211 if (i == 10) leak_mark();
212 cycle(cls, obj, obj2);
213 }
214 // allow some slop for [Test new] inside cycle()
215 // to land in different side table stripes
216 leak_check(8192);
217
218
219 // rdar://14105994
220 id weaks[8];
221 for (size_t i = 0; i < sizeof(weaks)/sizeof(weaks[0]); i++) {
222 objc_storeWeak(&weaks[i], obj);
223 }
224 for (size_t i = 0; i < sizeof(weaks)/sizeof(weaks[0]); i++) {
225 objc_storeWeak(&weaks[i], nil);
226 }
227 }
228
229 int main()
230 {
231 test_class([Test class]);
232 test_class([CustomTryRetain class]);
233 test_class([CustomIsDeallocating class]);
234 test_class([CustomAllowsWeakReference class]);
235 test_class([CustomRetainWeakReference class]);
236
237
238 id result;
239
240 Crash *obj3 = [Crash new];
241 result = objc_storeWeak(&weak, obj3);
242 testassert(result == obj3);
243 testassert(weak == obj3);
244
245 result = objc_storeWeak(&weak2, obj3);
246 testassert(result == obj3);
247 testassert(weak2 == obj3);
248
249 [obj3 release];
250 fail("should have crashed in -[Crash dealloc]");
251 }