]> git.saurik.com Git - apple/objc4.git/blobdiff - test/initializeVersusWeak.m
objc4-818.2.tar.gz
[apple/objc4.git] / test / initializeVersusWeak.m
index c7a0e368064aeadfb14154fc13e0f6a8c8034e85..e9c1580d463d986b6d044ee815230f8794024564 100644 (file)
 #include <objc/objc-internal.h>
 #include "test.h"
 
-#pragma clang diagnostic ignored "-Wdeprecated-declarations"
 #pragma clang diagnostic ignored "-Warc-unsafe-retained-assign"
 
 // This is StripedMap's pointer hash
-uintptr_t hash(id obj) {
+#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
+    enum { StripeCount = 8 };
+#else
+    enum { StripeCount = 64 };
+#endif
+uintptr_t stripehash(id obj) {
     uintptr_t addr = (uintptr_t)obj;
-    return ((addr >> 4) ^ (addr >> 9)) % 64;
+    return ((addr >> 4) ^ (addr >> 9)) % StripeCount;
 }
 
 bool sameAlignment(id o1, id o2)
 {
-    return hash(o1) == hash(o2);
+    return stripehash(o1) == stripehash(o2);
 }
 
-// Return a new string object that uses the same striped weak locks as `obj`.
-NSMutableString *newAlignedString(id obj) 
+// Return a new non-tagged object that uses the same striped weak locks as `obj`
+NSObject *newAlignedObject(id obj) 
 {
-    NSMutableArray *strings = [NSMutableArray new];
-    NSMutableString *result;
-    do {
-        result = [NSMutableString new];
-        [strings addObject:result];
-    } while (!sameAlignment(obj, result));
+    // Use immutable arrays because their contents are stored inline, 
+    // which prevents Guard Malloc from using the same alignment for all of them
+    NSArray *result = [NSArray new];
+    while (!sameAlignment(obj, result)) {
+        result = [result arrayByAddingObject:result];
+    }
     return result;
 }
 
 
 __weak NSObject *weak1;
-__weak NSMutableString *weak2;
-NSMutableString *strong2;
+__weak NSObject *weak2;
+NSObject *strong2;
 
 @interface A : NSObject @end
 @implementation A
@@ -58,7 +62,7 @@ void testA()
     // without holding locks.
     @autoreleasepool {
         A *obj = [A new];
-        strong2 = newAlignedString(obj);
+        strong2 = newAlignedObject(obj);
         [obj addObserver:obj forKeyPath:@"foo" options:0 context:0];
         weak1 = obj;  // weak store #1
         [obj removeObserver:obj forKeyPath:@"foo"];
@@ -68,8 +72,8 @@ void testA()
 
 
 __weak NSObject *weak3;
-__weak NSMutableString *weak4;
-NSMutableString *strong4;
+__weak NSObject *weak4;
+NSObject *strong4;
 
 @interface B : NSObject @end
 @implementation B
@@ -87,7 +91,7 @@ void testB()
     // without holding locks.
     @autoreleasepool {
         B *obj = [B new];
-        strong4 = newAlignedString(obj);
+        strong4 = newAlignedObject(obj);
         weak3 = obj;
         [obj addObserver:obj forKeyPath:@"foo" options:0 context:0];
         [weak3 self];  // weak load #3
@@ -116,13 +120,67 @@ void testC()
 }
 
 
-int main()
+__weak id weak6;
+NSObject *strong6;
+semaphore_t Dgo;
+semaphore_t Ddone;
+
+void *Dthread(void *arg __unused)
+{
+    @autoreleasepool {
+        semaphore_wait(Dgo);
+        for (int i = 0; i < 1000; i++) {
+            id x = weak6;
+            testassert(x == strong6);
+        }
+        return nil;
+    }
+}
+
+@interface D : NSObject @end
+@implementation D
++(void)initialize {
+    strong6 = [self new];
+    weak6 = strong6;
+    semaphore_signal(Dgo);
+    for (int i = 0; i < 1000; i++) {
+        id x = weak6;
+        testassert(x == strong6);
+    }
+}
+@end
+
+void testD()
 {
-    alarm(10);  // replace hangs with crashes
+    // +initialize performs a weak store of itself, then another thread
+    // tries to load that weak variable before +initialize completes.
+    // Deadlock occurs if the +initialize thread tries to acquire the
+    // sidetable lock for another operation and the second thread holds
+    // the sidetable lock while waiting for +initialize.
+    
+    @autoreleasepool {
+        semaphore_create(mach_task_self(), &Dgo, 0, 0);
+        semaphore_create(mach_task_self(), &Ddone, 0, 0);
+        pthread_t th;
+        pthread_create(&th, nil, Dthread, nil);
+        [D self];
+        pthread_join(th, nil);
+    }
+}
 
-    testA();
-    testB();
-    testC();
+int main()
+{
+    if (is_guardmalloc() && getenv("MALLOC_PROTECT_BEFORE")) {
+        testwarn("fixme malloc guard before breaks this with debug libobjc");
+    }
+    else {
+        alarm(10);  // replace hangs with crashes
+        
+        testA();
+        testB();
+        testC();
+        testD();
+    }
 
     succeed(__FILE__);
 }