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.
12 #include <Foundation/NSObject.h>
16 static bool did_dealloc;
20 @interface NSObject (WeakInternals)
22 -(BOOL)_isDeallocating;
25 @interface Test : NSObject @end
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);
33 // objc_loadWeak() does not eagerly clear the storage.
34 testassert(objc_loadWeakRetained(&weak) == nil);
35 testassert(weak != nil);
37 // dealloc clears the storage.
38 testprintf("Weak references clear during super dealloc\n");
39 testassert(weak2 != nil);
41 testassert(weak == nil);
42 testassert(weak2 == nil);
48 @interface CustomTryRetain : Test @end
49 @implementation CustomTryRetain
50 -(BOOL)_tryRetain { state++; return [super _tryRetain]; }
53 @interface CustomIsDeallocating : Test @end
54 @implementation CustomIsDeallocating
55 -(BOOL)_isDeallocating { state++; return [super _isDeallocating]; }
58 @interface CustomAllowsWeakReference : Test @end
59 @implementation CustomAllowsWeakReference
60 -(BOOL)allowsWeakReference { state++; return [super allowsWeakReference]; }
63 @interface CustomRetainWeakReference : Test @end
64 @implementation CustomRetainWeakReference
65 -(BOOL)retainWeakReference { state++; return [super retainWeakReference]; }
68 @interface Crash : NSObject @end
71 testassert(weak == self);
72 testassert(weak2 == self);
73 testassert(objc_loadWeakRetained(&weak) == nil);
74 testassert(objc_loadWeakRetained(&weak2) == nil);
76 testprintf("Weak store crashes while deallocating\n");
77 objc_storeWeak(&weak, self);
78 fail("objc_storeWeak of deallocating value should have crashed");
84 void cycle(Class cls, Test *obj, Test *obj2)
86 testprintf("Cycling class %s\n", class_getName(cls));
90 // state counts calls to custom weak methods
91 // Difference test classes have different expected values.
94 if (cls == [Test class]) {
98 else if (cls == [CustomTryRetain class] ||
99 cls == [CustomRetainWeakReference class])
104 else if (cls == [CustomIsDeallocating class] ||
105 cls == [CustomAllowsWeakReference class])
112 testprintf("Weak assignment\n");
114 result = objc_storeWeak(&weak, obj);
115 testassert(state == storeTarget);
116 testassert(result == obj);
117 testassert(weak == obj);
119 testprintf("Weak assignment to the same value\n");
121 result = objc_storeWeak(&weak, obj);
122 testassert(state == storeTarget);
123 testassert(result == obj);
124 testassert(weak == obj);
126 testprintf("Weak load\n");
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);
135 testprintf("Weak assignment to different value\n");
137 result = objc_storeWeak(&weak, obj2);
138 testassert(state == storeTarget);
139 testassert(result == obj2);
140 testassert(weak == obj2);
142 testprintf("Weak assignment to NULL\n");
144 result = objc_storeWeak(&weak, NULL);
145 testassert(state == 0);
146 testassert(result == NULL);
147 testassert(weak == NULL);
149 testprintf("Weak re-assignment to NULL\n");
151 result = objc_storeWeak(&weak, NULL);
152 testassert(state == 0);
153 testassert(result == NULL);
154 testassert(weak == NULL);
156 testprintf("Weak move\n");
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);
168 testprintf("Weak copy\n");
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);
181 testprintf("Weak clear\n");
186 result = objc_storeWeak(&weak, obj3);
187 testassert(state == storeTarget);
188 testassert(result == obj3);
189 testassert(weak == obj3);
192 result = objc_storeWeak(&weak2, obj3);
193 testassert(state == storeTarget);
194 testassert(result == obj3);
195 testassert(weak2 == obj3);
199 testassert(did_dealloc);
200 testassert(weak == NULL);
201 testassert(weak2 == NULL);
205 void test_class(Class cls)
207 Test *obj = [cls new];
208 Test *obj2 = [cls new];
210 for (int i = 0; i < 100000; i++) {
211 if (i == 10) leak_mark();
212 cycle(cls, obj, obj2);
214 // allow some slop for [Test new] inside cycle()
215 // to land in different side table stripes
221 for (size_t i = 0; i < sizeof(weaks)/sizeof(weaks[0]); i++) {
222 objc_storeWeak(&weaks[i], obj);
224 for (size_t i = 0; i < sizeof(weaks)/sizeof(weaks[0]); i++) {
225 objc_storeWeak(&weaks[i], nil);
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]);
240 Crash *obj3 = [Crash new];
241 result = objc_storeWeak(&weak, obj3);
242 testassert(result == obj3);
243 testassert(weak == obj3);
245 result = objc_storeWeak(&weak2, obj3);
246 testassert(result == obj3);
247 testassert(weak2 == obj3);
250 fail("should have crashed in -[Crash dealloc]");