[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
This commit is contained in:
Artem Vasilev
2022-12-15 17:50:19 +01:00
committed by Space Team
parent 11bc3dbd82
commit 879f6c3432
@@ -96,20 +96,22 @@ internal class ValueWithPostCompute<KEY, VALUE, DATA>(
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
// should be called under a synchronized section // should be called under a synchronized section
private fun computeValueWithoutLock(): VALUE { 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 // 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 // or the some other thread calculated the value while we were waiting to acquire the lock
when (val newStateSnapshot = value) { when (val newStateSnapshot = value) {
ValueIsNotComputed -> { ValueIsNotComputed -> {
// will be computed next // will be computed later, the read of `ValueIsNotComputed` guarantees that lock is not null
require(lock!!.isHeldByCurrentThread)
} }
is ExceptionWasThrownDuringValueComputation -> { is ExceptionWasThrownDuringValueComputation -> {
// if some other thread tried to compute the value but failed with the exception // if some other thread tried to compute the value but failed with the exception
throw newStateSnapshot.error throw newStateSnapshot.error
} }
else -> { 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 return value as VALUE
} }
} }
@@ -134,6 +136,7 @@ internal class ValueWithPostCompute<KEY, VALUE, DATA>(
lock = null lock = null
guard = null guard = null
value = calculatedValue value = calculatedValue
return calculatedValue return calculatedValue
} }