Fix memory bug induced by frozen lazy. (#2018)

This commit is contained in:
Nikolay Igotti
2018-09-07 16:30:01 +03:00
committed by GitHub
parent 8f768fd1df
commit 101e7f0048
3 changed files with 39 additions and 2 deletions
+5
View File
@@ -713,6 +713,11 @@ task lazy1(type: RunKonanTest) {
source = "runtime/workers/lazy1.kt"
}
task lazy2(type: RunStandaloneKonanTest) {
goldValue = "123\nOK\n"
source = "runtime/workers/lazy2.kt"
}
task enumIdentity(type: RunKonanTest) {
disabled = (project.testTarget == 'wasm32') // Workers need pthreads.
goldValue = "true\n"
@@ -0,0 +1,31 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
import kotlin.test.*
object Foo {
val bar = Bar()
}
class Bar {
val f by lazy {
foo()
}
fun foo() = 123
}
fun printAll() {
println(Foo.bar.f)
}
// This test is extracted from the real problem found in kotlinx.serialization, where zeroing out
// initializer field in frozen lazy object led to the crash, induced by breaking frozen objects'
// invariant (initializer end up in the same container as the lazy object itself, so it was destroyed
// earlier than it should when reference counter was decremented).
fun main(args: Array<String>) {
printAll()
kotlin.native.internal.GC.collect()
println("OK")
}
@@ -36,8 +36,9 @@ internal class FreezeAwareLazyImpl<out T>(initializer: () -> T) : Lazy<T> {
if (!ensureAcyclicAndSet(this, 0, result)) {
throw InvalidMutabilityException("Setting cyclic data via lazy in $this: $result")
}
// Clear initializer_ reference.
ensureAcyclicAndSet(this, 1, null)
// Do not clear initializer_ reference, as it may break freezing invariants and zero out
// still valid object. It seems to be safe only in case when `this` is not reachable from
// initializer.
@Suppress("UNCHECKED_CAST")
return result as T
}