diff --git a/Test/CMakeLists.txt b/Test/CMakeLists.txt index b88dda39..ca7d7f65 100644 --- a/Test/CMakeLists.txt +++ b/Test/CMakeLists.txt @@ -33,6 +33,7 @@ set(TESTS ProtocolCreation.m ResurrectInDealloc_arc.m RuntimeTest.m + StackBlockRetain_arc.m SuperMethodMissing.m WeakBlock_arc.m WeakRefLoad.m diff --git a/Test/StackBlockRetain_arc.m b/Test/StackBlockRetain_arc.m new file mode 100644 index 00000000..4ec48809 --- /dev/null +++ b/Test/StackBlockRetain_arc.m @@ -0,0 +1,37 @@ +#include "Test.h" + +// A block that captures a stack block copies it when it is copied itself, +// and releases that copy when it goes away. What the captured block +// captured must go with it. + +static int deallocs; + +@interface Captured : Test +@end +@implementation Captured +- (void)dealloc +{ + deallocs++; +} +@end + +static id kept; + +static void keep(void (^block)(void)) +{ + kept = ^{ block(); }; +} + +int main(void) +{ + @autoreleasepool + { + Captured *captured = [Captured new]; + keep(^{ (void)captured; }); + captured = nil; + assert(deallocs == 0); + kept = nil; + } + assert(deallocs == 1); + return 0; +} diff --git a/arc.mm b/arc.mm index 10d4acb6..e99bf073 100644 --- a/arc.mm +++ b/arc.mm @@ -496,6 +496,10 @@ static inline id retain(id obj, BOOL isWeak) Class cls = obj->isa; if (UNLIKELY(objc_test_class_flag(cls, objc_class_flag_is_block))) { + if (cls == static_cast(&_NSConcreteStackBlock)) + { + return obj; + } return Block_copy(obj); } if (objc_test_class_flag(cls, objc_class_flag_fast_arc))