From 538a82133ad6fddfd0ca64de167c4aca3bc1a2da Mon Sep 17 00:00:00 2001 From: Mike Pall Date: Tue, 11 Mar 2025 23:04:30 +0100 Subject: Change handling of nil value markers in template tables. Reported by Bernhard M. Wiedemann. #1348 #1155 Fixes from Peter Cawley, Christian Clason, Lewis Russell. --- src/lj_bcread.c | 10 ++++++---- src/lj_bcwrite.c | 8 +++++--- src/lj_opt_fold.c | 6 ++++-- src/lj_opt_mem.c | 4 +++- src/lj_parse.c | 20 +++++--------------- src/lj_tab.c | 1 + 6 files changed, 24 insertions(+), 25 deletions(-) diff --git a/src/lj_bcread.c b/src/lj_bcread.c index ee7d7c18..55709522 100644 --- a/src/lj_bcread.c +++ b/src/lj_bcread.c @@ -179,7 +179,7 @@ static const void *bcread_varinfo(GCproto *pt) } /* Read a single constant key/value of a template table. */ -static void bcread_ktabk(LexState *ls, TValue *o) +static void bcread_ktabk(LexState *ls, TValue *o, GCtab *t) { MSize tp = bcread_uleb128(ls); if (tp >= BCDUMP_KTAB_STR) { @@ -191,6 +191,8 @@ static void bcread_ktabk(LexState *ls, TValue *o) } else if (tp == BCDUMP_KTAB_NUM) { o->u32.lo = bcread_uleb128(ls); o->u32.hi = bcread_uleb128(ls); + } else if (t && tp == BCDUMP_KTAB_NIL) { /* Restore nil value marker. */ + settabV(ls->L, o, t); } else { lj_assertLS(tp <= BCDUMP_KTAB_TRUE, "bad constant type %d", tp); setpriV(o, ~tp); @@ -207,15 +209,15 @@ static GCtab *bcread_ktab(LexState *ls) MSize i; TValue *o = tvref(t->array); for (i = 0; i < narray; i++, o++) - bcread_ktabk(ls, o); + bcread_ktabk(ls, o, NULL); } if (nhash) { /* Read hash entries. */ MSize i; for (i = 0; i < nhash; i++) { TValue key; - bcread_ktabk(ls, &key); + bcread_ktabk(ls, &key, NULL); lj_assertLS(!tvisnil(&key), "nil key"); - bcread_ktabk(ls, lj_tab_set(ls->L, t, &key)); + bcread_ktabk(ls, lj_tab_set(ls->L, t, &key), t); } } return t; diff --git a/src/lj_bcwrite.c b/src/lj_bcwrite.c index de200ef4..ec6f13c8 100644 --- a/src/lj_bcwrite.c +++ b/src/lj_bcwrite.c @@ -71,6 +71,8 @@ static void bcwrite_ktabk(BCWriteCtx *ctx, cTValue *o, int narrow) *p++ = BCDUMP_KTAB_NUM; p = lj_strfmt_wuleb128(p, o->u32.lo); p = lj_strfmt_wuleb128(p, o->u32.hi); + } else if (tvistab(o)) { /* Write the nil value marker as a nil. */ + *p++ = BCDUMP_KTAB_NIL; } else { lj_assertBCW(tvispri(o), "unhandled type %d", itype(o)); *p++ = BCDUMP_KTAB_NIL+~itype(o); @@ -133,7 +135,7 @@ static void bcwrite_ktab_sorted_hash(BCWriteCtx *ctx, Node *node, MSize nhash) TValue **heap = ctx->heap; MSize i = nhash; for (;; node--) { /* Build heap. */ - if (!tvisnil(&node->key)) { + if (!tvisnil(&node->val)) { bcwrite_ktabk_heap_insert(heap, --i, nhash, &node->key); if (i == 0) break; } @@ -163,7 +165,7 @@ static void bcwrite_ktab(BCWriteCtx *ctx, char *p, const GCtab *t) MSize i, hmask = t->hmask; Node *node = noderef(t->node); for (i = 0; i <= hmask; i++) - nhash += !tvisnil(&node[i].key); + nhash += !tvisnil(&node[i].val); } /* Write number of array slots and hash slots. */ p = lj_strfmt_wuleb128(p, narray); @@ -184,7 +186,7 @@ static void bcwrite_ktab(BCWriteCtx *ctx, char *p, const GCtab *t) } else { MSize i = nhash; for (;; node--) - if (!tvisnil(&node->key)) { + if (!tvisnil(&node->val)) { bcwrite_ktabk(ctx, &node->key, 0); bcwrite_ktabk(ctx, &node->val, 1); if (--i == 0) break; diff --git a/src/lj_opt_fold.c b/src/lj_opt_fold.c index 36aacebb..6fdf4566 100644 --- a/src/lj_opt_fold.c +++ b/src/lj_opt_fold.c @@ -2217,9 +2217,11 @@ LJFOLD(HREF TDUP KNUM) LJFOLDF(fwd_href_tdup) { TValue keyv; + cTValue *val; lj_ir_kvalue(J->L, &keyv, fright); - if (lj_tab_get(J->L, ir_ktab(IR(fleft->op1)), &keyv) == niltvg(J2G(J)) && - lj_opt_fwd_href_nokey(J)) + val = lj_tab_get(J->L, ir_ktab(IR(fleft->op1)), &keyv); + /* Check for either nil or the nil value marker in the template table. */ + if ((tvisnil(val) || tvistab(val)) && lj_opt_fwd_href_nokey(J)) return lj_ir_kkptr(J, niltvg(J2G(J))); return NEXTFOLD; } diff --git a/src/lj_opt_mem.c b/src/lj_opt_mem.c index 8cacfcfe..6f956b37 100644 --- a/src/lj_opt_mem.c +++ b/src/lj_opt_mem.c @@ -233,7 +233,9 @@ static TRef fwd_ahload(jit_State *J, IRRef xref) return lj_ir_knum_u64(J, tv->u64); else if (tvisint(tv)) return lj_ir_kint(J, intV(tv)); - else if (tvisgcv(tv)) + else if (tvistab(tv)) /* Template table nil value marker. */ + return TREF_NIL; + else if (tvisstr(tv)) return lj_ir_kstr(J, strV(tv)); } /* Othwerwise: don't intern as a constant. */ diff --git a/src/lj_parse.c b/src/lj_parse.c index 70097598..f4116380 100644 --- a/src/lj_parse.c +++ b/src/lj_parse.c @@ -1725,7 +1725,7 @@ static void expr_table(LexState *ls, ExpDesc *e) FuncState *fs = ls->fs; BCLine line = ls->linenumber; GCtab *t = NULL; - int vcall = 0, needarr = 0, fixt = 0; + int vcall = 0, needarr = 0; uint32_t narr = 1; /* First array index. */ uint32_t nhash = 0; /* Number of hash entries. */ BCReg freg = fs->freereg; @@ -1769,9 +1769,10 @@ static void expr_table(LexState *ls, ExpDesc *e) lj_gc_anybarriert(fs->L, t); if (expr_isk_nojump(&val)) { /* Add const key/value to template table. */ expr_kvalue(fs, v, &val); - } else { /* Otherwise create dummy string key (avoids lj_tab_newkey). */ - settabV(fs->L, v, t); /* Preserve key with table itself as value. */ - fixt = 1; /* Fix this later, after all resizes. */ + /* Mark nil value with table value itself to preserve the key. */ + if (key.k == VKSTR && tvisnil(v)) settabV(fs->L, v, t); + } else { /* Preserve the key for the following non-const store. */ + settabV(fs->L, v, t); goto nonconst; } } else { @@ -1813,17 +1814,6 @@ static void expr_table(LexState *ls, ExpDesc *e) } else { if (needarr && t->asize < narr) lj_tab_reasize(fs->L, t, narr-1); - if (fixt) { /* Fix value for dummy keys in template table. */ - Node *node = noderef(t->node); - uint32_t i, hmask = t->hmask; - for (i = 0; i <= hmask; i++) { - Node *n = &node[i]; - if (tvistab(&n->val)) { - lj_assertFS(tabV(&n->val) == t, "bad dummy key in template table"); - setnilV(&n->val); /* Turn value into nil. */ - } - } - } lj_gc_check(fs->L); } } diff --git a/src/lj_tab.c b/src/lj_tab.c index 2d080552..62e33611 100644 --- a/src/lj_tab.c +++ b/src/lj_tab.c @@ -194,6 +194,7 @@ GCtab * LJ_FASTCALL lj_tab_dup(lua_State *L, const GCtab *kt) Node *next = nextnode(kn); /* Don't use copyTV here, since it asserts on a copy of a dead key. */ n->val = kn->val; n->key = kn->key; + if (tvistab(&n->val)) setnilV(&n->val); /* Replace nil value marker. */ setmref(n->next, next == NULL? next : (Node *)((char *)next + d)); } } -- cgit v1.2.3-55-g6feb