kotlinx.coroutines icon indicating copy to clipboard operation
kotlinx.coroutines copied to clipboard

BlockHound false positive in kotlin.jvm.internal.Reflection.renderLambdaToString

Open OliverO2 opened this issue 1 year ago • 4 comments

kotlinx-coroutines-debug:1.8.0

This one appeared once when running Kotest in debug mode with env KOTEST_DEBUG=true ./gradlew ...:

reactor.blockhound.BlockingOperationError: Blocking call! jdk.internal.misc.Unsafe#park
	at app//io.kotest.extensions.blockhound.KotestBlockHoundIntegration.applyTo$lambda$2$lambda$1(KotestBlockHoundIntegration.kt:28)
	at app//reactor.blockhound.BlockHound$Builder.lambda$install$8(BlockHound.java:488)
	at reactor.blockhound.BlockHoundRuntime.checkBlocking(BlockHoundRuntime.java:89)
	at [email protected]/jdk.internal.misc.Unsafe.park(Unsafe.java)
	at [email protected]/java.util.concurrent.locks.LockSupport.park(LockSupport.java:211)
	at [email protected]/java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:715)
	at [email protected]/java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:938)
	at [email protected]/java.util.concurrent.locks.ReentrantLock$Sync.lock(ReentrantLock.java:153)
	at [email protected]/java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:322)
	at app//kotlin.reflect.jvm.internal.impl.storage.DefaultSimpleLock.lock(locks.kt:48)
	at app//kotlin.reflect.jvm.internal.impl.storage.LockBasedStorageManager$MapBasedMemoizedFunction.invoke(LockBasedStorageManager.java:554)
	at app//kotlin.reflect.jvm.internal.impl.serialization.deserialization.TypeDeserializer.typeConstructor(TypeDeserializer.kt:156)
	at app//kotlin.reflect.jvm.internal.impl.serialization.deserialization.TypeDeserializer.simpleType(TypeDeserializer.kt:91)
	at app//kotlin.reflect.jvm.internal.impl.serialization.deserialization.TypeDeserializer.type(TypeDeserializer.kt:68)
	at app//kotlin.reflect.jvm.internal.impl.serialization.deserialization.MemberDeserializer.loadFunction(MemberDeserializer.kt:218)
	at app//kotlin.reflect.jvm.ReflectLambdaKt$reflect$descriptor$1.invoke(reflectLambda.kt:46)
	at app//kotlin.reflect.jvm.ReflectLambdaKt$reflect$descriptor$1.invoke(reflectLambda.kt:46)
	at app//kotlin.reflect.jvm.internal.UtilKt.deserializeToDescriptor(util.kt:267)
	at app//kotlin.reflect.jvm.ReflectLambdaKt.reflect(reflectLambda.kt:45)
	at app//kotlin.reflect.jvm.internal.ReflectionFactoryImpl.renderLambdaToString(ReflectionFactoryImpl.java:56)
	at app//kotlin.reflect.jvm.internal.ReflectionFactoryImpl.renderLambdaToString(ReflectionFactoryImpl.java:51)
	at app//kotlin.jvm.internal.Reflection.renderLambdaToString(Reflection.java:79)
	at app//kotlin.jvm.internal.Lambda.toString(Lambda.kt:11)
	at [email protected]/java.lang.String.valueOf(String.java:4220)
	at [email protected]/java.lang.StringBuilder.append(StringBuilder.java:173)
	at app//io.kotest.core.test.config.ResolvedTestConfig.toString(ResolvedTestConfig.kt)
	at [email protected]/java.lang.String.valueOf(String.java:4220)
	at [email protected]/java.lang.StringBuilder.append(StringBuilder.java:173)
	at app//io.kotest.core.test.TestCase.toString(TestCase.kt)
	at [email protected]/java.lang.String.valueOf(String.java:4220)
	at [email protected]/java.lang.StringBuilder.append(StringBuilder.java:173)
	at app//io.kotest.core.test.TestCase.toString(TestCase.kt)
	at [email protected]/java.lang.String.valueOf(String.java:4220)
	at [email protected]/java.lang.StringBuilder.append(StringBuilder.java:173)
	at app//io.kotest.engine.test.listener.TestCaseExecutionListenerToTestEngineListenerAdapter$testFinished$2.invoke(TestCaseExecutionListenerToTestEngineListenerAdapter.kt:19)
	at app//io.kotest.engine.test.listener.TestCaseExecutionListenerToTestEngineListenerAdapter$testFinished$2.invoke(TestCaseExecutionListenerToTestEngineListenerAdapter.kt:19)
	at app//io.kotest.mpp.Logger$log$1.invoke(logger.kt:19)
	at app//io.kotest.mpp.Logger$log$1.invoke(logger.kt:18)
	at app//io.kotest.mpp.LoggerKt.log(logger.kt:41)
	at app//io.kotest.mpp.Logger.log(logger.kt:18)
	at app//io.kotest.engine.test.listener.TestCaseExecutionListenerToTestEngineListenerAdapter.testFinished(TestCaseExecutionListenerToTestEngineListenerAdapter.kt:19)
	at app//io.kotest.engine.test.interceptors.TestFinishedInterceptor.intercept(TestFinishedInterceptor.kt:26)
	at app//io.kotest.engine.test.interceptors.TestFinishedInterceptor$intercept$1.invokeSuspend(TestFinishedInterceptor.kt)
	at app//kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at app//kotlinx.coroutines.internal.ScopeCoroutine.afterResume(Scopes.kt:28)
	at app//kotlinx.coroutines.AbstractCoroutine.resumeWith(AbstractCoroutine.kt:99)
	at app//kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)
	at app//kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:104)
	at app//kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:585)
	at app//kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:802)
	at app//kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:706)
	at app//kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:693)

