Opened 6 years ago

Closed 6 years ago

#10935 closed enhancement (fixed)

lua-5.3.5

Reported by: Bruce Dubbs Owned by: Douglas R. Reno
Priority: normal Milestone: 8.3
Component: BOOK Version: SVN
Severity: normal Keywords:
Cc:

Description

New point version.

Change History (3)

comment:1 by Douglas R. Reno, 6 years ago

Owner: changed from blfs-book to Douglas R. Reno
Status: newassigned

comment:2 by Douglas R. Reno, 6 years ago

Wrong code generated for a 'goto' followed by a label inside an 'if'.
reported by 云风 on 13 Apr 2017. existed since 5.2.

Example:

-- should print 32323232..., but prints only '3'
if true then
  goto LBL
  ::loop::
  print(2)
  ::LBL::
  print(3)
  goto loop
end

Patch:

lparser.c:
@@ -1392,7 +1392,7 @@
     luaK_goiffalse(ls->fs, &v);  /* will jump to label if condition is true */
     enterblock(fs, &bl, 0);  /* must enter block before 'goto' */
     gotostat(ls, v.t);  /* handle goto/break */
-    skipnoopstat(ls);  /* skip other no-op statements */
+    while (testnext(ls, ';')) {}  /* skip semicolons */
     if (block_follow(ls, 0)) {  /* 'goto' is the entire block? */
       leaveblock(fs);
       return;  /* and that is it */

Lua crashes when building sequences with more than 2^30 elements.
reported by Viacheslav Usov on 11 May 2017.

Example:

-- crashes if machine has enough memory
local t = {}
for i = 1, 0x7fffffff do
  t[i] = i
end

Patch:

ltable.c:
@@ -223,7 +223,9 @@
   unsigned int na = 0;  /* number of elements to go to array part */
   unsigned int optimal = 0;  /* optimal size for array part */
   /* loop while keys can fill more than half of total size */
-  for (i = 0, twotoi = 1; *pna > twotoi / 2; i++, twotoi *= 2) {
+  for (i = 0, twotoi = 1;
+       twotoi > 0 && *pna > twotoi / 2;
+       i++, twotoi *= 2) {
     if (nums[i] > 0) {
       a += nums[i];
       if (a > twotoi/2) {  /* more than half elements present? */

Table length computation overflows for sequences larger than 2^31 elements.
reported by Viacheslav Usov on 12 May 2017.

Example:

-- on a machine with enough memory
local t = {}
for i = 1, 2147483681 do
  t[i] = i
end
print(#t)

Patch:

ltable.h:
@@ -56,3 +56,3 @@
 LUAI_FUNC int luaH_next (lua_State *L, Table *t, StkId key);
-LUAI_FUNC int luaH_getn (Table *t);
+LUAI_FUNC lua_Unsigned luaH_getn (Table *t);
 
ltable.c:
@@ -614,4 +614,4 @@
 
-static int unbound_search (Table *t, unsigned int j) {
-  unsigned int i = j;  /* i is zero or a present index */
+static lua_Unsigned unbound_search (Table *t, lua_Unsigned j) {
+  lua_Unsigned i = j;  /* i is zero or a present index */
   j++;
@@ -620,3 +620,3 @@
     i = j;
-    if (j > cast(unsigned int, MAX_INT)/2) {  /* overflow? */
+    if (j > l_castS2U(LUA_MAXINTEGER) / 2) {  /* overflow? */
       /* table was built with bad purposes: resort to linear search */
@@ -630,3 +630,3 @@
   while (j - i > 1) {
-    unsigned int m = (i+j)/2;
+    lua_Unsigned m = (i+j)/2;
     if (ttisnil(luaH_getint(t, m))) j = m;
@@ -642,3 +642,3 @@
 */
-int luaH_getn (Table *t) {
+lua_Unsigned luaH_getn (Table *t) {
   unsigned int j = t->sizearray;

Lua does not check GC when creating error messages.
reported by Viacheslav Usov on 06 Jul 2017. existed since 5.3.2.

Example:

function test()
  bob.joe.larry = 23
end

-- memory will grow steadly
for i = 1, math.huge do
  pcall(test)
  if i % 100000 == 0 then
    io.write(collectgarbage'count'*1024, "\n")
  end
end

Patch:

ldebug.c:
@@ -653,6 +653,7 @@
   CallInfo *ci = L->ci;
   const char *msg;
   va_list argp;
+  luaC_checkGC(L);  /* error message uses memory */
   va_start(argp, fmt);
   msg = luaO_pushvfstring(L, fmt, argp);  /* format message */
   va_end(argp);

Dead keys with nil values can stay in weak tables.
reported by 云风 Cloud Wu on 15 Aug 2017. existed since 5.2.

Example:

-- The following chunk, under a memory checker like valgrind, produces a memory access violation.

local a = setmetatable({}, {__mode = 'kv'})

a['ABCDEFGHIJKLMNOPQRSTUVWXYZ' .. 'abcdefghijklmnopqrstuvwxyz'] = {}
a[next(a)] = nil
collectgarbage()
print(a['BCDEFGHIJKLMNOPQRSTUVWXYZ' .. 'abcdefghijklmnopqrstuvwxyz'])

Patch:

lgc.c:
@@ -643,8 +643,9 @@
     for (n = gnode(h, 0); n < limit; n++) {
       if (!ttisnil(gval(n)) && (iscleared(g, gkey(n)))) {
         setnilvalue(gval(n));  /* remove value ... */
-        removeentry(n);  /* and remove entry from table */
       }
+      if (ttisnil(gval(n)))  /* is entry empty? */
+        removeentry(n);  /* remove entry from table */
     }
   }
 }

lua_pushcclosure should not call the garbage collector when n is zero.
reported by Andrew Gierth on 05 Dec 2017. existed since 5.3.3.

Patch:

lapi.c:
@@ -533,6 +533,7 @@
   lua_lock(L);
   if (n == 0) {
     setfvalue(L->top, fn);
+    api_incr_top(L);
   }
   else {
     CClosure *cl;
@@ -546,9 +547,9 @@
       /* does not need barrier because closure is white */
     }
     setclCvalue(L, L->top, cl);
+    api_incr_top(L);
+    luaC_checkGC(L);
   }
-  api_incr_top(L);
-  luaC_checkGC(L);
   lua_unlock(L);
 }

Memory-allocation error when resizing a table can leave it in an inconsistent state..
reported by Roberto on 08 Dec 2017. existed since 5.0.

Example:

local a = {x = 1, y = 1, z = 1}
a[1] = 10   -- goes to the hash part (which has 4 slots)
print(a[1])   --> 10

-- assume that the 2nd memory allocation from now fails
pcall(rawset, a, 2, 20)   -- forces a rehash

-- a[1] now exists both in the array part (because the array part
-- grew) and in the hash part (because the allocation of the hash
-- part failed, keeping it as it was).
-- This makes the following traversal goes forever...
for k,v in pairs(a) do print(k,v) end

Patch:

ltable.c:
@@ -332,17 +332,34 @@
 }
 
 
+typedef struct {
+  Table *t;
+  unsigned int nhsize;
+} AuxsetnodeT;
+
+
+static void auxsetnode (lua_State *L, void *ud) {
+  AuxsetnodeT *asn = cast(AuxsetnodeT *, ud);
+  setnodevector(L, asn->t, asn->nhsize);
+}
+
+
 void luaH_resize (lua_State *L, Table *t, unsigned int nasize,
                                           unsigned int nhsize) {
   unsigned int i;
   int j;
+  AuxsetnodeT asn;
   unsigned int oldasize = t->sizearray;
   int oldhsize = allocsizenode(t);
   Node *nold = t->node;  /* save old hash ... */
   if (nasize > oldasize)  /* array part must grow? */
     setarrayvector(L, t, nasize);
   /* create new hash part with appropriate size */
-  setnodevector(L, t, nhsize);
+  asn.t = t; asn.nhsize = nhsize;
+  if (luaD_rawrunprotected(L, auxsetnode, &asn) != LUA_OK) {  /* mem. error? */
+    setarrayvector(L, t, oldasize);  /* array back to its original size */
+    luaD_throw(L, LUA_ERRMEM);  /* rethrow memory error */
+  }
   if (nasize < oldasize) {  /* array part must shrink? */
     t->sizearray = nasize;
     /* re-insert elements from vanishing slice */


comment:3 by Douglas R. Reno, 6 years ago

Resolution: fixed
Status: assignedclosed

Fixed at r20278

Note: See TracTickets for help on using tickets.