]> git.saurik.com Git - apple/objc4.git/blob - test/initializeVersusWeak.m
objc4-680.tar.gz
[apple/objc4.git] / test / initializeVersusWeak.m
1 // TEST_CONFIG MEM=arc
2 // TEST_CFLAGS -framework Foundation
3
4 // Problem: If weak reference operations provoke +initialize, the runtime
5 // can deadlock (recursive weak lock, or lock inversion between weak lock
6 // and +initialize lock).
7 // Solution: object_setClass() and objc_storeWeak() perform +initialize
8 // if needed so that no weakly-referenced object can ever have an
9 // un-+initialized isa.
10
11 #include <Foundation/Foundation.h>
12 #include <objc/objc-internal.h>
13 #include "test.h"
14
15 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
16 #pragma clang diagnostic ignored "-Warc-unsafe-retained-assign"
17
18 // This is StripedMap's pointer hash
19 uintptr_t hash(id obj) {
20 uintptr_t addr = (uintptr_t)obj;
21 return ((addr >> 4) ^ (addr >> 9)) % 64;
22 }
23
24 bool sameAlignment(id o1, id o2)
25 {
26 return hash(o1) == hash(o2);
27 }
28
29 // Return a new string object that uses the same striped weak locks as `obj`.
30 NSMutableString *newAlignedString(id obj)
31 {
32 NSMutableArray *strings = [NSMutableArray new];
33 NSMutableString *result;
34 do {
35 result = [NSMutableString new];
36 [strings addObject:result];
37 } while (!sameAlignment(obj, result));
38 return result;
39 }
40
41
42 __weak NSObject *weak1;
43 __weak NSMutableString *weak2;
44 NSMutableString *strong2;
45
46 @interface A : NSObject @end
47 @implementation A
48 +(void)initialize {
49 weak2 = strong2; // weak store #2
50 strong2 = nil;
51 }
52 @end
53
54 void testA()
55 {
56 // Weak store #1 provokes +initialize which performs weak store #2.
57 // Solution: weak store #1 runs +initialize if needed
58 // without holding locks.
59 @autoreleasepool {
60 A *obj = [A new];
61 strong2 = newAlignedString(obj);
62 [obj addObserver:obj forKeyPath:@"foo" options:0 context:0];
63 weak1 = obj; // weak store #1
64 [obj removeObserver:obj forKeyPath:@"foo"];
65 obj = nil;
66 }
67 }
68
69
70 __weak NSObject *weak3;
71 __weak NSMutableString *weak4;
72 NSMutableString *strong4;
73
74 @interface B : NSObject @end
75 @implementation B
76 +(void)initialize {
77 weak4 = strong4; // weak store #4
78 strong4 = nil;
79 }
80 @end
81
82
83 void testB()
84 {
85 // Weak load #3 provokes +initialize which performs weak store #4.
86 // Solution: object_setClass() runs +initialize if needed
87 // without holding locks.
88 @autoreleasepool {
89 B *obj = [B new];
90 strong4 = newAlignedString(obj);
91 weak3 = obj;
92 [obj addObserver:obj forKeyPath:@"foo" options:0 context:0];
93 [weak3 self]; // weak load #3
94 [obj removeObserver:obj forKeyPath:@"foo"];
95 obj = nil;
96 }
97 }
98
99
100 __weak id weak5;
101
102 @interface C : NSObject @end
103 @implementation C
104 +(void)initialize {
105 weak5 = [self new];
106 }
107 @end
108
109 void testC()
110 {
111 // +initialize performs a weak store of itself.
112 // Make sure the retry in objc_storeWeak() doesn't spin.
113 @autoreleasepool {
114 [C self];
115 }
116 }
117
118
119 int main()
120 {
121 alarm(10); // replace hangs with crashes
122
123 testA();
124 testB();
125 testC();
126
127 succeed(__FILE__);
128 }
129