From ffb83301c58917c26efdd165cfd39ac676bec2d8 Mon Sep 17 00:00:00 2001 From: Calvin Rose Date: Sun, 21 Jun 2026 11:44:19 -0500 Subject: [PATCH] Handle bad ev/thread construction better. We were incorrectly handling bad arguments to create a new thread resulting in corruption. --- src/core/ev.c | 25 +++++++++++++++++++++---- test/fuzzers/fuzz_dobytes.c | 4 +++- test/suite-ev.janet | 4 ++++ 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/src/core/ev.c b/src/core/ev.c index 80bf486b..7fe8b17f 100644 --- a/src/core/ev.c +++ b/src/core/ev.c @@ -2326,6 +2326,14 @@ void janet_ev_threaded_call(JanetThreadedSubroutine fp, JanetEVGenericMessage ar /* Default callback for janet_ev_threaded_await. */ void janet_ev_default_threaded_callback(JanetEVGenericMessage return_value) { if (return_value.fiber == NULL) { + /* Clean up */ + switch (return_value.tag) { + default: + case JANET_EV_TCTAG_STRINGF: + case JANET_EV_TCTAG_ERR_STRINGF: + janet_free(return_value.argp); + break; + } return; } if (janet_fiber_can_resume(return_value.fiber)) { @@ -2340,7 +2348,6 @@ void janet_ev_default_threaded_callback(JanetEVGenericMessage return_value) { case JANET_EV_TCTAG_STRING: case JANET_EV_TCTAG_STRINGF: janet_schedule(return_value.fiber, janet_cstringv((const char *) return_value.argp)); - if (return_value.tag == JANET_EV_TCTAG_STRINGF) janet_free(return_value.argp); break; case JANET_EV_TCTAG_KEYWORD: janet_schedule(return_value.fiber, janet_ckeywordv((const char *) return_value.argp)); @@ -2348,7 +2355,6 @@ void janet_ev_default_threaded_callback(JanetEVGenericMessage return_value) { case JANET_EV_TCTAG_ERR_STRING: case JANET_EV_TCTAG_ERR_STRINGF: janet_cancel(return_value.fiber, janet_cstringv((const char *) return_value.argp)); - if (return_value.tag == JANET_EV_TCTAG_STRINGF) janet_free(return_value.argp); break; case JANET_EV_TCTAG_ERR_KEYWORD: janet_cancel(return_value.fiber, janet_ckeywordv((const char *) return_value.argp)); @@ -2358,6 +2364,14 @@ void janet_ev_default_threaded_callback(JanetEVGenericMessage return_value) { break; } } + /* Clean up */ + switch (return_value.tag) { + default: + case JANET_EV_TCTAG_STRINGF: + case JANET_EV_TCTAG_ERR_STRINGF: + janet_free(return_value.argp); + break; + } janet_gcunroot(janet_wrap_fiber(return_value.fiber)); } @@ -3054,6 +3068,7 @@ static JanetEVGenericMessage janet_go_thread_subr(JanetEVGenericMessage args) { const uint8_t *endbytes = nextbytes + buffer->count; uint32_t flags = args.tag; args.tag = 0; + args.argp = NULL; janet_init(); janet_vm.sandbox_flags = (uint32_t) args.argi; JanetTryState tstate; @@ -3109,7 +3124,7 @@ static JanetEVGenericMessage janet_go_thread_subr(JanetEVGenericMessage args) { janet_panicf("expected function or fiber, got %v", fiberv); } JanetFunction *func = janet_unwrap_function(fiberv); - fiber = janet_fiber(func, 64, func->def->min_arity, &value); + fiber = janet_fiber(func, 64, func->def->min_arity ? 1 : 0, &value); if (fiber == NULL) { janet_panicf("thread function must accept 0 or 1 arguments"); } @@ -3148,7 +3163,9 @@ static JanetEVGenericMessage janet_go_thread_subr(JanetEVGenericMessage args) { /* Make ev/thread call from parent thread error */ if (janet_checktype(tstate.payload, JANET_STRING)) { args.tag = JANET_EV_TCTAG_ERR_STRINGF; - args.argp = strdup((const char *) janet_unwrap_string(tstate.payload)); + JanetString msg = janet_unwrap_string(tstate.payload); + args.argp = janet_malloc(janet_string_length(msg) + 1); + memcpy(args.argp, msg, janet_string_length(msg) + 1); } else { args.tag = JANET_EV_TCTAG_ERR_STRING; args.argp = "failed to start thread"; diff --git a/test/fuzzers/fuzz_dobytes.c b/test/fuzzers/fuzz_dobytes.c index 35257f6c..4f0fb01d 100644 --- a/test/fuzzers/fuzz_dobytes.c +++ b/test/fuzzers/fuzz_dobytes.c @@ -2,7 +2,9 @@ #include /* Disable leak sanitizer */ -int __lsan_is_turned_off(void) { return 1; } +int __lsan_is_turned_off(void) { + return 1; +} int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { diff --git a/test/suite-ev.janet b/test/suite-ev.janet index 77c8ad39..b1829681 100644 --- a/test/suite-ev.janet +++ b/test/suite-ev.janet @@ -605,4 +605,8 @@ (assert (zero? exit-code) "subprocess ran") (assert (= data "hi\nthere\n") "output is correct") +# Error handling +(assert-error "bad thread" (ev/thread in)) +(assert-error "bad thread 2" (ev/thread (fn [x y] x) 1)) + (end-suite)