puniverse / quasar

Fibers, Channels and Actors for the JVM
http://docs.paralleluniverse.co/quasar/
Other
4.56k stars 574 forks source link

Parts of fiber stack frames are leaked under certain circumstances #282

Closed exFalso closed 7 years ago

exFalso commented 7 years ago

If a function has two subsequent variable scopes with variables of different types then asm cannot infer whether the stack slots refer to references or not, thereby causing quasar instrumentation to omit incrementing either of idxObj or idxPrim in the InstrumentMethod.FrameInfo constructor. This causes the slots number in the frame record to be smaller than it should be, causing Stack.popMethod to leak references (if there are more objects in the function than primitives).

To reproduce:

import co.paralleluniverse.fibers.Fiber
import co.paralleluniverse.fibers.Stack
import co.paralleluniverse.fibers.Suspendable
import java.util.concurrent.TimeUnit

class MyFiber : Fiber<Unit>() {
    @Suspendable
    override fun run() {
        leaky()

        val stackField = Fiber::class.java.getDeclaredField("stack")
        stackField.isAccessible = true
        val objectsField = Stack::class.java.getDeclaredField("dataObject")
        objectsField.isAccessible = true
        val stack = objectsField.get(stackField.get(this)) as Array<Any?>
        println(stack.toList().take(10)) // prints nulls as well as "leaked"
    }

    @Suspendable
    fun leaky() {
        val a = object {} // this is so that we have more objects than primitives
        do {
            val leaked = "leaked"
            Fiber.park(1, TimeUnit.NANOSECONDS)
        } while (false)
        do {
            val primitive = 2
            Fiber.park(1, TimeUnit.NANOSECONDS)
        } while (false)
    }
}

fun main(args: Array<String>) {
    MyFiber().start()
}
pron commented 7 years ago

The cause is that we clear the references on the stack in Stack.popMethod, but the number of slots to clear is taken from the current frame, which may not be the only frame in the method.

pron commented 7 years ago

Fixed in 977edd2 You can try it in 0.7.9-SNAPSHOT