quickjs-go
quickjs-go copied to clipboard
Encountered a segmentation fault (SIGSEGV) when trying to push a function into array.
Description
I encountered a segmentation fault (SIGSEGV) when trying to use quickjs-go to push a function into array.
Environment
- Go Version: 1.24.0
- quickjs-go Version: v0.4.15
- Operating System: macOS 15.3.1
Error Message
SIGSEGV: segmentation violation
PC=0x1042ca938 m=0 sigcode=2 addr=0x8
signal arrived during cgo execution
Reproduction Steps
- Create a new Go file with the following code:
package main
import (
"fmt"
"github.com/buke/quickjs-go"
)
const WorkerListenerName = "__WORKED_LISTENERS__"
// Load worker script
const script = `
addEventListener('fetch', event => {
event.respondWith(
new Response('Hello World!', {
status: 200,
headers: { 'Content-Type': 'text/plain' }
})
);
return 12345;
});
`
func main() {
// Create a new runtime
rt := quickjs.NewRuntime(
quickjs.WithExecuteTimeout(30),
quickjs.WithMemoryLimit(128*1024),
quickjs.WithGCThreshold(256*1024),
quickjs.WithMaxStackSize(65534),
quickjs.WithCanBlock(true),
)
defer rt.Close()
// Create a new context
ctx := rt.NewContext()
defer ctx.Close()
addEventListenerFn := ctx.Function(addEventListener)
ctx.Globals().Set("addEventListener", addEventListenerFn)
ret, err := ctx.Eval(script)
if err != nil {
println(err.Error())
}
defer ret.Free()
defer addEventListenerFn.Free()
fmt.Printf("=========\n")
listeners := ctx.Globals().Get(WorkerListenerName)
fmt.Println(listeners.IsObject())
fmt.Printf("===It's Not OK===%+v\n", listeners.JSONStringify())
fmt.Println(ret.String())
// listeners := ctx.Globals().Get(WorkerListenerName)
// // ss, _ := listeners.Get("fetch").ToArray().Get(0)
// fmt.Printf("===%+v\n", listeners.JSONStringify())
}
func addEventListener(ctx *quickjs.Context, this quickjs.Value, args []quickjs.Value) quickjs.Value {
if len(args) < 2 {
return ctx.Undefined()
}
// Get event type
eventType := args[0].String()
// Get callback function
callback := args[1]
if !callback.IsFunction() {
return ctx.Undefined()
}
listeners := ctx.Globals().Get(WorkerListenerName)
if !listeners.IsObject() {
listeners = ctx.Object()
ctx.Globals().Set(WorkerListenerName, listeners)
}
if listeners.Get(string(eventType)).IsUndefined() {
listeners.Set(string(eventType), ctx.Array().ToValue())
}
listener := ctx.Object()
listener.Set("callback", callback)
listeners.Get(eventType).ToArray().Push(listener)
fmt.Printf("===It's OK==%+v\n", listeners.JSONStringify())
ls := ctx.Globals().Get(WorkerListenerName)
fmt.Printf("===It's OK==%+v\n", ls.JSONStringify())
return ctx.Undefined()
}
- Run the code
Expected Behavior
The code should successfully register the event listener and store it in the global object without crashing.
Actual Behavior
The program crashes with a segmentation fault during execution.
Additional Information
- The crash occurs when trying to handle JavaScript event listeners and store them in a global object
- The error suggests memory access violation during CGO execution
- The code attempts to implement a simple event listener system similar to web browsers
Possible Related Issues
Question
Is there a proper way to handle JavaScript event listeners and store them in the global context using quickjs-go? The current implementation leads to a segmentation fault.
And It's work in C:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "./quickjs/quickjs.h"
char WorkerListenerName[] = "__WORKED_LISTENERS__";
static JSValue js_add_event_listener(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv) {
if (argc != 2)
return JS_UNDEFINED;
const char* event_type = JS_ToCString(ctx, argv[0]);
if (!event_type)
return JS_UNDEFINED;
JSValue callback = JS_DupValue(ctx, argv[1]);
JSValue global_obj = JS_GetGlobalObject(ctx);
JSValue listeners = JS_NewObject(ctx);
JSValue listener = JS_NewObject(ctx);
JS_SetPropertyStr(ctx, listener, "callback", callback);
JSValue arr = JS_NewArray(ctx);
JSValue pushFunc = JS_GetPropertyStr(ctx, arr, "push");
JS_Call(ctx, pushFunc, arr, 1, &listener);
JS_SetPropertyStr(ctx, listeners, event_type, arr);
JS_SetPropertyStr(ctx, global_obj, WorkerListenerName, listeners);
JSValue ref = JS_JSONStringify(ctx, listeners, JS_NULL, JS_NULL);
const char *jsonStr = JS_ToCString(ctx, ref);
printf("===: %s\n", jsonStr);
JS_FreeCString(ctx, event_type);
return JS_UNDEFINED;
}
int main(int argc, char **argv) {
JSRuntime *rt = JS_NewRuntime();
JSContext *ctx = JS_NewContext(rt);
JSValue global_obj = JS_GetGlobalObject(ctx);
JSValue add_event_listener_func = JS_NewCFunction(ctx, js_add_event_listener,
"addEventListener", 2);
JS_SetPropertyStr(ctx, global_obj, "addEventListener", add_event_listener_func);
const char *user_code =
"addEventListener('fetch', event => {\n"
" // event.respondWith(\n"
" // new Response('Hello World!', {\n"
" // status: 200,\n"
" // headers: { 'Content-Type': 'text/plain' }\n"
" // })\n"
" //);\n"
" return 12345;\n"
"});";
JSValue val = JS_Eval(ctx, user_code, strlen(user_code), "<input>", JS_EVAL_TYPE_GLOBAL);
if (JS_IsException(val)) {
JSValue exc = JS_GetException(ctx);
const char *str = JS_ToCString(ctx, exc);
fprintf(stderr, "Error: %s\n", str);
JS_FreeCString(ctx, str);
JS_FreeValue(ctx, exc);
}
JSValue listeners = JS_GetPropertyStr(ctx, global_obj, WorkerListenerName);
JSValue ref = JS_JSONStringify(ctx, listeners, JS_NULL, JS_NULL);
const char *jsonStr = JS_ToCString(ctx, ref);
printf("===: %s\n", jsonStr);
JSValue arr = JS_GetPropertyStr(ctx, listeners, "fetch");
JSValue listener = JS_GetPropertyUint32(ctx, arr, 0);
JSValue callback = JS_GetPropertyStr(ctx, listener, "callback");
JS_BOOL isFn = JS_IsFunction(ctx, callback);
printf("===: %d\n", isFn);
JSValue ret = JS_Call(ctx, callback, listener, 0, NULL);
JSValue ref2 = JS_JSONStringify(ctx, ret, JS_NULL, JS_NULL);
const char *jsonStr2 = JS_ToCString(ctx, ref2);
printf("===: %s\n", jsonStr2);
JS_FreeValue(ctx, val);
JS_FreeValue(ctx, global_obj);
JS_FreeContext(ctx);
// JS_FreeRuntime(rt);
return 0;
}
Have you tried increasing you memory limit? We are experiencing similar crash behaviour when the memory limit is too low. In you C version you have no limit set.
See also https://github.com/buke/quickjs-go/issues/396
please try not to using the collection api (such as context.Array() / value.ToArray() ), using context.Eval with js code to instead it .
and the collection api will be remove in next tag
I'm going to close this issue. If there are any problems, please feel free to reopen it.