2 // TEST_CFLAGS -framework Foundation
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.
11 #include <Foundation/Foundation.h>
12 #include <objc/objc-internal.h>
15 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
16 #pragma clang diagnostic ignored "-Warc-unsafe-retained-assign"
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;
24 bool sameAlignment(id o1, id o2)
26 return hash(o1) == hash(o2);
29 // Return a new string object that uses the same striped weak locks as `obj`.
30 NSMutableString *newAlignedString(id obj)
32 NSMutableArray *strings = [NSMutableArray new];
33 NSMutableString *result;
35 result = [NSMutableString new];
36 [strings addObject:result];
37 } while (!sameAlignment(obj, result));
42 __weak NSObject *weak1;
43 __weak NSMutableString *weak2;
44 NSMutableString *strong2;
46 @interface A : NSObject @end
49 weak2 = strong2; // weak store #2
56 // Weak store #1 provokes +initialize which performs weak store #2.
57 // Solution: weak store #1 runs +initialize if needed
58 // without holding locks.
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"];
70 __weak NSObject *weak3;
71 __weak NSMutableString *weak4;
72 NSMutableString *strong4;
74 @interface B : NSObject @end
77 weak4 = strong4; // weak store #4
85 // Weak load #3 provokes +initialize which performs weak store #4.
86 // Solution: object_setClass() runs +initialize if needed
87 // without holding locks.
90 strong4 = newAlignedString(obj);
92 [obj addObserver:obj forKeyPath:@"foo" options:0 context:0];
93 [weak3 self]; // weak load #3
94 [obj removeObserver:obj forKeyPath:@"foo"];
102 @interface C : NSObject @end
111 // +initialize performs a weak store of itself.
112 // Make sure the retry in objc_storeWeak() doesn't spin.
121 alarm(10); // replace hangs with crashes