arr-weak.m 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  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. objc\[\d+\]: HALTED
  7. END
  8. */
  9. #include "test.h"
  10. #include <Foundation/NSObject.h>
  11. static id weak;
  12. static id weak2;
  13. static id weak3;
  14. static id weak4;
  15. static bool did_dealloc;
  16. static int state;
  17. @interface NSObject (WeakInternals)
  18. -(BOOL)_tryRetain;
  19. -(BOOL)_isDeallocating;
  20. @end
  21. @interface Test : NSObject @end
  22. @implementation Test
  23. -(void)dealloc {
  24. testprintf("Weak storeOrNil does not crash while deallocating\n");
  25. weak4 = (id)0x100; // old value must not be used
  26. id result = objc_initWeakOrNil(&weak4, self);
  27. testassert(result == nil);
  28. testassert(weak4 == nil);
  29. result = objc_storeWeakOrNil(&weak4, self);
  30. testassert(result == nil);
  31. testassert(weak4 == nil);
  32. // The value returned by objc_loadWeak() is now nil,
  33. // but the storage is not yet cleared.
  34. testassert(weak == self);
  35. testassert(weak2 == self);
  36. // objc_loadWeak() does not eagerly clear the storage.
  37. testassert(objc_loadWeakRetained(&weak) == nil);
  38. testassert(weak != nil);
  39. // dealloc clears the storage.
  40. testprintf("Weak references clear during super dealloc\n");
  41. testassert(weak2 != nil);
  42. [super dealloc];
  43. testassert(weak == nil);
  44. testassert(weak2 == nil);
  45. did_dealloc = true;
  46. }
  47. @end
  48. @interface CustomTryRetain : Test @end
  49. @implementation CustomTryRetain
  50. -(BOOL)_tryRetain { state++; return [super _tryRetain]; }
  51. @end
  52. @interface CustomIsDeallocating : Test @end
  53. @implementation CustomIsDeallocating
  54. -(BOOL)_isDeallocating { state++; return [super _isDeallocating]; }
  55. @end
  56. @interface CustomAllowsWeakReference : Test @end
  57. @implementation CustomAllowsWeakReference
  58. -(BOOL)allowsWeakReference { state++; return [super allowsWeakReference]; }
  59. @end
  60. @interface CustomRetainWeakReference : Test @end
  61. @implementation CustomRetainWeakReference
  62. -(BOOL)retainWeakReference { state++; return [super retainWeakReference]; }
  63. @end
  64. @interface Crash : NSObject @end
  65. @implementation Crash
  66. -(void)dealloc {
  67. testassert(weak == self);
  68. testassert(weak2 == self);
  69. testassert(objc_loadWeakRetained(&weak) == nil);
  70. testassert(objc_loadWeakRetained(&weak2) == nil);
  71. testprintf("Weak storeOrNil does not crash while deallocating\n");
  72. id result = objc_storeWeakOrNil(&weak, self);
  73. testassert(result == nil);
  74. testprintf("Weak store crashes while deallocating\n");
  75. objc_storeWeak(&weak, self);
  76. fail("objc_storeWeak of deallocating value should have crashed");
  77. [super dealloc];
  78. }
  79. @end
  80. void cycle(Class cls, Test *obj, Test *obj2, bool storeOrNil)
  81. {
  82. testprintf("Cycling class %s\n", class_getName(cls));
  83. id result;
  84. id (*storeWeak)(id *location, id obj);
  85. id (*initWeak)(id *location, id obj);
  86. if (storeOrNil) {
  87. testprintf("Using objc_storeWeakOrNil\n");
  88. storeWeak = objc_storeWeakOrNil;
  89. initWeak = objc_initWeakOrNil;
  90. } else {
  91. testprintf("Using objc_storeWeak\n");
  92. storeWeak = objc_storeWeak;
  93. initWeak = objc_initWeak;
  94. }
  95. // state counts calls to custom weak methods
  96. // Difference test classes have different expected values.
  97. int storeTarget;
  98. int loadTarget;
  99. if (cls == [Test class]) {
  100. storeTarget = 0;
  101. loadTarget = 0;
  102. }
  103. else if (cls == [CustomTryRetain class] ||
  104. cls == [CustomRetainWeakReference class])
  105. {
  106. storeTarget = 0;
  107. loadTarget = 1;
  108. }
  109. else if (cls == [CustomIsDeallocating class] ||
  110. cls == [CustomAllowsWeakReference class])
  111. {
  112. storeTarget = 1;
  113. loadTarget = 0;
  114. }
  115. else fail("wut");
  116. testprintf("Weak assignment\n");
  117. state = 0;
  118. result = storeWeak(&weak, obj);
  119. testassert(state == storeTarget);
  120. testassert(result == obj);
  121. testassert(weak == obj);
  122. testprintf("Weak assignment to the same value\n");
  123. state = 0;
  124. result = storeWeak(&weak, obj);
  125. testassert(state == storeTarget);
  126. testassert(result == obj);
  127. testassert(weak == obj);
  128. testprintf("Weak load\n");
  129. state = 0;
  130. result = objc_loadWeakRetained(&weak);
  131. if (state != loadTarget) testprintf("state %d target %d\n", state, loadTarget);
  132. testassert(state == loadTarget);
  133. testassert(result == obj);
  134. testassert(result == weak);
  135. [result release];
  136. testprintf("Weak assignment to different value\n");
  137. state = 0;
  138. result = storeWeak(&weak, obj2);
  139. testassert(state == storeTarget);
  140. testassert(result == obj2);
  141. testassert(weak == obj2);
  142. testprintf("Weak assignment to NULL\n");
  143. state = 0;
  144. result = storeWeak(&weak, NULL);
  145. testassert(state == 0);
  146. testassert(result == NULL);
  147. testassert(weak == NULL);
  148. testprintf("Weak re-assignment to NULL\n");
  149. state = 0;
  150. result = storeWeak(&weak, NULL);
  151. testassert(state == 0);
  152. testassert(result == NULL);
  153. testassert(weak == NULL);
  154. testprintf("Weak move\n");
  155. state = 0;
  156. result = storeWeak(&weak, obj);
  157. testassert(state == storeTarget);
  158. testassert(result == obj);
  159. testassert(weak == obj);
  160. weak2 = (id)(PAGE_MAX_SIZE-16);
  161. objc_moveWeak(&weak2, &weak);
  162. testassert(weak == nil);
  163. testassert(weak2 == obj);
  164. storeWeak(&weak2, NULL);
  165. testprintf("Weak copy\n");
  166. state = 0;
  167. result = storeWeak(&weak, obj);
  168. testassert(state == storeTarget);
  169. testassert(result == obj);
  170. testassert(weak == obj);
  171. weak2 = (id)(PAGE_MAX_SIZE-16);
  172. objc_copyWeak(&weak2, &weak);
  173. testassert(weak == obj);
  174. testassert(weak2 == obj);
  175. storeWeak(&weak, NULL);
  176. storeWeak(&weak2, NULL);
  177. testprintf("Weak clear\n");
  178. id obj3 = [cls new];
  179. state = 0;
  180. result = storeWeak(&weak, obj3);
  181. testassert(state == storeTarget);
  182. testassert(result == obj3);
  183. testassert(weak == obj3);
  184. state = 0;
  185. result = storeWeak(&weak2, obj3);
  186. testassert(state == storeTarget);
  187. testassert(result == obj3);
  188. testassert(weak2 == obj3);
  189. did_dealloc = false;
  190. [obj3 release];
  191. testassert(did_dealloc);
  192. testassert(weak == NULL);
  193. testassert(weak2 == NULL);
  194. testprintf("Weak init and destroy\n");
  195. id obj4 = [cls new];
  196. state = 0;
  197. weak = (id)0x100; // old value must not be used
  198. result = initWeak(&weak, obj4);
  199. testassert(state == storeTarget);
  200. testassert(result == obj4);
  201. testassert(weak == obj4);
  202. state = 0;
  203. weak2 = (id)0x100; // old value must not be used
  204. result = initWeak(&weak2, obj4);
  205. testassert(state == storeTarget);
  206. testassert(result == obj4);
  207. testassert(weak2 == obj4);
  208. state = 0;
  209. weak3 = (id)0x100; // old value must not be used
  210. result = initWeak(&weak3, obj4);
  211. testassert(state == storeTarget);
  212. testassert(result == obj4);
  213. testassert(weak3 == obj4);
  214. state = 0;
  215. objc_destroyWeak(&weak3);
  216. testassert(state == 0);
  217. testassert(weak3 == obj4); // storage is unchanged
  218. did_dealloc = false;
  219. [obj4 release];
  220. testassert(did_dealloc);
  221. testassert(weak == NULL); // not destroyed earlier so cleared now
  222. testassert(weak2 == NULL); // not destroyed earlier so cleared now
  223. testassert(weak3 == obj4); // destroyed earlier so not cleared now
  224. objc_destroyWeak(&weak);
  225. objc_destroyWeak(&weak2);
  226. }
  227. void test_class(Class cls)
  228. {
  229. // prime strong and weak side tables before leak checking
  230. Test *prime[256] = {nil};
  231. for (size_t i = 0; i < sizeof(prime)/sizeof(prime[0]); i++) {
  232. objc_storeWeak(&prime[i], [cls new]);
  233. }
  234. Test *obj = [cls new];
  235. Test *obj2 = [cls new];
  236. for (int i = 0; i < 100000; i++) {
  237. cycle(cls, obj, obj2, false);
  238. cycle(cls, obj, obj2, true);
  239. }
  240. leak_mark();
  241. for (int i = 0; i < 100000; i++) {
  242. cycle(cls, obj, obj2, false);
  243. cycle(cls, obj, obj2, true);
  244. }
  245. // allow some slop for side table expansion
  246. // 5120 is common with this configuration
  247. leak_check(6000);
  248. // rdar://14105994
  249. id weaks[8];
  250. for (size_t i = 0; i < sizeof(weaks)/sizeof(weaks[0]); i++) {
  251. objc_storeWeak(&weaks[i], obj);
  252. }
  253. for (size_t i = 0; i < sizeof(weaks)/sizeof(weaks[0]); i++) {
  254. objc_storeWeak(&weaks[i], nil);
  255. }
  256. }
  257. int main()
  258. {
  259. test_class([Test class]);
  260. test_class([CustomTryRetain class]);
  261. test_class([CustomIsDeallocating class]);
  262. test_class([CustomAllowsWeakReference class]);
  263. test_class([CustomRetainWeakReference class]);
  264. id result;
  265. Crash *obj3 = [Crash new];
  266. result = objc_storeWeak(&weak, obj3);
  267. testassert(result == obj3);
  268. testassert(weak == obj3);
  269. result = objc_storeWeak(&weak2, obj3);
  270. testassert(result == obj3);
  271. testassert(weak2 == obj3);
  272. [obj3 release];
  273. fail("should have crashed in -[Crash dealloc]");
  274. }