5151#include < algorithm>
5252#include < cmath>
5353#include < climits>
54+ #include < cstdint>
5455#include < cstring>
5556
5657#include " lua.h"
@@ -109,8 +110,15 @@ class NodeArray {
109110 if (withLastfree) {
110111 // Large table: allocate Limbox + Node[]
111112 // LAYOUT: [Limbox header][Node array of size n]
113+ // Verify no overflow in size calculation
114+ if (n > (MAX_SIZET - sizeof (Limbox)) / sizeof (Node)) {
115+ luaG_runerror (L, " table size overflow" );
116+ }
112117 size_t total = sizeof (Limbox) + n * sizeof (Node);
113118 char * block = luaM_newblock (L, total);
119+ // Verify alignment assumptions (critical for type punning safety)
120+ lua_assert (reinterpret_cast <uintptr_t >(block) % alignof (Limbox) == 0 );
121+ lua_assert (reinterpret_cast <uintptr_t >(block + sizeof (Limbox)) % alignof (Node) == 0 );
114122 // Limbox is at the start, nodes follow
115123 // Safe per C++17 §8.2.10: reinterpret_cast to properly aligned type
116124 Limbox* limbox = reinterpret_cast <Limbox*>(block);
@@ -131,6 +139,8 @@ class NodeArray {
131139 // nodeStart points to element after Limbox, so (nodeStart - 1) conceptually
132140 // points to the Limbox (treating the block as Limbox array for arithmetic purposes)
133141 Limbox* limbox = reinterpret_cast <Limbox*>(nodeStart) - 1 ;
142+ // Verify we're not accessing uninitialized memory
143+ lua_assert (limbox->lastfree >= nodeStart);
134144 return limbox->lastfree ;
135145 }
136146};
@@ -704,6 +714,9 @@ static Value *resizearray (lua_State *L , Table *t,
704714 unsigned tomove = (oldasize < newasize) ? oldasize : newasize;
705715 size_t tomoveb = (oldasize < newasize) ? oldasizeb : newasizeb;
706716 lua_assert (tomoveb > 0 );
717+ lua_assert (tomove <= newasize); /* ensure destination bounds */
718+ lua_assert (tomove <= oldasize); /* ensure source bounds */
719+ lua_assert (tomoveb <= newasizeb); /* verify size calculation */
707720 memcpy (np - tomove, op - tomove, tomoveb);
708721 luaM_freemem (L, op - oldasize, oldasizeb); /* free old block */
709722 }
@@ -727,7 +740,9 @@ static void setnodevector (lua_State *L, Table *t, unsigned size) {
727740 }
728741 else {
729742 unsigned int lsize = luaO_ceillog2 (size);
730- if (lsize > MAXHBITS || (1u << lsize) > MAXHSIZE)
743+ if (lsize > MAXHBITS)
744+ luaG_runerror (L, " table overflow" );
745+ if ((1u << lsize) > MAXHSIZE)
731746 luaG_runerror (L, " table overflow" );
732747 size = Table::powerOfTwo (lsize);
733748 bool needsLastfree = (lsize >= LIMFORLAST);
@@ -1240,14 +1255,17 @@ static lua_Unsigned hash_search (lua_State *L, Table *t, unsigned asize) {
12401255 lua_Unsigned i = asize + 1 ; /* caller ensures t[i] is present */
12411256 unsigned rnd = G (L)->getSeed ();
12421257 int n = (asize > 0 ) ? luaO_ceillog2 (asize) : 0 ; /* width of 'asize' */
1258+ lua_assert (n >= 0 && n < 32 ); /* ensure shift is safe (avoid UB) */
12431259 unsigned mask = (1u << n) - 1 ; /* 11...111 with the width of 'asize' */
12441260 unsigned incr = (rnd & mask) + 1 ; /* first increment (at least 1) */
12451261 lua_Unsigned j = (incr <= l_castS2U (LUA_MAXINTEGER) - i) ? i + incr : i + 1 ;
12461262 rnd >>= n; /* used 'n' bits from 'rnd' */
12471263 while (!hashkeyisempty (t, j)) { /* repeat until an absent t[j] */
12481264 i = j; /* 'i' is a present index */
12491265 if (j <= l_castS2U (LUA_MAXINTEGER)/2 - 1 ) {
1266+ lua_Unsigned old_j = j;
12501267 j = j*2 + (rnd & 1 ); /* try again with 2j or 2j+1 */
1268+ lua_assert (j > old_j && j <= l_castS2U (LUA_MAXINTEGER)); /* no wrap */
12511269 rnd >>= 1 ;
12521270 }
12531271 else {
0 commit comments