# UNDF: UNDF-2026-000000705 --- a/lparser.h +++ b/lparser.h @@ -60,6 +60,10 @@ typedef struct FuncState { struct FuncState *prev; /* enclosing function */ struct LexState *ls; /* lexical state */ BlockCnt *bl; /* chain of current blocks */ + /* CWE-407 fix: hash map for O(1) upvalue name lookup. + * upval_ht[name->hash & (UPVAL_HT_SIZE-1)] = upvalue index + 1, 0 = empty. + * Collisions fall back to the linear scan in searchupvalue_slow(). */ + int upval_ht[256]; } FuncState; --- a/lparser.c +++ b/lparser.c @@ -357,11 +357,37 @@ static int searchupvalue (FuncState *fs, TString *name) { ** Search the upvalues of the function 'fs' for one ** with the given 'name'. */ +/* CWE-407: full O(n) fallback — only used on hash collision */ +static int searchupvalue_slow (FuncState *fs, TString *name) { + int i; + Upvaldesc *up = fs->f->upvalues; + for (i = 0; i < fs->nups; i++) { + if (eqstr(up[i].name, name)) return i; + } + return -1; +} + static int searchupvalue (FuncState *fs, TString *name) { int i; - Upvaldesc *up = fs->f->upvalues; - for (i = 0; i < fs->nups; i++) { - if (eqstr(up[i].name, name)) return i; + int slot = (int)(name->hash & 255u); + /* probe up to 8 slots before falling back to linear scan */ + for (i = 0; i < 8; i++, slot = (slot + 1) & 255) { + int entry = fs->upval_ht[slot]; + if (entry == 0) return -1; /* empty slot — not present */ + if (eqstr(fs->f->upvalues[entry - 1].name, name)) + return entry - 1; } - return -1; /* not found */ + return searchupvalue_slow(fs, name); /* collision fallback */ } @@ -382,6 +408,10 @@ static int newupvalue (FuncState *fs, TString *name, expdesc *v) { Upvaldesc *up = allocupvalue(fs); FuncState *prev = fs->prev; + /* CWE-407 fix: register new upvalue in hash table */ + int slot = (int)(name->hash & 255u); + while (fs->upval_ht[slot]) slot = (slot + 1) & 255; + fs->upval_ht[slot] = fs->nups; /* store index+1 (0 = empty sentinel) */ + if (v->k == VLOCAL) {