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.
This commit is contained in:
Svyatoslav Scherbina
2021-05-21 07:34:34 +00:00
committed by Space
parent 573191251e
commit dc8934ab22
@@ -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>): 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_type>): 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)