diff --git a/quickjs.c b/quickjs.c index 0a3abac68..e7d92b70d 100644 --- a/quickjs.c +++ b/quickjs.c @@ -23378,7 +23378,8 @@ static int find_var_htab(JSFunctionDef *fd, JSAtom var_name) p = &fd->vars_htab[i & m]; if (*p == UINT32_MAX) return -1; - if (fd->vars[*p].var_name == var_name) + if (fd->vars[*p].var_name == var_name && + fd->vars[*p].scope_level == 0) return *p; i += j; j += 1; // quadratic probing @@ -23405,11 +23406,9 @@ static int find_var(JSContext *ctx, JSFunctionDef *fd, JSAtom name) if (fd->vars_htab) { i = find_var_htab(fd, name); - if (i == -1) - goto not_found; - vd = &fd->vars[i]; - if (vd->scope_level == 0) + if (i >= 0) return i; + goto not_found; } for(i = fd->var_count; i-- > 0;) { vd = &fd->vars[i]; diff --git a/tests/test_find_var_htab.js b/tests/test_find_var_htab.js new file mode 100644 index 000000000..996954307 --- /dev/null +++ b/tests/test_find_var_htab.js @@ -0,0 +1,20 @@ +import { assert } from "./assert.js"; + +// Regression test for find_var_htab: when a var shadows a block-scoped +// let of the same name, the htab probe must skip entries with +// scope_level != 0. 27 vars are needed to trigger the htab path. +function test_find_var_htab() { + { let x = "let"; } + var v0, v1, v2, v3, v4, v5, v6, v7, v8, v9; + var v10, v11, v12, v13, v14, v15, v16, v17; + var v18, v19, v20, v21, v22, v23, v24; + var x = "var"; + + function closure() { + return x; + } + + assert(closure(), "var", "find_var_htab returned wrong slot index"); +} + +test_find_var_htab();