arr-weak.m   [plain text]


// TEST_CONFIG MEM=mrc
// TEST_CRASHES
/*
TEST_RUN_OUTPUT
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.
CRASHED: SIG(ILL|TRAP)
END
*/

#include "test.h"

#include <Foundation/NSObject.h>

static id weak;
static id weak2;
static bool did_dealloc;

@interface Test : NSObject @end
@implementation Test 
-(void)dealloc {
    testassert(weak == self);
    testassert(weak2 == self);

    testprintf("Weak references clear during super dealloc\n");
    testassert(weak2 != NULL);
    [super dealloc];
    testassert(weak2 == NULL);

    did_dealloc = true;
}
@end

@interface Crash : NSObject @end
@implementation Crash
-(void)dealloc {
    testassert(weak == self);
    testassert(weak2 == self);

    testprintf("Weak store crashes while deallocating\n");
    objc_storeWeak(&weak, self);
    fail("objc_storeWeak of deallocating value should have crashed");
    [super dealloc];
}
@end


void cycle(Test *obj, Test *obj2)
{
    id result;

    testprintf("Weak assignment\n");
    result = objc_storeWeak(&weak, obj);
    testassert(result == obj);
    testassert(weak == obj);

    testprintf("Weak assignment to the same value\n");
    result = objc_storeWeak(&weak, obj);
    testassert(result == obj);
    testassert(weak == obj);

    testprintf("Weak assignment to different value\n");
    result = objc_storeWeak(&weak, obj2);
    testassert(result == obj2);
    testassert(weak == obj2);

    testprintf("Weak assignment to NULL\n");
    result = objc_storeWeak(&weak, NULL);
    testassert(result == NULL);
    testassert(weak == NULL);

    testprintf("Weak re-assignment to NULL\n");
    result = objc_storeWeak(&weak, NULL);
    testassert(result == NULL);
    testassert(weak == NULL);

    testprintf("Weak move\n");
    result = objc_storeWeak(&weak, obj);
    testassert(result == obj);
    testassert(weak == obj);
    weak2 = (id)(PAGE_SIZE-16);
    objc_moveWeak(&weak2, &weak);
    testassert(weak == nil);
    testassert(weak2 == obj);
    objc_storeWeak(&weak2, NULL);

    testprintf("Weak copy\n");
    result = objc_storeWeak(&weak, obj);
    testassert(result == obj);
    testassert(weak == obj);
    weak2 = (id)(PAGE_SIZE-16);
    objc_copyWeak(&weak2, &weak);
    testassert(weak == obj);
    testassert(weak2 == obj);
    objc_storeWeak(&weak, NULL);
    objc_storeWeak(&weak2, NULL);

    testprintf("Weak clear\n");

    id obj3 = [Test new];

    result = objc_storeWeak(&weak, obj3);
    testassert(result == obj3);
    testassert(weak == obj3);

    result = objc_storeWeak(&weak2, obj3);
    testassert(result == obj3);
    testassert(weak2 == obj3);

    did_dealloc = false;
    [obj3 release];
    testassert(did_dealloc);
    testassert(weak == NULL);
    testassert(weak2 == NULL);
}


int main()
{
    Test *obj = [Test new];
    Test *obj2 = [Test new];
    id result;

    for (int i = 0; i < 100000; i++) {
        if (i == 10) leak_mark();
        cycle(obj, obj2);
    }
    // allow some slop for [Test new] inside cycle() 
    // to land in different side table stripes
    leak_check(3072);


    // rdar://14105994
    id weaks[8];
    for (size_t i = 0; i < sizeof(weaks)/sizeof(weaks[0]); i++) {
        objc_storeWeak(&weaks[i], obj);
    }
    for (size_t i = 0; i < sizeof(weaks)/sizeof(weaks[0]); i++) {
        objc_storeWeak(&weaks[i], nil);
    }


    Crash *obj3 = [Crash new];
    result = objc_storeWeak(&weak, obj3);
    testassert(result == obj3);
    testassert(weak == obj3);

    result = objc_storeWeak(&weak2, obj3);
    testassert(result == obj3);
    testassert(weak2 == obj3);

    [obj3 release];
    fail("should have crashed in -[Crash dealloc]");
}