Search code examples
iosxcodejavascriptcore

Xcode debugger hangs in callback function from JavaScriptCore


Update

It is fixed in Xcode 8.0


Environment

Xcode 7.3.1, iPhone SE, iOS 9.3.5

Problem

I bound C function to JavaScript function by JSObjectMakeFunctionWithCallback with JavaScriptCore framework. If I put breakpoint in this C function, Xcode debugger hangs when execution position comes here from JavaScript by JSEvaluateScript.

  • I want to know reason of issue.
  • I want to know approach to implement C function which works with breakpoint correctly and is callable from JavaScript environment.

I don't need idea using Objective-C API, Because I want to share code with iOS and Android.

Condition

From my experiment, I got these conditions.

  • It does not happens in iOS Simulator.
  • It does not happens when JS function is calling from JSObjectCallAsFunction.
  • It happens when JS function is calling from JSEvaluateScript.

My opinions by looking call stack in Simulator running is this issue is from JavaScriptCore's JIT/LLINT embedded assembly. I guess that these assembly lacks something relates debugging mechanism. So I worry that there is no solution in programmer on user side of JavaScriptCode.

Reproducible source code

I packaged small reproducible example in this repository.

https://github.com/omochi/jscore-debugger-hangup

steps

  1. Clone this repository.
  2. Open with Xcode.
  3. Open test_main.c.
  4. Put breakpoint at printf in TestNativeFunc and JSEvaluateScript in TestMain.
  5. Run application.
  6. It paused at printf.
  7. Continue.
  8. It paused at JSEvaluateScript.
  9. Xcode hangs.

If you remove two breakpoints, it run correctly and print two func messages.

code

static JSValueRef TestNativeFunc(JSContextRef ctx,
                                 JSObjectRef function,
                                 JSObjectRef thisObject,
                                 size_t argumentCount,
                                 const JSValueRef arguments[],
                                 JSValueRef* exception)
{
    printf("func\n");
    return JSValueMakeNull(ctx);
}    

void TestMain() {
    JSGlobalContextRef context = JSGlobalContextCreate(NULL);

    JSObjectRef func = JSObjectMakeFunctionWithCallback(context, NULL, &TestNativeFunc);
    JSValueProtect(context, func);

    JSObjectCallAsFunction(context, func, NULL, 0, NULL, NULL);    

    JSObjectRef global_object = JSContextGetGlobalObject(context);    

    JSStringRef f_str = JSStringCreateWithUTF8CString("f");

    JSObjectSetProperty(context, global_object, f_str, func, 0, NULL);

    JSStringRef script = JSStringCreateWithUTF8CString("f();");
    JSEvaluateScript(context, script, NULL, NULL, 1, NULL);

    JSStringRelease(f_str);

    JSValueUnprotect(context, func);
    JSGlobalContextRelease(context);
}    

Solution

  • This is a known bug in Xcode 7.3.1, and it should be fixed in Xcode 8.0. If you find that it isn't when you get a chance to upgrade to 8.0, please file a bug with http://bugreporter.apple.com.