From fb81ae0cd1a3edf8898a110a81a51485c5620cb6 Mon Sep 17 00:00:00 2001 From: Svyatoslav Scherbina Date: Mon, 20 Sep 2021 19:32:17 +0300 Subject: [PATCH] Native: fix deadlock in kotlinx.cinterop.typeOf impl for JVM Don't use ConcurrentHashMap.computeIfAbsent for typeOf cache, because the computation may call typeOf recursively for different type (e.g. C enum var type computation calls typeOf for enum base integer type), which might cause a deadlock in computeIfAbsent. --- .../Runtime/src/jvm/kotlin/kotlinx/cinterop/JvmTypes.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/kotlin-native/Interop/Runtime/src/jvm/kotlin/kotlinx/cinterop/JvmTypes.kt b/kotlin-native/Interop/Runtime/src/jvm/kotlin/kotlinx/cinterop/JvmTypes.kt index b9d1f03c710..861be2e0236 100644 --- a/kotlin-native/Interop/Runtime/src/jvm/kotlin/kotlinx/cinterop/JvmTypes.kt +++ b/kotlin-native/Interop/Runtime/src/jvm/kotlin/kotlinx/cinterop/JvmTypes.kt @@ -35,7 +35,12 @@ private val typeOfCache = ConcurrentHashMap, CVariable.Type>() @Suppress("NON_PUBLIC_CALL_FROM_PUBLIC_INLINE") inline fun typeOf() = @Suppress("DEPRECATION") - typeOfCache.computeIfAbsent(T::class.java) { T::class.companionObjectInstance as CVariable.Type } + typeOfCache.getOrPut(T::class.java) { T::class.companionObjectInstance as CVariable.Type } +// Note: not using ^ `computeIfAbsent` because it can cause a deadlock: +// companion object initializer can indirectly use `typeOf` (as it happens for enum "vars"), +// so `computeIfAbsent` would be called recursively for different keys in the case. +// See also the documentation for [ConcurrentHashMap.computeIfAbsent], which +// specifically mentions this problem. /** * Returns interpretation of entity with given pointer, or `null` if it is null.