diff options
author | Jo-Philipp Wich <jo@mein.io> | 2024-11-29 17:00:18 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-11-29 17:00:18 +0100 |
commit | 1323a272b6f0dff9445c111c0e47e5633288a39d (patch) | |
tree | a9e37aca9c94fa5ec3ed90c589d6881bf6dad173 /types.c | |
parent | 3408edf99bf214792ea17ff3d67b08890701c2b4 (diff) | |
parent | ed5ce8f490188f3c528c7dd5db09ec0470377283 (diff) |
Merge pull request #246 from jow-/fix-upvalue-resolve
vm: resolve upvalues before pushing them onto the stack
Diffstat (limited to 'types.c')
-rw-r--r-- | types.c | 48 |
1 files changed, 37 insertions, 11 deletions
@@ -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); } |