Mark value fields in ReflectProperties as volatile

These fields were originally non-volatile because of an incorrect
assumption I had at the time that a value was safely published if the
underlying object's class has at least one final field. This is true for
almost all values used in lazy/lazySoft: DeserializedFunctionDescriptor,
DeserializedPropertyDescriptor, KTypeImpl, java.lang.reflect.Field, etc.
But of course, this only means that the object was _safely initialized_
and not safely published via the non-volatile reference, where other
threads can still observe null, even after that constructed object was
leaked to the outer world by some other means and led to observable
changes in behavior.

This can fix some concurrency issues in kotlin-reflect. I wasn't able to
reproduce the problem in stress tests though.
This commit is contained in:
Alexander Udalov
2019-10-23 15:21:32 +02:00
parent 8af3b3e51e
commit c24f2d06d4
@@ -46,7 +46,7 @@ public class ReflectProperties {
// A delegate for a lazy property, whose initializer may be invoked multiple times including simultaneously from different threads
public static class LazyVal<T> extends Val<T> {
private final Function0<T> initializer;
private Object value = null;
private volatile Object value = null;
public LazyVal(@NotNull Function0<T> initializer) {
this.initializer = initializer;
@@ -70,7 +70,7 @@ public class ReflectProperties {
// including simultaneously from different threads
public static class LazySoftVal<T> extends Val<T> {
private final Function0<T> initializer;
private SoftReference<Object> value = null;
private volatile SoftReference<Object> value = null;
public LazySoftVal(@Nullable T initialValue, @NotNull Function0<T> initializer) {
this.initializer = initializer;