Might be worth adding an allowance to BlockHound.Builder.allowBlockingCallsInReflectionImpl() at whatever level is deemed appropriate.

OliverO2 avatar May 13 '24 08:05 OliverO2

The error complains about our reflect library and we (coroutines) are unlikely to ship BH rules for anything but coroutines themselves.

Would it work for you to add a rule in your project for the whole Kotlin reflect package? On a side note, the fact that renderToString acquires a global lock is issue on its own, but alas it's more complicated then "just fix it"

qwwdfsad avatar May 16 '24 10:05 qwwdfsad

we (coroutines) are unlikely to ship BH rules for anything but coroutines themselves.

We already do: https://github.com/Kotlin/kotlinx.coroutines/blob/cd696d3f8f4afdbc735915c2bded974616331b55/kotlinx-coroutines-debug/src/CoroutinesBlockHoundIntegration.kt#L173-L183

for the whole Kotlin reflect package?

A bit scary, given that reflection can execute arbitrary user-supplied code.

dkhalanskyjb avatar May 16 '24 10:05 dkhalanskyjb

The error complains about our reflect library and we (coroutines) are unlikely to ship BH rules for anything but coroutines themselves.

Surely a balancing issue, just thought to let you know because some reflection allowance was already there.

Would it work for you to add a rule in your project for the whole Kotlin reflect package?

Sure, no big deal. [Edit: Not the whole package, but selected reflection functions.]

On a side note, the fact that renderToString acquires a global lock is issue on its own, but alas it's more complicated then "just fix it"

Agreed.

OliverO2 avatar May 16 '24 10:05 OliverO2

Just FYI, here is another blocking call from reflection triggered by Ktor 2.3.12:

reactor.blockhound.BlockingOperationError: Blocking call! jdk.internal.misc.Unsafe#park
    at app//de.infix.testBalloon.integration.blockingDetection.TestBalloonBlockHoundIntegration.applyTo$lambda$1$lambda$0(Integration.jvm.kt:76)
    at app//reactor.blockhound.BlockHound$Builder.lambda$install$8(BlockHound.java:488)
    at reactor.blockhound.BlockHoundRuntime.checkBlocking(BlockHoundRuntime.java:89)
    at [email protected]/jdk.internal.misc.Unsafe.park(Unsafe.java)
    at [email protected]/java.util.concurrent.locks.LockSupport.park(LockSupport.java:211)
    at [email protected]/java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:715)
    at [email protected]/java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:938)
    at [email protected]/java.util.concurrent.locks.ReentrantLock$Sync.lock(ReentrantLock.java:153)
    at [email protected]/java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:322)
    at app//kotlin.reflect.jvm.internal.impl.storage.DefaultSimpleLock.lock(locks.kt:48)
    at app//kotlin.reflect.jvm.internal.impl.storage.LockBasedStorageManager$LockBasedLazyValue.invoke(LockBasedStorageManager.java:386)
    at app//kotlin.reflect.jvm.internal.impl.storage.LockBasedStorageManager$LockBasedNotNullLazyValue.invoke(LockBasedStorageManager.java:527)
    at app//kotlin.reflect.jvm.internal.impl.descriptors.impl.AbstractClassDescriptor.getDefaultType(AbstractClassDescriptor.java:175)
    at app//kotlin.reflect.jvm.internal.impl.types.KotlinTypeFactory.simpleType(KotlinTypeFactory.kt:85)
    at app//kotlin.reflect.jvm.internal.impl.types.KotlinTypeFactory.simpleType$default(KotlinTypeFactory.kt:77)
    at app//kotlin.reflect.full.KClassifiers.createKotlinType(KClassifiers.kt:69)
    at app//kotlin.reflect.full.KClassifiers.createType(KClassifiers.kt:62)
    at app//kotlin.reflect.jvm.internal.CachesKt$CACHE_FOR_BASE_CLASSIFIERS$1.invoke(caches.kt:37)
    at app//kotlin.reflect.jvm.internal.CachesKt$CACHE_FOR_BASE_CLASSIFIERS$1.invoke(caches.kt:36)
    at app//kotlin.reflect.jvm.internal.ComputableClassValue.computeValue(CacheByClass.kt:49)
    at app//kotlin.reflect.jvm.internal.ComputableClassValue.computeValue(CacheByClass.kt:46)
    at [email protected]/java.lang.ClassValue.getFromHashMap(ClassValue.java:228)
    at [email protected]/java.lang.ClassValue.getFromBackup(ClassValue.java:210)
    at [email protected]/java.lang.ClassValue.get(ClassValue.java:116)
    at app//kotlin.reflect.jvm.internal.ClassValueCache.get(CacheByClass.kt:63)
    at app//kotlin.reflect.jvm.internal.CachesKt.getOrCreateKType(caches.kt:55)
    at app//kotlin.reflect.jvm.internal.ReflectionFactoryImpl.typeOf(ReflectionFactoryImpl.java:123)
    at app//kotlin.jvm.internal.Reflection.typeOf(Reflection.java:128)
    at app//io.ktor.client.plugins.websocket.BuildersKt.webSocket(builders.kt:247)
    at app//io.ktor.client.plugins.websocket.BuildersKt$webSocket$1.invokeSuspend(builders.kt)
    at app//kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
    at app//kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:101)
    at app//kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:589)
    at app//kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:832)
    at app//kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:720)
    at app//kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:707)

OliverO2 avatar May 16 '25 12:05 OliverO2