From 6c1a482539e8d0b2031ca1aaf8ad6bbb5a0f7c25 Mon Sep 17 00:00:00 2001 From: Alexander Shabalin Date: Mon, 12 Oct 2020 22:20:43 +0300 Subject: [PATCH] Add crashing test on KT-41811 (#4437) --- .../tests/interop/objc/tests/kt41811.h | 2 ++ .../tests/interop/objc/tests/kt41811.kt | 35 +++++++++++++++++++ .../tests/interop/objc/tests/kt41811.m | 2 ++ 3 files changed, 39 insertions(+) diff --git a/backend.native/tests/interop/objc/tests/kt41811.h b/backend.native/tests/interop/objc/tests/kt41811.h index 7f64f6fc699..724c4e55b40 100644 --- a/backend.native/tests/interop/objc/tests/kt41811.h +++ b/backend.native/tests/interop/objc/tests/kt41811.h @@ -5,6 +5,8 @@ extern BOOL deallocRetainReleaseDeallocated; @interface DeallocRetainRelease : NSObject @end; +extern DeallocRetainRelease* globalDeallocRetainRelease; + @protocol WeakReference @required @property (weak) id referent; diff --git a/backend.native/tests/interop/objc/tests/kt41811.kt b/backend.native/tests/interop/objc/tests/kt41811.kt index 5106473b0e1..ae0c2dd50d6 100644 --- a/backend.native/tests/interop/objc/tests/kt41811.kt +++ b/backend.native/tests/interop/objc/tests/kt41811.kt @@ -81,3 +81,38 @@ private fun createGarbageDeallocLoadWeak(weakRef: WeakReferenceProtocol) { assertSame(obj, weakDeallocLoadWeak!!.referent) } } + +@Test +fun testKT41811WithGlobal() { + // Attempt to make the state predictable: + kotlin.native.internal.GC.collect() + + deallocRetainReleaseDeallocated = false + assertFalse(deallocRetainReleaseDeallocated) + + autoreleasepool { + { + globalDeallocRetainRelease = object: DeallocRetainRelease() {} + }() + } + + assertFalse(deallocRetainReleaseDeallocated) + + // Clean up local DeallocRetainRelease on Kotlin side + kotlin.native.internal.GC.collect() + + assertFalse(deallocRetainReleaseDeallocated) + + // And drop the last reference to DeallocRetainRelease from ObjC global scope. + globalDeallocRetainRelease = null + + assertFalse(deallocRetainReleaseDeallocated) + + // This will dispose `DeallocRetainRelease` on Kotlin side, which will cause `dealloc` + // on ObjC side, which triggers `retain` and `release` of `self`. If these messages + // were to reach Kotlin side, the `release` would have immediately scheduled the + // second disposal of Kotlin object. + kotlin.native.internal.GC.collect() + + assertTrue(deallocRetainReleaseDeallocated) +} diff --git a/backend.native/tests/interop/objc/tests/kt41811.m b/backend.native/tests/interop/objc/tests/kt41811.m index f54e05a6e30..0a7335df931 100644 --- a/backend.native/tests/interop/objc/tests/kt41811.m +++ b/backend.native/tests/interop/objc/tests/kt41811.m @@ -15,6 +15,8 @@ BOOL deallocRetainReleaseDeallocated = NO; } @end; +DeallocRetainRelease* globalDeallocRetainRelease = nil; + @implementation ObjCWeakReference @end;