diff --git a/stdlib/public/runtime/HeapObject.cpp b/stdlib/public/runtime/HeapObject.cpp index 9b3b2b81c989e..4421ae69eed43 100644 --- a/stdlib/public/runtime/HeapObject.cpp +++ b/stdlib/public/runtime/HeapObject.cpp @@ -710,6 +710,13 @@ void swift::swift_rootObjCDealloc(HeapObject *self) { void swift::swift_deallocClassInstance(HeapObject *object, size_t allocatedSize, size_t allocatedAlignMask) { + size_t retainCount = swift_retainCount(object); + if (SWIFT_UNLIKELY(retainCount > 1)) + swift::fatalError(0, + "Object %p deallocated with retain count %zd, reference " + "may have escaped from deinit.\n", + object, retainCount); + #if SWIFT_OBJC_INTEROP // We need to let the ObjC runtime clean up any associated objects or weak // references associated with this object. @@ -718,6 +725,7 @@ void swift::swift_deallocClassInstance(HeapObject *object, #else const bool fastDeallocSupported = true; #endif + if (!fastDeallocSupported || !object->refCounts.getPureSwiftDeallocation()) { objc_destructInstance((id)object); } diff --git a/test/Runtime/deinit_escape.swift b/test/Runtime/deinit_escape.swift new file mode 100644 index 0000000000000..31593b3addb87 --- /dev/null +++ b/test/Runtime/deinit_escape.swift @@ -0,0 +1,26 @@ +// RUN: %target-run-simple-swift + +// REQUIRES: executable_test +// UNSUPPORTED: use_os_stdlib +// UNSUPPORTED: back_deployment_runtime + +import StdlibUnittest + +var DeinitEscapeTestSuite = TestSuite("DeinitEscape") + +var globalObjects: [AnyObject] = [] + +DeinitEscapeTestSuite.test("deinit escapes self") { + expectCrashLater() + + class C { + deinit { + globalObjects.append(self) + } + } + _ = C() + + expectUnreachable() +} + +runAllTests()