puniverse / quasar

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

Incorrect instrumentation verification codepath triggered by function overloads. #294

Open exFalso opened 7 years ago

exFalso commented 7 years ago

The following code:

import co.paralleluniverse.fibers.Fiber
import co.paralleluniverse.fibers.Suspendable

@Suspendable
fun function() {
    function(arrayOf(0))
}

@Suspendable
fun function(m: Any) {
    Fiber.yield()
}

fun main(args: Array<String>) {

    val fiber = object : Fiber<Any>() {
        @Suspendable
        override fun run(): Any {
            return function(object {})
        }
    }

    fiber.start().get()
}

produces

QUASAR WARNING: Assertions enabled. This may harm performance.
QUASAR WARNING: Fibers are set to verify instrumentation. This may *severely* harm performance.
WARNING: Uninstrumented whole methods ('**') or single calls ('!!') detected: 
    at co.paralleluniverse.common.util.ExtendedStackTrace.here() (ExtendedStackTrace.java:46)
    at co.paralleluniverse.fibers.Fiber.checkInstrumentation() (Fiber.java:1694)
    at co.paralleluniverse.fibers.Fiber.verifySuspend(co.paralleluniverse.fibers.Fiber) (Fiber.java:1667)
    at co.paralleluniverse.fibers.Fiber.verifySuspend() (Fiber.java:1662)
    at co.paralleluniverse.fibers.Fiber.yield() (Fiber.java:665)
    at AKt.function() (A.kt:11) !! (instrumented suspendable calls at: lines [6],  calls [AKt.function(java.lang.Object)])
    at AKt$main$fiber$1.run() (A.kt:19) !! (instrumented suspendable calls at: lines [19],  calls [AKt.function(java.lang.Object)])
    at co.paralleluniverse.fibers.Fiber.run1() (Fiber.java:1092)

There are two variants of function, one with no args, and one that accepts an Any. The one with no args is never actually called, however note that in the stack trace it shows up at AKt.function() (A.kt:11) !! (instrumented suspendable calls at: lines [6], calls [AKt.function(java.lang.Object)]).

When this unused function is deleted verification succeeds as it should.

Digging a bit deeper, the overload of function triggers the more complex code path in ExtendedStackTrace.java:getMethod(). From what I understand this codepath tries to figure out which variant was called by using line number information in the bytecode. I think the bug is in this code, setting a breakpoint on the visitEnd() function in the MethodVisitor reveals minLine = 6, maxLine = 26, which is the merge of both function's min/max line number. This means the visitor states got mixed up somehow, causing that codepath to pick the wrong method.

circlespainter commented 6 years ago

With which Quasar version does it happen? I couldn't reproduce it with 0.7.9 and Kotlin 1.1.51 .

exFalso commented 6 years ago

I tried it with Quasar 0.7.9 and Kotlin 1.1.51 and it does the same. Note that this requires instrumentation verification on (-Dco.paralleluniverse.fibers.verifyInstrumentation=true)