From c8827424e7acf0822e695c661c2570522aadef7b Mon Sep 17 00:00:00 2001 From: Calvin Rose Date: Thu, 19 Aug 2021 21:51:53 -0500 Subject: [PATCH] Fix memory leak and use after free Use after free was caused by missing janet_gcroot call when setting up thread. --- src/core/ev.c | 1 + src/core/gc.c | 15 +++++++++++++++ src/core/marsh.c | 7 +++---- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/core/ev.c b/src/core/ev.c index c24af8d6..a3eb06ef 100644 --- a/src/core/ev.c +++ b/src/core/ev.c @@ -2487,6 +2487,7 @@ static JanetEVGenericMessage janet_go_thread_subr(JanetEVGenericMessage args) { JANET_MARSHAL_UNSAFE, NULL, &nextbytes); if (!janet_checktype(aregv, JANET_TABLE)) janet_panic("expected table for abstract registry"); janet_vm.abstract_registry = janet_unwrap_table(aregv); + janet_gcroot(janet_wrap_table(janet_vm.abstract_registry)); } /* Get supervsior */ diff --git a/src/core/gc.c b/src/core/gc.c index faba1bf7..b1efbe00 100644 --- a/src/core/gc.c +++ b/src/core/gc.c @@ -512,6 +512,21 @@ int janet_gcunrootall(Janet root) { /* Free all allocated memory */ void janet_clear_memory(void) { +#ifdef JANET_EV + JanetKV *items = janet_vm.threaded_abstracts.data; + for (int32_t i = 0; i < janet_vm.threaded_abstracts.capacity; i++) { + if (janet_checktype(items[i].key, JANET_ABSTRACT)) { + void *abst = janet_unwrap_abstract(items[i].key); + if (0 == janet_abstract_decref(abst)) { + JanetAbstractHead *head = janet_abstract_head(abst); + if (head->type->gc) { + janet_assert(!head->type->gc(head->data, head->size), "finalizer failed"); + } + janet_free(janet_abstract_head(abst)); + } + } + } +#endif JanetGCObject *current = janet_vm.blocks; while (NULL != current) { janet_deinit_block(current); diff --git a/src/core/marsh.c b/src/core/marsh.c index 2d7d2066..a937a70b 100644 --- a/src/core/marsh.c +++ b/src/core/marsh.c @@ -1143,17 +1143,16 @@ static const uint8_t *unmarshal_one_abstract(UnmarshalState *st, const uint8_t * Janet key; data = unmarshal_one(st, data, &key, flags + 1); const JanetAbstractType *at = janet_get_abstract_type(key); - if (at == NULL) goto oops; + if (at == NULL) janet_panic("unknown abstract type"); if (at->unmarshal) { JanetMarshalContext context = {NULL, st, flags, data, at}; *out = janet_wrap_abstract(at->unmarshal(&context)); if (context.at != NULL) { - janet_panicf("janet_unmarshal_abstract not called"); + janet_panic("janet_unmarshal_abstract not called"); } return context.data; } -oops: - janet_panic("invalid abstract type"); + janet_panic("invalid abstract type - no unmarshal function pointer"); } static const uint8_t *unmarshal_one(