From ed5ce8f490188f3c528c7dd5db09ec0470377283 Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Fri, 29 Nov 2024 16:36:53 +0100 Subject: types: resolve upvalue values in arrays and objects Some objects, such as wildcard module import namespace dictionaries may contain upvalue type values. Extend `ucv_key_get()` to transparently resolve such values before returning them to the caller in order to avoid increasing the refcount of the upvalue itself, leading to a memory leak later on when the VM indirectly dereferences it on upon `uc_vm_stack_push()`, loosing the upvalue object reference itself in the process. This long standing leak was discovered while fixing another upvalue related module import quirk. Signed-off-by: Jo-Philipp Wich --- types.c | 48 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 11 deletions(-) (limited to 'types.c') diff --git a/types.c b/types.c index 9751e24..26f588e 100644 --- a/types.c +++ b/types.c @@ -2237,8 +2237,9 @@ uc_value_t * ucv_key_get(uc_vm_t *vm, uc_value_t *scope, uc_value_t *key) { uc_value_t *o, *v = NULL; + bool found = false; + uc_upvalref_t *ref; int64_t idx; - bool found; char *k; if (ucv_type(scope) == UC_ARRAY) { @@ -2247,23 +2248,48 @@ ucv_key_get(uc_vm_t *vm, uc_value_t *scope, uc_value_t *key) if (idx < 0 && idx > INT64_MIN && (uint64_t)llabs(idx) <= ucv_array_length(scope)) idx += ucv_array_length(scope); - if (idx >= 0 && (uint64_t)idx < ucv_array_length(scope)) - return ucv_get(ucv_array_get(scope, idx)); + if (idx >= 0 && (uint64_t)idx < ucv_array_length(scope)) { + v = ucv_array_get(scope, idx); + found = true; + } } - k = ucv_key_to_string(vm, key); + if (!found) { + k = ucv_key_to_string(vm, key); + + for (o = scope; o; o = ucv_prototype_get(o)) { + if (ucv_type(o) != UC_OBJECT) + continue; - for (o = scope; o; o = ucv_prototype_get(o)) { - if (ucv_type(o) != UC_OBJECT) - continue; + v = ucv_object_get(o, k ? k : ucv_string_get(key), &found); - v = ucv_object_get(o, k ? k : ucv_string_get(key), &found); + if (found) + break; + } - if (found) - break; + free(k); } - free(k); + /* Handle upvalue values in objects; under some specific circumstances + objects may contain upvalues, this primarily happens with wildcard module + import namespace dictionaries. */ +#ifdef __clang_analyzer__ + /* Clang static analyzer does not understand that ucv_type(NULL) can't + * possibly yield UC_UPVALUE. Nudge it. */ + if (v != NULL && ucv_type(v) == UC_UPVALUE) +#else + if (ucv_type(v) == UC_UPVALUE) +#endif + { + ref = (uc_upvalref_t *)v; + + if (ref->closed) + return ucv_get(ref->value); + else if (vm) + return ucv_get(vm->stack.entries[ref->slot]); + else + return NULL; + } return ucv_get(v); } -- cgit v1.2.3