From dc8934ab22d4b6ae648f3ab367c3dee1eebeb76e Mon Sep 17 00:00:00 2001 From: Svyatoslav Scherbina Date: Fri, 21 May 2021 07:34:34 +0000 Subject: [PATCH] Native: fix crash in custom LLVM diagnostics handler 48a684c0 added custom LLVM diagnostic handler, using JvmCallbacks machinery, thus triggered a bug in the latter: callbacks are cached and outlive the compilation session, but rely on memory that is reclaimed at the end of the compilation session. So during a subsequent compilation in the same process (e.g. when the compiler runs in the Gradle daemon process), LLVM might call the callback which accesses the reclaimed memory, which in turn causes the crash. Fix this by forcing JvmCallbacks to allocate memory that doesn't "expire" at the end of the compilation session. --- .../kotlin/kotlinx/cinterop/JvmCallbacks.kt | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/kotlin-native/Interop/Runtime/src/jvm/kotlin/kotlinx/cinterop/JvmCallbacks.kt b/kotlin-native/Interop/Runtime/src/jvm/kotlin/kotlinx/cinterop/JvmCallbacks.kt index edbf5a39f3c..3f6b9d5acf8 100644 --- a/kotlin-native/Interop/Runtime/src/jvm/kotlin/kotlinx/cinterop/JvmCallbacks.kt +++ b/kotlin-native/Interop/Runtime/src/jvm/kotlin/kotlinx/cinterop/JvmCallbacks.kt @@ -405,7 +405,7 @@ private external fun ffiTypeStruct0(elements: Long): Long * @param elements types of the struct elements */ private fun ffiTypeStruct(elementTypes: List): ffi_type { - val elements = nativeHeap.allocArrayOfPointersTo(*elementTypes.toTypedArray(), null) + val elements = persistentHeap.allocArrayOfPointersTo(*elementTypes.toTypedArray(), null) val res = ffiTypeStruct0(elements.rawValue) if (res == 0L) { throw OutOfMemoryError() @@ -425,7 +425,7 @@ private external fun ffiCreateCif0(nArgs: Int, rType: Long, argTypes: Long): Lon */ private fun ffiCreateCif(returnType: ffi_type, paramTypes: List): ffi_cif { val nArgs = paramTypes.size - val argTypes = nativeHeap.allocArrayOfPointersTo(*paramTypes.toTypedArray(), null) + val argTypes = persistentHeap.allocArrayOfPointersTo(*paramTypes.toTypedArray(), null) val res = ffiCreateCif0(nArgs, returnType.rawPtr, argTypes.rawValue) when (res) { @@ -456,6 +456,26 @@ private fun ffiCreateClosure(ffiCif: ffi_cif, impl: FfiClosureImpl): NativePtr { return res } +// Callbacks are globally cached and outlive the memory allocated by nativeHeap, +// which gets forcibly reclaimed at the end of the compiler invocation. +// So use an ad hoc allocator that is not affected. +// Note: this is mostly a workaround, but proper solution would require a significant rework of this machinery. +private object persistentHeap : NativeFreeablePlacement { + override fun alloc(size: Long, align: Int): NativePointed { + return interpretOpaquePointed( + nativeMemUtils.allocRaw( + if (size == 0L) 1L else size, // It is a hack: `nativeMemUtils.allocRaw` can't allocate zero bytes + align + ) + ) + } + + override fun free(mem: NativePtr) { + nativeMemUtils.freeRaw(mem) + } + +} + private external fun newGlobalRef(any: Any): Long private external fun derefGlobalRef(ref: Long): Any private external fun deleteGlobalRef(ref: Long) \ No newline at end of file