From 7a92f3f99a26d9e51be40b744ed4fab0b50ecaa5 Mon Sep 17 00:00:00 2001 From: Roberto I Date: Fri, 10 Oct 2025 15:28:41 -0300 Subject: Change in dumping of NULL strings When dumping a string, adding 2 to its size may overflow a size_t for external strings, which may not have a header. (Adding 1 is Ok, because all strings end with a '\0' not included in their size.) The new method for saving NULL strings code them as a repeated string, using the reserved index 0. --- ldump.c | 22 +++++++++++++--------- lundump.c | 12 ++++++------ 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/ldump.c b/ldump.c index a75b20d2..57957889 100644 --- a/ldump.c +++ b/ldump.c @@ -132,27 +132,31 @@ static void dumpInteger (DumpState *D, lua_Integer x) { /* -** Dump a String. First dump its "size": size==0 means NULL; -** size==1 is followed by an index and means "reuse saved string with -** that index"; size>=2 is followed by the string contents with real -** size==size-2 and means that string, which will be saved with -** the next available index. +** Dump a String. First dump its "size": +** size==0 is followed by an index and means "reuse saved string with +** that index"; index==0 means NULL. +** size>=1 is followed by the string contents with real size==size-1 and +** means that string, which will be saved with the next available index. +** The real size does not include the ending '\0' (which is not dumped), +** so adding 1 to it cannot overflow a size_t. */ static void dumpString (DumpState *D, TString *ts) { - if (ts == NULL) - dumpSize(D, 0); + if (ts == NULL) { + dumpVarint(D, 0); /* will "reuse" NULL */ + dumpVarint(D, 0); /* special index for NULL */ + } else { TValue idx; int tag = luaH_getstr(D->h, ts, &idx); if (!tagisempty(tag)) { /* string already saved? */ - dumpVarint(D, 1); /* reuse a saved string */ + dumpVarint(D, 0); /* reuse a saved string */ dumpVarint(D, l_castS2U(ivalue(&idx))); /* index of saved string */ } else { /* must write and save the string */ TValue key, value; /* to save the string in the hash */ size_t size; const char *s = getlstr(ts, size); - dumpSize(D, size + 2); + dumpSize(D, size + 1); dumpVector(D, s, size + 1); /* include ending '\0' */ D->nstr++; /* one more saved string */ setsvalue(D->L, &key, ts); /* the string is the key */ diff --git a/lundump.c b/lundump.c index 74839af8..3b61cc8c 100644 --- a/lundump.c +++ b/lundump.c @@ -147,20 +147,20 @@ static void loadString (LoadState *S, Proto *p, TString **sl) { TString *ts; TValue sv; size_t size = loadSize(S); - if (size == 0) { /* no string? */ - lua_assert(*sl == NULL); /* must be prefilled */ - return; - } - else if (size == 1) { /* previously saved string? */ + if (size == 0) { /* previously saved string? */ lua_Unsigned idx = loadVarint(S, LUA_MAXUNSIGNED); /* get its index */ TValue stv; + if (idx == 0) { /* no string? */ + lua_assert(*sl == NULL); /* must be prefilled */ + return; + } if (novariant(luaH_getint(S->h, l_castU2S(idx), &stv)) != LUA_TSTRING) error(S, "invalid string index"); *sl = ts = tsvalue(&stv); /* get its value */ luaC_objbarrier(L, p, ts); return; /* do not save it again */ } - else if ((size -= 2) <= LUAI_MAXSHORTLEN) { /* short string? */ + else if ((size -= 1) <= LUAI_MAXSHORTLEN) { /* short string? */ char buff[LUAI_MAXSHORTLEN + 1]; /* extra space for '\0' */ loadVector(S, buff, size + 1); /* load string into buffer */ *sl = ts = luaS_newlstr(L, buff, size); /* create string */ -- cgit v1.2.3-55-g6feb