lithdew / quickjs

Go bindings to QuickJS: a fast, small, and embeddable ES2020 JavaScript interpreter.
MIT License
148 stars 37 forks source link

"At code:1" error message #6

Open kooksee opened 3 years ago

kooksee commented 3 years ago
  1. platform: mac
  2. code
func TestName(t *testing.T) {
    const code = `
var name = "test_hello";

function main() {
}

main();
`
    runtime := quickjs.NewRuntime()

    context := runtime.NewContext()
    defer context.Free()

    for {
        val, err := context.Eval(code)
        if err != nil {
            fmt.Printf("%#v\n", err)
            time.Sleep(time.Second)
            continue
        }

        g:=context.Globals()
        fmt.Println(g.Get("name"),val)
        time.Sleep(time.Millisecond*10)
        val.Free()
    }
}
  1. output
    test_hello undefined
    test_hello undefined
    test_hello undefined
    test_hello undefined
    test_hello undefined
    test_hello undefined
    test_hello undefined
    test_hello undefined
    test_hello undefined
    test_hello undefined
    test_hello undefined
    &quickjs.Error{Cause:"", Stack:"    at code:1\n"}
    &quickjs.Error{Cause:"", Stack:"    at code:1\n"}
    &quickjs.Error{Cause:"", Stack:"    at code:1\n"}
    &quickjs.Error{Cause:"", Stack:"    at code:1\n"}
    &quickjs.Error{Cause:"", Stack:"    at code:1\n"}
    &quickjs.Error{Cause:"", Stack:"    at code:1\n"}
    &quickjs.Error{Cause:"", Stack:"    at code:1\n"}
    &quickjs.Error{Cause:"", Stack:"    at code:1\n"}
    &quickjs.Error{Cause:"", Stack:"    at code:1\n"}
    &quickjs.Error{Cause:"", Stack:"    at code:1\n"}
    &quickjs.Error{Cause:"", Stack:"    at code:1\n"}
    &quickjs.Error{Cause:"", Stack:"    at code:1\n"}
    &quickjs.Error{Cause:"", Stack:"    at code:1\n"}
    &quickjs.Error{Cause:"", Stack:"    at code:1\n"}
    &quickjs.Error{Cause:"", Stack:"    at code:1\n"}
    &quickjs.Error{Cause:"", Stack:"    at code:1\n"}
    &quickjs.Error{Cause:"", Stack:"    at code:1\n"}
    &quickjs.Error{Cause:"", Stack:"    at code:1\n"}
    &quickjs.Error{Cause:"", Stack:"    at code:1\n"}
    &quickjs.Error{Cause:"", Stack:"    at code:1\n"}
    &quickjs.Error{Cause:"", Stack:"    at code:1\n"}
    &quickjs.Error{Cause:"", Stack:"    at code:1\n"}
    test_hello undefined
jerome-42 commented 3 years ago

Hi, Same results here (linux/amd64/go 1.15.8). I find the culprit, before parsing code quickjs check the heap size against the memory allocated with:

static inline BOOL js_check_stack_overflow(JSRuntime *rt, size_t alloca_size)
{
    size_t size;
    size = rt->stack_top - js_get_stack_pointer();
    return unlikely((size + alloca_size) > rt->stack_size);
}

with

static inline uint8_t *js_get_stack_pointer(void)
{
    return __builtin_frame_address(0);
}

I have printed value of __builtin_frame_address(0) while calling context.Eval(code):

0x7ffd781aabd0
0x7ffd781aad60
0x7ffd781aa880

The stack value isn't the same but values are close. Then for no apparent reason stack make a big jump !

0x7f27a0556cd0

Then quickjs think something really bad happen (stack overflow) and throw an error. If I replace time.Sleep(time.Millisecond) by time.Sleep(0) which does nothing as the doc says, the problem disappear.

What is the relation between time.Sleep() and __builtin_frame_address(0) ?

I check the time.Sleep() implementation in runtime, but this is related to runtime and scheduler which are too complicated to me. Maybe cgo has an explanation but I have not find it.

As I can't fix the heap size check, I find this workaround: disable the stack check of quickjs by removing the preprocessor CONFIG_STACK_CHECK in quickjs.c line 77:

#if !defined(EMSCRIPTEN)
/* enable stack limitation */
//#define CONFIG_STACK_CHECK /* bug when called after time.Sleep() in Go */
#endif

Maybe someone will fix the js_check_stack_overflow callers to return a real error message as "stack overflow detected" or someone will fix the bug (cgo ? Does the check need to be embedded in Go with runtime's function and not in C part ?).

ex34toway commented 1 year ago

Some issue in jvm,once call it in ScheduledExecutorService scheduleWithFixedDelay method,it will [exception],no any error info....