LiquidPlayer / LiquidCore

Node.js virtual machine for Android and iOS
MIT License
1.01k stars 127 forks source link

Sporadic JNI error : ClassCastException #125

Closed skloik closed 4 years ago

skloik commented 5 years ago

Hi,

Occasionally liquidCore crashing with this kind of error:

signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr -------- Abort message: 'java_vm_ext.cc:542] JNI DETECTED ERROR IN APPLICATION: JNI NewLongArray called with pending exception java.lang.ClassCastException: org.liquidplayer.javascript.JNIJSValue cannot be cast to org.liquidplayer.javascript.JNIJSObject'

Android: 26 ABI: arm64 LiquidCore: 0.6.2

ericwlange commented 5 years ago

@skloik Hard to tell what's happening here, as it is a pending exception in JNI. That means it occurred before the call to NewLongArray, which is used exactly once in LiquidCore, in JSFunction.cpp. This is called upon a callback from JavaScript to Java.

One instance where I can imagine this happening would be the following:

JSContext context = new JSContext();
JSFunction failMe = new JSFunction(context, "failMe") {
    public void failMe(JSObject obj) {
        // We are expecting an object here, but what if JavaScript sends me a number??
        // You will probably get a similar exception
    }
}
context.property("failMe", failMe);
context.evaluateScript("failMe({})"); // This should work without error
context.evaluateScript("failMe(5)"); // This may generate an exception like you see

When you create a JSFunction callback, the parameter signature is assumed to be correct based on what's called from JavaScript. If the signature of what's actually called from JavaScript does not match, it will throw. If you are working with unknown types, then use JSValue directly and test in the callback, like so:

JSContext context = new JSContext();
JSFunction succeedMe = new JSFunction(context, "succeedMe") {
    public void succeedMe(JSValue value) {
        // We are expecting an object here, but what if JavaScript sends me a number??
        if (value.isObject()) {
            JSObject obj = value.toObject();
            // Now you can treat it as an object
        } else if (value.isNumber()) {
            // Do something else
        }
    }
}
context.property("succeedMe", succeedMe);
context.evaluateScript("succeedMe({})"); // This should work without error
context.evaluateScript("succeedMe(5)"); // So should this
ericwlange commented 4 years ago

Closing as no response from OP.