From 879f6c3432ee1092767f3d74e707ab10af03cb01 Mon Sep 17 00:00:00 2001 From: Artem Vasilev Date: Thu, 15 Dec 2022 17:50:19 +0100 Subject: [PATCH] [LL FIR] restructure lock assertion to prevent NPEs When the other thread has already computed the value and cleared the lock, the other thread could still enter the computeValueWithoutLock() and see lock == null --- .../low/level/api/fir/caches/ValueWithPostCompute.kt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/caches/ValueWithPostCompute.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/caches/ValueWithPostCompute.kt index b8f713a980d..6108fbee742 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/caches/ValueWithPostCompute.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/caches/ValueWithPostCompute.kt @@ -96,20 +96,22 @@ internal class ValueWithPostCompute( @Suppress("UNCHECKED_CAST") // should be called under a synchronized section private fun computeValueWithoutLock(): VALUE { - require(lock!!.isHeldByCurrentThread) // if we entered synchronized section that's mean that the value is not yet calculated and was not started to be calculated // or the some other thread calculated the value while we were waiting to acquire the lock when (val newStateSnapshot = value) { ValueIsNotComputed -> { - // will be computed next + // will be computed later, the read of `ValueIsNotComputed` guarantees that lock is not null + require(lock!!.isHeldByCurrentThread) } is ExceptionWasThrownDuringValueComputation -> { // if some other thread tried to compute the value but failed with the exception throw newStateSnapshot.error } else -> { - // other thread computed the value for us + // other thread computed the value for us and set `lock` to null + require(lock == null) + return value as VALUE } } @@ -134,6 +136,7 @@ internal class ValueWithPostCompute( lock = null guard = null value = calculatedValue + return calculatedValue }