--[=[
** lua.stx / llex.c
Tue Dec  2 10:45:48 EDT 1997
>> BUG: "lastline" was not reset on function entry, so debug information
>> started only in the 2nd line of a function.



=================================================================
--- Version 3.1 alpha

** lua.c
Thu Jan 15 14:34:58 EDT 1998
>> must include "stdlib.h" (for "exit()").

** lbuiltin.c / lobject.h
Thu Jan 15 14:34:58 EDT 1998
>> MAX_WORD may be bigger than MAX_INT
(by lhf)

** llex.c
Mon Jan 19 18:17:18 EDT 1998
>> wrong line number (+1) in error report when file starts with "#..."

** lstrlib.c
Tue Jan 27 15:27:49 EDT 1998
>> formats like "%020d" were considered too big (3 digits); moreover,
>> some sistems limit printf to at most 500 chars, so we can limit sizes
>> to 2 digits (99).

** lapi.c
Tue Jan 27 17:12:36 EDT 1998
>> "lua_getstring" may create a new string, so should check GC

** lstring.c / ltable.c
Wed Jan 28 14:48:12 EDT 1998
>> tables can become full of "empty" slots, and keep growing without limits.

** lstrlib.c
Mon Mar  9 15:26:09 EST 1998
>> gsub('a', '(b?)%1*' ...) loops (because the capture is empty).

** lstrlib.c
Mon May 18 19:20:00 EST 1998
>> arguments for "format" 'x', 'X', 'o' and 'u' must be unsigned int.



=================================================================
--- Version 3.1

** liolib.c / lauxlib.c
Mon Sep  7 15:57:02 EST 1998
>> function "luaL_argerror" prints wrong argument number (from a user's point
of view) when functions have upvalues.

** lstrlib.c
Tue Nov 10 17:29:36 EDT 1998
>> gsub/strfind do not check whether captures are properly finished.
(by roberto/tomas)

** lbuiltin.c
Fri Dec 18 11:22:55 EDT 1998
>> "tonumber" goes crazy with negative numbers in other bases (not 10),
because "strtol" returns long, not unsigned long.
(by Visual C++)

** lstrlib.c
Mon Jan  4 10:41:40 EDT 1999
>> "format" does not check size of format item (such as "%00000...00000d").

** lapi.c
Wed Feb  3 14:40:21 EDT 1999
>> getlocal cannot return the local itself, since lua_isstring and
lua_isnumber can modify it.

** lstrlib.c
Thu Feb  4 17:08:50 EDT 1999
>> format "%s" may break limit of "sprintf" on some machines.
(by Marcelo Sales)

** lzio.c
Thu Mar  4 11:49:37 EST 1999
>> file stream cannot call fread after EOF.
(by lhf)



=================================================================
--- Version 3.2 (beta)

** lstrlib.c
Fri Apr 30 11:10:20 EST 1999
>> '$' at end of pattern was matching regular '$', too.
(by anna; since 2.5)

** lbuiltin.c
Fri May 21 17:15:11 EST 1999
>> foreach, foreachi, foreachvar points to function in stack when stack
can be reallocated.
(by tomas; since 3.2 beta)

** lparser.c
Wed Jun 16 10:32:46 EST 1999
>> cannot assign to unlimited variables, because it causes overflow in
the number of returns of a function.
(since 3.1)



=================================================================
--- Version 3.2

** lmathlib.c
Wed Aug 18 11:28:38 EST 1999
>> random(0) and random(x,0) are wrong (0 is read as no argument!).
(by Dave Bollinger; since 3.1)

** lparser.c
Thu Sep  2 10:07:20 EST 1999
>> in the (old) expression << ls->fs->f->consts[checkname(ls)] >>, checkname
could realloc f->consts.
(by Supratik Champati; since 3.2 beta)

** lobject.c / lbuiltin.c
Wed Sep  8 17:41:54 EST 1999
>> tonumber'e1' and tonumber('  ', x), for x!=10, gave 0 instead of nil.
(since 3.1)

** lstrlib.c
Thu Nov 11 14:36:30 EDT 1999
>> `strfind' does not handle \0 in plain search.
(by Jon Kleiser; since 3.1)

** lparser.c
Wed Dec 29 16:05:43 EDT 1999
>> return gives wrong line in debug information
(by lhf; since 3.2 [at least])

** ldo.c
Thu Dec 30 16:39:33 EDT 1999
>> cannot reopen stdin (for binary mode)
(by lhf & roberto; since 3.1)

** lapi.c
Thu Mar  2 09:41:53 EST 2000
>> lua_settable should check stack space (it could call a T.M.)
(by lhf & celes; since 3.2; it was already fixed by fixed stack)

** lparser.c
Mon Apr  3 09:59:06 EST 2000
>> '%' should be in expfollow
(by Edgar Toernig; since 3.1; it was already fixed)

** lbuiltin.c
Mon Apr  3 10:05:05 EST 2000
>> tostring() without arguments gives seg. fault.
(by Edgar Toernig; since 3.0)



=================================================================
--- Version 4.0 alpha

Tested with full test suites (as locked in Mon Apr 24 14:23:11 EST 2000)
in the following platforms:
* Linux   - gcc, g++
* AIX     - gcc
* Solaris - gcc, cc
* IRIX	  - cc, cc-purify
* Windows - Visual C++ (.c e .cpp, warning level=4)


** lstrlib.c
Tue May  2 15:27:58 EST 2000
>> `strfind' gets wrong subject length when there is an offset
(by Jon Kleiser; since 4.0a)

** lparser.c
Fri May 12 15:11:12 EST 2000
>> first element in a list constructor is not adjusted to one value
>> (e.g. �a = {gsub('a','a','')}�)
(by Tomas; since 4.0a)

** lparser.c
Wed May 24 14:50:16 EST 2000
>> record-constructor starting with an upvalue name gets an error
>> (e.g. �local a; function f() x = {a=1} end�)
(by Edgar Toernig; since 3.1)

** lparser.c
Tue Aug 29 15:56:05 EST 2000
>> error message for `for' uses `while'
(since 4.0a; already corrected)

** lgc.c
Tue Aug 29 15:57:41 EST 2000
>> gc tag method for nil could call line hook
(by ry; since ?)



=================================================================
--- Version 4.0 Beta

** liolib.c
Fri Sep 22 15:12:37 EST 2000
>> `read("*w")' should return nil at EOF
(by roberto; since 4.0b)

** lvm.c
Mon Sep 25 11:47:48 EST 2000
>> lua_gettable does not get key from stack top
(by Philip Yi; since 4.0b)

** lgc.c
Mon Sep 25 11:50:48 EST 2000
>> GC may crash when checking locked C closures
(by Philip Yi; since 4.0b)

** lapi.c
Wed Sep 27 09:50:19 EST 2000
>> lua_tag should return LUA_NOTAG for non-valid indices
(by Paul Hankin; since 4.0b)

** llex.h / llex.c / lparser.c
Wed Sep 27 13:39:45 EST 2000
>> parser overwrites semantic information when looking ahead
>> (e.g. �a = {print'foo'}�)
(by Edgar Toernig; since 4.0b, deriving from previous bug)

** liolib.c
Thu Oct 26 10:50:46 EDT 2000
>> in function `read_file', realloc() doesn't free the buffer if it can't
>> allocate new memory
(by Mauro Vezzosi; since 4.0b)



=================================================================
--- Version 4.0

** lparser.c
Wed Nov 29 09:51:44 EDT 2000
>> parser does not accept a `;' after a `return'
(by lhf; since 4.0b)

** liolib.c
Fri Dec 22 15:30:42 EDT 2000
>> when `read' fails it must return nil (and not no value)
(by cassino; since at least 3.1)

** lstring.c/lapi.c
Thu Feb  1 11:55:45 EDT 2001
>> lua_pushuserdata(L, NULL) is buggy
(by Edgar Toernig; since 4.0)

** ldo.c
Fri Feb  2 14:06:40 EDT 2001
>> �while 1 dostring[[print('hello\n')]] end� never reclaims memory
(by Andrew Paton; since 4.0b)

** lbaselib.c
Tue Feb  6 11:57:13 EDT 2001
>> ESC (which starts precompiled code) in C is \33, not \27
(by Edgar Toernig and lhf; since 4.0b)

** lparser.c
Tue Jul 10 16:59:18 EST 2001
>> error message for `%a' gave wrong line number
(by Leonardo Constantino; since 4.0)

** lbaselib.c
Fri Dec 21 15:21:05 EDT 2001
>> seg. fault when rawget/rawset get extra arguments
(by Eric Mauger; since 4.0b)

** lvm.c
Wed Jun 19 13:28:20 EST 2002
>> line hook gets wrong `ar'
(by Daniel C. Sinclair; since 4.0.b)

** ldo.c
Wed Jun 19 13:31:49 EST 2002
>> `protectedparser' may run GC, and then collect `filename'
>> (in function `parse_file')
(by Alex Bilyk; since 4.0)




=================================================================
--- Version 5.0 alpha

** lgc.c
Fri Aug 30 13:49:14 EST 2002
>> GC metamethod stored in a weak metatable being collected together with
>> userdata may not be cleared properly
(by Roberto; since 5.0a)

** lapi.c
Thu Nov 21 11:00:00 EST 2002
>> ULONG_MAX>>10 may not fit into an int
(by Jeff Petkau; since 4.0)

** lparser.c
Fri Dec  6 17:06:40 UTC 2002
>> scope of generic for variables is not sound
(by Gavin Wraith; since 5.0a)




=================================================================
--- Version 5.0 beta
** lbaselib.c
Fri Dec 20 09:53:19 UTC 2002
>> `resume' was checking the wrong value for stack overflow
(by Maik Zimmermann; since 5.0b)

** ldo.c
Thu Jan 23 11:29:06 UTC 2003
>> error during garbage collection in luaD_protectedparser is not being
>> protected
(by Benoit Germain; since 5.0a)

** ldo.c (and others)
Fri Feb 28 14:20:33 EST 2003
>> GC metamethod calls could mess C/Lua stack syncronization
(by Roberto; since 5.0b)

** lzio.h/zlio.c
Thu Mar 20 11:40:12 EST 2003
>> zio mixes a 255 as first char in a buffer with EOZ
(by lhf; since 5.0a)



--]=]
-----------------------------------------------------------------
-- Lua 5.0 (final)

Bug{
what = [[lua_closethread exists only in the manual]],
report = [[by Nguyen Binh, 28/04/2003]],
patch = [[no patch; the manual is wrong]],
}


Bug{
what = [[attempt to resume a running coroutine crashes Lua]],
example = [[
function co_func (current_co)
   coroutine.resume(co)
end
co = coroutine.create(co_func)
coroutine.resume(co)
coroutine.resume(co)     --> seg. fault
]],
report = [[by Alex Bilyk, 09/05/2003]], 
patch = [[
* ldo.c:
325,326c325
<     if (nargs >= L->top - L->base)
<       luaG_runerror(L, "cannot resume dead coroutine");
---
>     lua_assert(nargs < L->top - L->base);
329c328,329
<   else if (ci->state & CI_YIELD) {  /* inside a yield? */
---
>   else {  /* inside a yield */
>     lua_assert(ci->state & CI_YIELD);
344,345d343
<   else
<     luaG_runerror(L, "cannot resume non-suspended coroutine");
351a350,358
> static int resume_error (lua_State *L, const char *msg) {
>   L->top = L->ci->base;
>   setsvalue2s(L->top, luaS_new(L, msg));
>   incr_top(L);
>   lua_unlock(L);
>   return LUA_ERRRUN;
> }
> 
> 
355a363,368
>   if (L->ci == L->base_ci) {
>     if (nargs >= L->top - L->base)
>       return resume_error(L, "cannot resume dead coroutine");
>   }
>   else if (!(L->ci->state & CI_YIELD))  /* not inside a yield? */
>     return resume_error(L, "cannot resume non-suspended coroutine");
]],
}


Bug{
what = [[file:close cannot be called without a file. (results in seg fault)]],
example = [[
> io.stdin.close()    -- correct call shold be io.stdin:close()
]],
report = [[by Tuomo Valkonen, 27/05/2003]], 
patch = [[
* liolib.c:
161c161
<   if (lua_isnone(L, 1)) {
---
>   if (lua_isnone(L, 1) && lua_type(L, lua_upvalueindex(1)) == LUA_TTABLE) {
]],   --}}
}


Bug{
what = [[C functions also may have stacks larger than current top]],
example = [[
Must recompile lua with a change in lua.c and with lua_assert defined:
* lua.c:
381a382
>   lua_checkstack(l, 1000);
]],
report = [[Alex Bilyk, 09/06/2003]],
patch = [[
* lgc.c:
247c247
<     if (!(ci->state & CI_C) && lim < ci->top)
---
>     if (lim < ci->top)
]],
}


Bug{
what = [[`pc' address is invalidated when a coroutine is suspended]],
example = [[
function g(x)
    coroutine.yield(x)
end

function f (i)
  debug.sethook(print, "l")
  for j=1,1000 do
    g(i+j)
  end
end

co = coroutine.wrap(f)
co(10)
pcall(co)
pcall(co)
]],
report = [[Nick Trout, 07/07/2003]],
patch = [[
* lvm.c:
402,403c402,403
<   L->ci->u.l.pc = &pc;
<   if (L->hookmask & LUA_MASKCALL)
---
>   if (L->hookmask & LUA_MASKCALL) {
>     L->ci->u.l.pc = &pc;
404a405
>   }
405a407
>   L->ci->u.l.pc = &pc;
676,678c678
<           lua_assert(ci->u.l.pc == &pc &&
<                      ttisfunction(ci->base - 1) &&
<                      (ci->state & CI_SAVEDPC));
---
>           lua_assert(ttisfunction(ci->base - 1) && (ci->state & CI_SAVEDPC));
]]
}


Bug{
what = [[userdata to be collected still counts into new GC threshold,
increasing memory consumption]],
report = [[Roberto, 25/07/2003]],
example = [[
a = newproxy(true)
getmetatable(a).__gc = function () end
for i=1,10000000 do
  newproxy(a)
  if math.mod(i, 10000) == 0 then print(gcinfo()) end
end
]],
patch = [[
* lgc.h:
18c18
< void luaC_separateudata (lua_State *L);
---
> size_t luaC_separateudata (lua_State *L);

* lgc.c:
113c113,114
< void luaC_separateudata (lua_State *L) {
---
> size_t luaC_separateudata (lua_State *L) {
>   size_t deadmem = 0;
127a129
>       deadmem += sizeudata(gcotou(curr)->uv.len);
136a139
>   return deadmem;
390c393
< static void checkSizes (lua_State *L) {
---
> static void checkSizes (lua_State *L, size_t deadmem) {
400c403
<   G(L)->GCthreshold = 2*G(L)->nblocks;  /* new threshold */
---
>   G(L)->GCthreshold = 2*G(L)->nblocks - deadmem;  /* new threshold */
454c457,458
< static void mark (lua_State *L) {
---
> static size_t mark (lua_State *L) {
>   size_t deadmem;
467c471
<   luaC_separateudata(L);  /* separate userdata to be preserved */
---
>   deadmem = luaC_separateudata(L);  /* separate userdata to be preserved */
475a480
>   return deadmem;
480c485
<   mark(L);
---
>   size_t deadmem = mark(L);
482c487
<   checkSizes(L);
---
>   checkSizes(L, deadmem);
]]
}

Bug{
what=[[IBM AS400 (OS400) has sizeof(void *)==16, and a `%p' may generate
up to 60 characters in a `printf'. That causes a buffer overflow in
`tostring'.]],

report = [[David Burgess, 25/08/2003]],

example = [[print{}; (in an AS400 machine)]],

patch = [[
* liolib.c:
178c178
<   char buff[32];
---
>   char buff[128];

* lbaselib.c:
327c327
<   char buff[64];
---
>   char buff[128];
]]
}


Bug{
what = [[syntax `local function' does not increment stack size]],

report = [[Rici Lake, 26/09/2003]],

example = [[
-- must run this with precompiled code
local a,b,c
local function d () end
]],

patch = [[
* lparser.c:
1143a1144
>   FuncState *fs = ls->fs;
1145c1146,1147
<   init_exp(&v, VLOCAL, ls->fs->freereg++);
---
>   init_exp(&v, VLOCAL, fs->freereg);
>   luaK_reserveregs(fs, 1);
1148c1150,1152
<   luaK_storevar(ls->fs, &v, &b);
---
>   luaK_storevar(fs, &v, &b);
>   /* debug information will only see the variable after this point! */
>   getlocvar(fs, fs->nactvar - 1).startpc = fs->pc;
]],

}


Bug{

what = [[count hook may be called without being set]],

report = [[Andreas Stenius, 06/10/2003]],

example = [[
set your hooks with

  lua_sethook(L, my_hook, LUA_MASKLINE | LUA_MASKRET, 1);

(It is weird to use a count > 0 without setting the count hook,
but it is not wrong.)
]],

patch = [[
* lvm.c:
69c69
<   if (mask > LUA_MASKLINE) {  /* instruction-hook set? */
---
>   if (mask & LUA_MASKCOUNT) {  /* instruction-hook set? */
]],

}


Bug{

what = [[`dofile' eats one return value when called without arguments]],

report = [[Frederico Abraham, 15/01/2004]],

example = [[
a,b = dofile()   --< here you enter `return 1,2,3 <eof>'
print(a,b)   --> 2   3   (should be 1 and 2)
]],

patch = [[
* lbaselib.c:
313a314
>   int n = lua_gettop(L);
317c318
<   return lua_gettop(L) - 1;
---
>   return lua_gettop(L) - n;
]],

}



-----------------------------------------------------------------
-- Lua 5.0.2

Bug{
what = [[string concatenation may cause arithmetic overflow, leading
to a buffer overflow]],

report = [[Rici Lake, 20/05/2004]],

example = [[
longs = string.rep("\0", 2^25)
function catter(i)
    return assert(loadstring(
      string.format("return function(a) return a%s end",
                     string.rep("..a", i-1))))()
end
rep129 = catter(129)
rep129(longs)
]],

patch = [[
* lvm.c:
@@ -321,15 +321,15 @@
         luaG_concaterror(L, top-2, top-1);
     } else if (tsvalue(top-1)->tsv.len > 0) {  /* if len=0, do nothing */
       /* at least two string values; get as many as possible */
-      lu_mem tl = cast(lu_mem, tsvalue(top-1)->tsv.len) +
-                  cast(lu_mem, tsvalue(top-2)->tsv.len);
+      size_t tl = tsvalue(top-1)->tsv.len;
       char *buffer;
       int i;
-      while (n < total && tostring(L, top-n-1)) {  /* collect total length */
-        tl += tsvalue(top-n-1)->tsv.len;
-        n++;
+      /* collect total length */
+      for (n = 1; n < total && tostring(L, top-n-1); n++) {
+        size_t l = tsvalue(top-n-1)->tsv.len;
+        if (l >= MAX_SIZET - tl) luaG_runerror(L, "string length overflow");
+        tl += l;
       }
-      if (tl > MAX_SIZET) luaG_runerror(L, "string size overflow");
       buffer = luaZ_openspace(L, &G(L)->buff, tl);
       tl = 0;
       for (i=n; i>0; i--) {  /* concat all strings */
]]
}


Bug{
what = [[lua_getupvalue and setupvalue do not check for index too small]],

report = [[Mike Pall, ?/2004]],

example = [[debug.getupvalue(function() end, 0)]],

patch = [[
* lapi.c
941c941
<     if (n > f->c.nupvalues) return NULL;
---
>     if (!(1 <= n && n <= f->c.nupvalues)) return NULL;
947c947
<     if (n > p->sizeupvalues) return NULL;
---
>     if (!(1 <= n && n <= p->sizeupvalues)) return NULL;
]]
}


Bug{
what = [[values holded in open upvalues of suspended threads may be
incorrectly collected]],

report = [[Spencer Schumann, 31/12/2004]],

example = [[
local thread_id = 0
local threads = {}

function fn(thread)
    thread_id = thread_id + 1
    threads[thread_id] = function()
                             thread = nil
                         end
    coroutine.yield()
end

while true do
    local thread = coroutine.create(fn)
    coroutine.resume(thread, thread)
end
]],

patch = [[
* lgc.c:
221,224c221,222
<       if (!u->marked) {
<         markobject(st, &u->value);
<         u->marked = 1;
<       }
---
>       markobject(st, u->v);
>       u->marked = 1;
]],
}


Bug{
what = [[rawset/rawget do not ignore extra arguments]],

report = [[Romulo Bahiense, 11/03/2005]],

example = [[
a = {}
rawset(a, 1, 2, 3)
print(a[1], a[2])    -- should be 2 and nil
]],

patch = [[
* lbaselib.c:
175a176
>   lua_settop(L, 2);
183a185
>   lua_settop(L, 3);
]],
}


Bug{
what = [[weak tables that survive one collection are never collected]],

report = [[Chromix, 02/01/2006]],

example = [[
a = {}
print(gcinfo())
for i = 1, 10000 do
  a[i] = setmetatable({}, {__mode = "v"})
end
collectgarbage()
a = nil
collectgarbage()
print(gcinfo())
]],

patch = [[
* lgc.c
@@ -366,7 +366,7 @@
   GCObject *curr;
   int count = 0;  /* number of collected items */
   while ((curr = *p) != NULL) {
-    if (curr->gch.marked > limit) {
+    if ((curr->gch.marked & ~(KEYWEAK | VALUEWEAK)) > limit) {
       unmark(curr);
       p = &curr->gch.next;
     }
]],

}


Bug{
what = [[Some "not not exp" may not result in boolean values]],
report = [[]],
since = [[4.0]],
example = [[
-- should print false, but prints nil
print(not not (nil and 4))
]],
patch = [[]],
}


Bug{
what = [[On some machines, closing a "piped file" (created with io.popen)
may crash Lua]],
report = [[]],
since = [[5.0]],
example = [[
-- only on some machines
  f = io.popen("ls")
  f:close()
]],
patch = [[]],
}



-----------------------------------------------------------------
-- Lua 5.1

Bug{
what = [[In 16-bit machines, expressions and/or with numeric constants as the
right operand may result in weird values]],

report = [[Andreas Stenius/Kein-Hong Man, 15/03/2006]],

example = [[
print(false or 0)   -- on 16-bit machines
]],

patch = [[
* lcode.c:
@@ -731,17 +731,15 @@
     case OPR_AND: {
       lua_assert(e1->t == NO_JUMP);  /* list must be closed */
       luaK_dischargevars(fs, e2);
-      luaK_concat(fs, &e1->f, e2->f);
-      e1->k = e2->k; e1->u.s.info = e2->u.s.info;
-      e1->u.s.aux = e2->u.s.aux; e1->t = e2->t;
+      luaK_concat(fs, &e2->f, e1->f);
+      *e1 = *e2;
       break;
     }
     case OPR_OR: {
       lua_assert(e1->f == NO_JUMP);  /* list must be closed */
       luaK_dischargevars(fs, e2);
-      luaK_concat(fs, &e1->t, e2->t);
-      e1->k = e2->k; e1->u.s.info = e2->u.s.info;
-      e1->u.s.aux = e2->u.s.aux; e1->f = e2->f;
+      luaK_concat(fs, &e2->t, e1->t);
+      *e1 = *e2;
       break;
     }
]],

}


Bug{
what = [[luaL_checkudata may produce wrong error message]],

report = [[Greg Falcon, 21/03/2006]],

example = [[
getmetatable(io.stdin).__gc()
  --> bad argument #1 to '__gc' (FILE* expected, got table)
]],

patch = [[
* lauxlib.c:
@@ -123,11 +123,17 @@

 LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) {
   void *p = lua_touserdata(L, ud);
-  lua_getfield(L, LUA_REGISTRYINDEX, tname);  /* get correct metatable */
-  if (p == NULL || !lua_getmetatable(L, ud) || !lua_rawequal(L, -1, -2))
-    luaL_typerror(L, ud, tname);
-  lua_pop(L, 2);  /* remove both metatables */
-  return p;
+  if (p != NULL) {  /* value is a userdata? */
+    if (lua_getmetatable(L, ud)) {  /* does it have a metatable? */
+      lua_getfield(L, LUA_REGISTRYINDEX, tname);  /* get correct metatable */
+      if (lua_rawequal(L, -1, -2)) {  /* does it have the correct mt? */
+        lua_pop(L, 2);  /* remove both metatables */
+        return p;
+      }
+    }
+  }
+  luaL_typerror(L, ud, tname);  /* else error */
+  return NULL;  /* to avoid warnings */
 }
]]

}


Bug{
what = [[
In Windows,
when Lua is used in an application that also uses DirectX,
it may present an erractic behavior.
THIS IS NOT A LUA BUG!
The problem is that DirectX violates an ABI that Lua depends on.]],

patch = [[
The simplest solution is to use DirectX with
the D3DCREATE_FPU_PRESERVE flag.

Otherwise, you can change the definition of lua_number2int,
in luaconf.h, to this one:
#define lua_number2int(i,d)   __asm fld d   __asm fistp i
]],

}


Bug{
what = [[option '%q' in string.format does not handle '\r' correctly.]],

example = [[
local s = "a string with \r and \n and \r\n and \n\r"
local c = string.format("return %q", s)
assert(assert(loadstring(c))() == s)
]],

patch = [[
* lstrlib.c:
@@ -703,6 +703,10 @@
         luaL_addchar(b, *s);
         break;
       }
+      case '\r': {
+        luaL_addlstring(b, "\\r", 2);
+        break;
+      }
       case '\0': {
         luaL_addlstring(b, "\\000", 4);
         break;
]],

}


Bug{
what = [[lua_dostring/lua_dofile should return any values returned
by the chunk]],

patch = [[
* lauxlib.h:
@@ -108,9 +108,11 @@

 #define luaL_typename(L,i)     lua_typename(L, lua_type(L,(i)))

-#define luaL_dofile(L, fn)     (luaL_loadfile(L, fn) || lua_pcall(L, 0, 0, 0))
+#define luaL_dofile(L, fn) \
+       (luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0))

-#define luaL_dostring(L, s)    (luaL_loadstring(L, s) || lua_pcall(L, 0, 0, 0))+#define luaL_dostring(L, s) \
+       (luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0))

 #define luaL_getmetatable(L,n) (lua_getfield(L, LUA_REGISTRYINDEX, (n)))
]],

}


Bug{

what = [[garbage collector does not compensate enough for finalizers]],

patch = [[
lgc.c:
@@ -322,4 +322,6 @@

-static void propagateall (global_State *g) {
-  while (g->gray) propagatemark(g);
+static size_t propagateall (global_State *g) {
+  size_t m = 0;
+  while (g->gray) m += propagatemark(g);
+  return m;
 }
@@ -542,3 +544,3 @@
   marktmu(g);  /* mark `preserved' userdata */
-  propagateall(g);  /* remark, to propagate `preserveness' */
+  udsize += propagateall(g);  /* remark, to propagate `preserveness' */
   cleartable(g->weak);  /* remove collected objects from weak tables */
@@ -592,2 +594,4 @@
         GCTM(L);
+        if (g->estimate > GCFINALIZECOST)
+          g->estimate -= GCFINALIZECOST;
]]
}


Bug{

what = [[debug hooks may get wrong when mixed with coroutines]],

report = [[by Ivko Stanilov, 03/06/2006]],

example = [[
co = coroutine.create(function (a,b)
   coroutine.yield(a, b)
   return b, "end"
end)

debug.sethook(co, function() end, "lcr")
coroutine.resume(co, 100, 2000)
coroutine.resume(co, 100, 2000)
]],

patch = [[
* ldo.c:
@@ -389,6 +389,7 @@
       return;
   }
   else {  /* resuming from previous yield */
+    L->status = 0;
     if (!f_isLua(ci)) {  /* `common' yield? */
       /* finish interrupted execution of `OP_CALL' */
       lua_assert(GET_OPCODE(*((ci-1)->savedpc - 1)) == OP_CALL ||
@@ -399,7 +400,6 @@
     else  /* yielded inside a hook: just continue its execution */
       L->base = L->ci->base;
   }
-  L->status = 0;
   luaV_execute(L, cast_int(L->ci - L->base_ci));
 }
]],

}



-----------------------------------------------------------------
-- Lua 5.1.1

Bug{
what = [[list constructors have wrong limit]],

report = [[by Norman Ramsey, June 2006]],

since = "Lua 5.1",

example = [[
a = {}
a[1] = "x={1"
for i = 2, 2^20 do
  a[i] = 1
end
a[#a + 1] = "}"
s = table.concat(a, ",")
assert(loadstring(s))()
print(#x)
]],

patch = [[
* lparser.c:
@@ -489,7 +489,7 @@

 static void listfield (LexState *ls, struct ConsControl *cc) {
   expr(ls, &cc->v);
-  luaY_checklimit(ls->fs, cc->na, MAXARG_Bx, "items in a constructor");
+  luaY_checklimit(ls->fs, cc->na, MAX_INT, "items in a constructor");
   cc->na++;
   cc->tostore++;
 }
]],

}


Bug{
what = [[wrong message error in some cases involving closures]],

report = [[Shmuel Zeigerman, on 07/2006]],

since = "Lua 5.1",

example = [[
local Var
local function main()
  NoSuchName (function() Var=0 end)
end
main()
--> lua5.1: temp:3: attempt to call upvalue 'Var' (a nil value)
]],

patch = [[
*ldebug.c:
@@ -435,14 +435,16 @@
         break;
       }
       case OP_CLOSURE: {
-        int nup;
+        int nup, j;
         check(b < pt->sizep);
         nup = pt->p[b]->nups;
         check(pc + nup < pt->sizecode);
-        for (; nup>0; nup--) {
-          OpCode op1 = GET_OPCODE(pt->code[pc+nup]);
+        for (j = 1; j <= nup; j++) {
+          OpCode op1 = GET_OPCODE(pt->code[pc + j]);
           check(op1 == OP_GETUPVAL || op1 == OP_MOVE);
         }
+        if (reg != NO_REG)  /* tracing? */
+          pc += nup;  /* do not 'execute' these pseudo-instructions */
         break;
       }
       case OP_VARARG: {
]],

}


Bug{
what = [[string.format("%") may read past the string]],
report = [[Roberto, on 09/2006]],
since = [[5.0 (at least)]],
example = [[print(string.format("%"))]],
patch = [[
*lstrlib.c:
@@ -723,7 +723,7 @@

 static const char *scanformat (lua_State *L, const char *strfrmt, char *form) {   const char *p = strfrmt;
-  while (strchr(FLAGS, *p)) p++;  /* skip flags */
+  while (*p != '\0' && strchr(FLAGS, *p) != NULL) p++;  /* skip flags */
   if ((size_t)(p - strfrmt) >= sizeof(FLAGS))
     luaL_error(L, "invalid format (repeated flags)");
   if (isdigit(uchar(*p))) p++;  /* skip width */
]],
}


Bug{
what = [[os.date throws an error when result is the empty string]],
report = [[]],
since = [[4.0]],
example = [[print(os.date(""))]],
patch = [[
*loslib.c:
@@ -148,7 +148,18 @@
   else {
-    char b[256];
-    if (strftime(b, sizeof(b), s, stm))
-      lua_pushstring(L, b);
-    else
-      return luaL_error(L, LUA_QL("date") " format too long");
+    char cc[3];
+    luaL_Buffer b;
+    cc[0] = '%'; cc[2] = '\0';
+    luaL_buffinit(L, &b);
+    for (; *s; s++) {
+      if (*s != '%' || *(s + 1) == '\0')  /* no conversion specifier? */
+        luaL_addchar(&b, *s);
+      else {
+        size_t reslen;
+        char buff[200];  /* should be big enough for any conversion result */
+        cc[1] = *(++s);
+        reslen = strftime(buff, sizeof(buff), cc, stm);
+        luaL_addlstring(&b, buff, reslen);
+      }
+    }
+    luaL_pushresult(&b);
   }
]],
}


Bug{
what = [[setfenv accepts invalid 1st argument]],
report = [[Doug Rogers, on 02/2007]],
since = [[5.0]],
example = [[setfenv(nil, {})   -- should throw an error]],
patch = [[
*lbaselib.c:
@@ -116,3 +116,3 @@

-static void getfunc (lua_State *L) {
+static void getfunc (lua_State *L, int opt) {
   if (lua_isfunction(L, 1)) lua_pushvalue(L, 1);
@@ -120,3 +120,3 @@
     lua_Debug ar;
-    int level = luaL_optint(L, 1, 1);
+    int level = opt ? luaL_optint(L, 1, 1) : luaL_checkint(L, 1);
     luaL_argcheck(L, level >= 0, 1, "level must be non-negative");
@@ -133,3 +133,3 @@
 static int luaB_getfenv (lua_State *L) {
-  getfunc(L);
+  getfunc(L, 1);
   if (lua_iscfunction(L, -1))  /* is a C function? */
@@ -144,3 +144,3 @@
   luaL_checktype(L, 2, LUA_TTABLE);
-  getfunc(L);
+  getfunc(L, 0);
   lua_pushvalue(L, 2);
]],
}


Bug{
what = [[wrong code for arithmetic expressions in some specific scenarios]],
report = [[Thierry Grellier, on 01/2007]],
since = [[5.1]],
example = [[
-- use a large number of names (almost 256)
v1=1; v2=1; v3=1; v4=1; v5=1; v6=1; v7=1; v8=1; v9=1;
v10=1; v11=1; v12=1; v13=1; v14=1; v15=1; v16=1; v17=1;
v18=1; v19=1; v20=1; v21=1; v22=1; v23=1; v24=1; v25=1;
v26=1; v27=1; v28=1; v29=1; v30=1; v31=1; v32=1; v33=1;
v34=1; v35=1; v36=1; v37=1; v38=1; v39=1; v40=1; v41=1;
v42=1; v43=1; v44=1; v45=1; v46=1; v47=1; v48=1; v49=1;
v50=1; v51=1; v52=1; v53=1; v54=1; v55=1; v56=1; v57=1;
v58=1; v59=1; v60=1; v61=1; v62=1; v63=1; v64=1; v65=1;
v66=1; v67=1; v68=1; v69=1; v70=1; v71=1; v72=1; v73=1;
v74=1; v75=1; v76=1; v77=1; v78=1; v79=1; v80=1; v81=1;
v82=1; v83=1; v84=1; v85=1; v86=1; v87=1; v88=1; v89=1;
v90=1; v91=1; v92=1; v93=1; v94=1; v95=1; v96=1; v97=1;
v98=1; v99=1; v100=1; v101=1; v102=1; v103=1; v104=1; v105=1;
v106=1; v107=1; v108=1; v109=1; v110=1; v111=1; v112=1; v113=1;
v114=1; v115=1; v116=1; v117=1; v118=1; v119=1; v120=1; v121=1;
v122=1; v123=1; v124=1; v125=1; v126=1; v127=1; v128=1; v129=1;
v130=1; v131=1; v132=1; v133=1; v134=1; v135=1; v136=1; v137=1;
v138=1; v139=1; v140=1; v141=1; v142=1; v143=1; v144=1; v145=1;
v146=1; v147=1; v148=1; v149=1; v150=1; v151=1; v152=1; v153=1;
v154=1; v155=1; v156=1; v157=1; v158=1; v159=1; v160=1; v161=1;
v162=1; v163=1; v164=1; v165=1; v166=1; v167=1; v168=1; v169=1;
v170=1; v171=1; v172=1; v173=1; v174=1; v175=1; v176=1; v177=1;
v178=1; v179=1; v180=1; v181=1; v182=1; v183=1; v184=1; v185=1;
v186=1; v187=1; v188=1; v189=1; v190=1; v191=1; v192=1; v193=1;
v194=1; v195=1; v196=1; v197=1; v198=1; v199=1; v200=1; v201=1;
v202=1; v203=1; v204=1; v205=1; v206=1; v207=1; v208=1; v209=1;
v210=1; v211=1; v212=1; v213=1; v214=1; v215=1; v216=1; v217=1;
v218=1; v219=1; v220=1; v221=1; v222=1; v223=1; v224=1; v225=1;
v226=1; v227=1; v228=1; v229=1; v230=1; v231=1; v232=1; v233=1;
v234=1; v235=1; v236=1; v237=1; v238=1; v239=1; v240=1; v241=1;
v242=1; v243=1; v244=1; v245=1; v246=1; v247=1; v248=1; v249=1;
v250=1;
v251={k1 = 1};
v252=1;
print(2 * v251.k1, v251.k1 * 2);   -- 2 2, OK
v253=1;
print(2 * v251.k1, v251.k1 * 2);   -- 1 2, ???
]],
patch = [[
*lcode.c:
@@ -657,10 +657,16 @@
   if (constfolding(op, e1, e2))
     return;
   else {
-    int o1 = luaK_exp2RK(fs, e1);
     int o2 = (op != OP_UNM && op != OP_LEN) ? luaK_exp2RK(fs, e2) : 0;
-    freeexp(fs, e2);
-    freeexp(fs, e1);
+    int o1 = luaK_exp2RK(fs, e1);
+    if (o1 > o2) {
+      freeexp(fs, e1);
+      freeexp(fs, e2);
+    }
+    else {
+      freeexp(fs, e2);
+      freeexp(fs, e1);
+    }
     e1->u.s.info = luaK_codeABC(fs, op, 0, o1, o2);
     e1->k = VRELOCABLE;
   }
@@ -718,10 +724,15 @@
       luaK_exp2nextreg(fs, v);  /* operand must be on the `stack' */
       break;
     }
-    default: {
+    case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV:
+    case OPR_MOD: case OPR_POW: {
       if (!isnumeral(v)) luaK_exp2RK(fs, v);
       break;
     }
+    default: {
+      luaK_exp2RK(fs, v);
+      break;
+    }
   }
 }
]],
}

Bug{
what = [[assignment of nil to parameter may be optimized away]],
report = [[Thomas Lauer, on 03/2007]],
since = [[5.1]],
example = [[
function f (a)
  a=nil
  return a
end

print(f("test"))
]],
patch = [[
*lcode.c:
@@ -35,16 +35,20 @@
 void luaK_nil (FuncState *fs, int from, int n) {
   Instruction *previous;
   if (fs->pc > fs->lasttarget) {  /* no jumps to current position? */
-    if (fs->pc == 0)  /* function start? */
-      return;  /* positions are already clean */
-    previous = &fs->f->code[fs->pc-1];
-    if (GET_OPCODE(*previous) == OP_LOADNIL) {
-      int pfrom = GETARG_A(*previous);
-      int pto = GETARG_B(*previous);
-      if (pfrom <= from && from <= pto+1) {  /* can connect both? */
-        if (from+n-1 > pto)
-          SETARG_B(*previous, from+n-1);
-        return;
+    if (fs->pc == 0) {  /* function start? */
+      if (from >= fs->nactvar)
+        return;  /* positions are already clean */
+    }
+    else {
+      previous = &fs->f->code[fs->pc-1];
+      if (GET_OPCODE(*previous) == OP_LOADNIL) {
+        int pfrom = GETARG_A(*previous);
+        int pto = GETARG_B(*previous);
+        if (pfrom <= from && from <= pto+1) {  /* can connect both? */
+          if (from+n-1 > pto)
+            SETARG_B(*previous, from+n-1);
+          return;
+        }
       }
     }
   }
]],
}


Bug{
what = [[__concat metamethod converts numbers to strings]],
report = [[Paul Winwood, on 12/2006]],
since = [[5.0]],
example = [[
a = {}
setmetatable(a, {__concat = function (a,b) print(type(a), type(b)) end})
a = 4 .. a
]],
patch = [[
*lvm.c:
@@ -281,10 +281,12 @@
   do {
     StkId top = L->base + last + 1;
     int n = 2;  /* number of elements handled in this pass (at least 2) */
-    if (!tostring(L, top-2) || !tostring(L, top-1)) {
+    if (!(ttisstring(top-2) || ttisnumber(top-2)) || !tostring(L, top-1)) {
       if (!call_binTM(L, top-2, top-1, top-2, TM_CONCAT))
         luaG_concaterror(L, top-2, top-1);
-    } else if (tsvalue(top-1)->len > 0) {  /* if len=0, do nothing */
+    } else if (tsvalue(top-1)->len == 0)  /* second op is empty? */
+      (void)tostring(L, top - 2);  /* result is first op (as string) */
+    else {
       /* at least two string values; get as many as possible */
       size_t tl = tsvalue(top-1)->len;
       char *buffer;
]],
}


Bug{
what = [[As a library, loadlib.c should not access Lua internals
(via lobject.h)]],
report = [[J�r�me Vuarand, on 03/2007]],
since = [[5.0 (at least)]],
example = [[the bug has no effect on external behavior]],
patch = [[remove the '#include "lobject.h" and use
'lua_pushfstring' instead of 'luaO_pushfstring']],
}



-----------------------------------------------------------------
-- Lua 5.1.2

Bug{
what = [[Lua may close standard files,
which then may be used by C]],
report = [[David Manura/Ross Berteig, on 04/2007]],
since = [[ ]],
example = [[
io.close(io.stderr)
-- in some systems, following attempts to write to 'stderr' may crash
a = a + 1
]],
patch = [[
]],
}

Bug{
what = [[code generated for "-nil", "-true", and "-false" is wrong]],
report = [[David Manura/Rici Lake, on 04/2007]],
since = [[5.1]],
example = [[print(-nil)]],
patch = [[
lcode.c:
@@ -699,7 +699,7 @@
   e2.t = e2.f = NO_JUMP; e2.k = VKNUM; e2.u.nval = 0;
   switch (op) {
     case OPR_MINUS: {
-      if (e->k == VK)
+      if (!isnumeral(e))
         luaK_exp2anyreg(fs, e);  /* cannot operate on non-numeric constants */
       codearith(fs, OP_UNM, e, &e2);
       break;
]],
}

Bug{
what = [[Count hook may be called without being set.]],
report = [[Mike Pall, on 05/2007]],
since = [[?]],
example = [[ ]],
patch = [[
lvm.c:
@@ -61,11 +61,9 @@
   lu_byte mask = L->hookmask;
   const Instruction *oldpc = L->savedpc;
   L->savedpc = pc;
-  if (mask > LUA_MASKLINE) {  /* instruction-hook set? */
-    if (L->hookcount == 0) {
-      resethookcount(L);
-      luaD_callhook(L, LUA_HOOKCOUNT, -1);
-    }
+  if ((mask & LUA_MASKCOUNT) && L->hookcount == 0) {
+    resethookcount(L);
+    luaD_callhook(L, LUA_HOOKCOUNT, -1);
   }
   if (mask & LUA_MASKLINE) {
     Proto *p = ci_func(L->ci)->l.p;
]],
}

Bug{
what = [[recursive coroutines may overflow C stack]],
report = [[ , on ]],
since = [[5.0]],
example = [[
a = function(a) coroutine.wrap(a)(a) end
a(a)
]],
patch = [[The 'nCcalls' counter should be shared by all threads.
(That is, it should be declared in the 'global_State' structure,
not in 'lua_State'.)
]],
}

Bug{
what = [[wrong error message in some concatenations]],
report = [[Alex Davies, on 05/2007]],
since = [[5.1.2]],
example = [[a = nil; a = (1)..a]],
patch = [[
ldebug.c:
@@ -563,8 +563,8 @@


 void luaG_concaterror (lua_State *L, StkId p1, StkId p2) {
-  if (ttisstring(p1)) p1 = p2;
-  lua_assert(!ttisstring(p1));
+  if (ttisstring(p1) || ttisnumber(p1)) p1 = p2;
+  lua_assert(!ttisstring(p1) && !ttisnumber(p1));
   luaG_typeerror(L, p1, "concatenate");
 }

]],
}

Bug{
what = [[Very small numbers all collide in the hash function.
(This creates only performance problems; the behavoir is correct.)]],
report = [[, on ]],
since = [[Lua 5.0]],
example = [[ ]],
patch = [[
ltable.c:
87,88c87,88
<   n += 1;  /* normalize number (avoid -0) */
<   lua_assert(sizeof(a) <= sizeof(n));
---
>   if (luai_numeq(n, 0))  /* avoid problems with -0 */
>     return gnode(t, 0);
]],
}

Bug{
what = [[Too many variables in an assignment may cause a
C stack overflow]],
report = [[Mike Pall, on 07/2007]],
since = [[5.0]],
example = [[
$ ulimit -s 1024       # Reduce C stack to 1MB for quicker results
$ lua -e 'local s = "a,"; for i=1,18 do s = s..s end print(loadstring("local a;"..s.."a=nil", ""))'
]],
patch = [[
lparser.c:
@@ -938,6 +938,8 @@
     primaryexp(ls, &nv.v);
     if (nv.v.k == VLOCAL)
       check_conflict(ls, lh, &nv.v);
+    luaY_checklimit(ls->fs, nvars, LUAI_MAXCCALLS - ls->L->nCcalls,
+                    "variable names");
     assignment(ls, &nv, nvars+1);
   }
   else {  /* assignment -> `=' explist1 */
]],
}

Bug{
what = [[An error in a module loaded through the '-l' option
shows no traceback]],
report = [[David Manura, on 08/2007]],
since = [[5.1]],
example = [[lua -ltemp    (assuming temp.lua has an error)]],
patch = [[
lua.c:
@@ -144,7 +144,7 @@
 static int dolibrary (lua_State *L, const char *name) {
   lua_getglobal(L, "require");
   lua_pushstring(L, name);
-  return report(L, lua_pcall(L, 1, 0, 0));
+  return report(L, docall(L, 1, 1));
 }
]],
}

Bug{
what = [['gsub' may go wild when wrongly called without its third
argument and with a large subject]],
report = [[Florian Berger, on 10/2007]],
since = [[5.1]],
example = [[
x = string.rep('a', 10000) .. string.rep('b', 10000)
print(#string.gsub(x, 'b'))
]],
patch = [[
lstrlib.c:
@@ -631,6 +631,2 @@
     }
-    default: {
-      luaL_argerror(L, 3, "string/function/table expected"); 
-      return;
-    }
   }
@@ -650,2 +646,3 @@
   const char *p = luaL_checkstring(L, 2);
+  int  tr = lua_type(L, 3);
   int max_s = luaL_optint(L, 4, srcl+1);
@@ -655,2 +652,5 @@
   luaL_Buffer b;
+  luaL_argcheck(L, tr == LUA_TNUMBER || tr == LUA_TSTRING ||
+                   tr == LUA_TFUNCTION || tr == LUA_TTABLE, 3,
+                      "string/function/table expected");
   luaL_buffinit(L, &b);
]],
}

Bug{
what = [[table.remove removes last element of a table when given
an out-of-bound index]],
report = [[Patrick Donnelly, on 11/2007]],
since = [[at least 5.0]],
example = [[
a = {1,2,3}
table.remove(a, 4)
print(a[3])   --> nil   (should be 3)
]],
patch = [[
ltablib.c:
@@ -118,7 +118,8 @@
 static int tremove (lua_State *L) {
   int e = aux_getn(L, 1);
   int pos = luaL_optint(L, 2, e);
-  if (e == 0) return 0;  /* table is `empty' */
+  if (!(1 <= pos && pos <= e))  /* position is outside bounds? */
+   return 0;  /* nothing to remove */
   luaL_setn(L, 1, e - 1);  /* t.n = n-1 */
   lua_rawgeti(L, 1, pos);  /* result = t[pos] */
   for ( ;pos<e; pos++) {
]],
}

Bug{
what = [[lua_setfenv may crash if called over an invalid object]],
report = [[Mike Pall, on 11/2007]],
since = [[5.1]],
example = [[
> debug.setfenv(3, {})
]],
patch = [[
lapi.c:
@@ -749,7 +749,7 @@
       res = 0;
       break;
   }
-  luaC_objbarrier(L, gcvalue(o), hvalue(L->top - 1));
+  if (res) luaC_objbarrier(L, gcvalue(o), hvalue(L->top - 1));
   L->top--;
   lua_unlock(L);
   return res;
]],
}

Bug{
what = [[stand-alone interpreter shows incorrect error message
when the "message" is a coroutine]],
report = [[Patrick Donnelly, on 17/12/2007]],
since = [[i ]],
example = [[> error(coroutine.create(function() end))]],
patch = [[
lua.c:
@@ -74,6 +74,8 @@
 
 
 static int traceback (lua_State *L) {
+  if (!lua_isstring(L, 1))  /* 'message' not a string? */
+    return 1;  /* keep it intact */
   lua_getfield(L, LUA_GLOBALSINDEX, "debug");
   if (!lua_istable(L, -1)) {
     lua_pop(L, 1);

]],
}

Bug{
what = [[debug.sethook/gethook may overflow the thread's stack]],
report = [[Ivko Stanilov, on 2008/01/04]],
since = [[5.1]],
example = [[
a = coroutine.create(function() yield() end) 
coroutine.resume(a)
debug.sethook(a)      -- may overflow the stack of 'a'
]],
patch = [[
ldblib.c:
@@ -268,12 +268,11 @@
     count = luaL_optint(L, arg+3, 0);
     func = hookf; mask = makemask(smask, count);
   }
-  gethooktable(L1);
-  lua_pushlightuserdata(L1, L1);
+  gethooktable(L);
+  lua_pushlightuserdata(L, L1);
   lua_pushvalue(L, arg+1);
-  lua_xmove(L, L1, 1);
-  lua_rawset(L1, -3);  /* set new hook */
-  lua_pop(L1, 1);  /* remove hook table */
+  lua_rawset(L, -3);  /* set new hook */
+  lua_pop(L, 1);  /* remove hook table */
   lua_sethook(L1, func, mask, count);  /* set hooks */
   return 0;
 }
@@ -288,11 +287,10 @@
   if (hook != NULL && hook != hookf)  /* external hook? */
     lua_pushliteral(L, "external hook");
   else {
-    gethooktable(L1);
-    lua_pushlightuserdata(L1, L1);
-    lua_rawget(L1, -2);   /* get hook */
-    lua_remove(L1, -2);  /* remove hook table */
-    lua_xmove(L1, L, 1);
+    gethooktable(L);
+    lua_pushlightuserdata(L, L1);
+    lua_rawget(L, -2);   /* get hook */
+    lua_remove(L, -2);  /* remove hook table */
   }
   lua_pushstring(L, unmakemask(mask, buff));
   lua_pushinteger(L, lua_gethookcount(L1));
]]
}



-----------------------------------------------------------------
-- Lua 5.1.3

Bug{
what = [[LUAI_MAXCSTACK must be smaller than -LUA_REGISTRYINDEX]],
report = [[Patrick Donnelly, on 2008/02/11]],
since = [[5.1.3]],
example = [[
j = 1e4
co = coroutine.create(function()
       t = {}
       for i = 1, j do t[i] = i end
       return unpack(t)
end)
print(coroutine.resume(co))
]],
patch = [[
luaconf.h:
443c443,444
< ** functions to consume unlimited stack space.
---
> ** functions to consume unlimited stack space. (must be smaller than
> ** -LUA_REGISTRYINDEX)
445,446c446
< #define LUAI_MCS_AUX  ((int)(INT_MAX / (4*sizeof(LUA_NUMBER))))
< #define LUAI_MAXCSTACK        (LUAI_MCS_AUX > SHRT_MAX ? SHRT_MAX : LUAI_MCS_AUX)
---
> #define LUAI_MAXCSTACK        8000
]],
}

Bug{
what = [[coroutine.resume pushes element without ensuring stack size]],
report = [[on 2008/02/11]],
since = [[5.0]],
example = [[(this bug cannot be detected without internal assertions)]],
patch = [[
lbaselib.c:
@@ -526,7 +526,7 @@
   status = lua_resume(co, narg);
   if (status == 0 || status == LUA_YIELD) {
     int nres = lua_gettop(co);
-    if (!lua_checkstack(L, nres))
+    if (!lua_checkstack(L, nres + 1))
       luaL_error(L, "too many results to resume");
     lua_xmove(co, L, nres);  /* move yielded values */
     return nres;
]],
}

Bug{
what = [[lua_checkstack may have arithmetic overflow for large 'size']],
report = [[Patrick Donnelly, on 2008/02/12]],
since = [[5.0]],
example = [[
print(unpack({1,2,3}, 0, 2^31-3))
]],
patch = [[
--- lapi.c      2008/01/03 15:20:39     2.55.1.3
+++ lapi.c      2008/02/14 16:05:21
@@ -93,15 +93,14 @@
 
 
 LUA_API int lua_checkstack (lua_State *L, int size) {
-  int res;
+  int res = 1;
   lua_lock(L);
-  if ((L->top - L->base + size) > LUAI_MAXCSTACK)
+  if (size > LUAI_MAXCSTACK || (L->top - L->base + size) > LUAI_MAXCSTACK)
     res = 0;  /* stack overflow */
-  else {
+  else if (size > 0) {
     luaD_checkstack(L, size);
     if (L->ci->top < L->top + size)
       L->ci->top = L->top + size;
-    res = 1;
   }
   lua_unlock(L);
   return res;
]],
}

Bug{
what = [[unpack with maximum indices may crash due to arithmetic overflow]],
report = [[Patrick Donnelly, on 2008/02/12]],
since = [[5.1]],
example = [[
print(unpack({1,2,3}, 2^31-1, 2^31-1))
]],
patch = [[
--- lbaselib.c  2008/02/11 16:24:24     1.191.1.5
+++ lbaselib.c  2008/02/14 16:10:25
@@ -344,10 +344,12 @@
   luaL_checktype(L, 1, LUA_TTABLE);
   i = luaL_optint(L, 2, 1);
   e = luaL_opt(L, luaL_checkint, 3, luaL_getn(L, 1));
+  if (i > e) return 0;  /* empty range */
   n = e - i + 1;  /* number of elements */
-  if (n <= 0) return 0;  /* empty range */
-  luaL_checkstack(L, n, "table too big to unpack");
-  for (; i<=e; i++)  /* push arg[i...e] */
+  if (n <= 0 || !lua_checkstack(L, n))  /* n <= 0 means arith. overflow */
+    return luaL_error(L, "too many results to unpack");
+  lua_rawgeti(L, 1, i);  /* push arg[i] (avoiding overflow problems) */
+  while (i++ < e)  /* push arg[i + 1...e] */
     lua_rawgeti(L, 1, i);
   return n;
 }
]],
}

Bug{
what = [[The validator for precompiled code has several flaws that
allow malicious binary code to crash the application]],
report = [[Peter Cawley, on 2008/03/24]],
since = [[5.0]],
example = [[
a = string.dump(function()return;end)
a = a:gsub(string.char(30,37,122,128), string.char(34,0,0), 1)
loadstring(a)()
]],
patch = [[
--- ldebug.c    2007/12/28 15:32:23     2.29.1.3
+++ ldebug.c    2008/04/04 15:15:40
@@ -275,12 +275,12 @@
 
 static int precheck (const Proto *pt) {
   check(pt->maxstacksize <= MAXSTACK);
-  lua_assert(pt->numparams+(pt->is_vararg & VARARG_HASARG) <= pt->maxstacksize);
-  lua_assert(!(pt->is_vararg & VARARG_NEEDSARG) ||
+  check(pt->numparams+(pt->is_vararg & VARARG_HASARG) <= pt->maxstacksize);
+  check(!(pt->is_vararg & VARARG_NEEDSARG) ||
               (pt->is_vararg & VARARG_HASARG));
   check(pt->sizeupvalues <= pt->nups);
   check(pt->sizelineinfo == pt->sizecode || pt->sizelineinfo == 0);
-  check(GET_OPCODE(pt->code[pt->sizecode-1]) == OP_RETURN);
+  check(pt->sizecode > 0 && GET_OPCODE(pt->code[pt->sizecode-1]) == OP_RETURN);
   return 1;
 }
 
@@ -363,7 +363,11 @@
     }
     switch (op) {
       case OP_LOADBOOL: {
-        check(c == 0 || pc+2 < pt->sizecode);  /* check its jump */
+        if (c == 1) {  /* does it jump? */
+          check(pc+2 < pt->sizecode);  /* check its jump */
+          check(GET_OPCODE(pt->code[pc+1]) != OP_SETLIST ||
+                GETARG_C(pt->code[pc+1]) != 0);
+        }
         break;
       }
       case OP_LOADNIL: {
@@ -428,7 +432,10 @@
       }
       case OP_SETLIST: {
         if (b > 0) checkreg(pt, a + b);
-        if (c == 0) pc++;
+        if (c == 0) {
+          pc++;
+          check(pc < pt->sizecode - 1);
+        }
         break;
       }
       case OP_CLOSURE: {
]],
}

Bug{
what = [[maliciously crafted precompiled code can blow the C stack]],
report = [[Greg Falcon, on 2008/03/25]],
since = [[5.0]],
example = [[
function crash(depth)
  local init = '\27\76\117\97\81\0\1\4\4\4\8\0\7\0\0\0\61\115\116' ..
               '\100\105\110\0\1\0\0\0\1\0\0\0\0\0\0\2\2\0\0\0\36' ..
               '\0\0\0\30\0\128\0\0\0\0\0\1\0\0\0\0\0\0\0\1\0\0\0' ..
               '\1\0\0\0\0\0\0\2'
  local mid = '\1\0\0\0\30\0\128\0\0\0\0\0\0\0\0\0\1\0\0\0\1\0\0\0\0'
  local fin = '\0\0\0\0\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0' ..
              '\0\0\97\0\1\0\0\0\1\0\0\0\0\0\0\0'
  local lch = '\2\0\0\0\36\0\0\0\30\0\128\0\0\0\0\0\1\0\0\0\0\0\0' ..
              '\0\1\0\0\0\1\0\0\0\0\0\0\2'
  local rch = '\0\0\0\0\0\0\0\2\0\0\0\1\0\0\0\1\0\0\0\1\0\0\0\2\0' ..
              '\0\0\97\0\1\0\0\0\1'
  for i=1,depth do lch,rch = lch..lch,rch..rch end
  loadstring(init .. lch .. mid .. rch .. fin)
end
for i=1,25 do print(i); crash(i) end
]],
patch = [[
--- lundump.c   2008/04/04 16:00:45     2.7.1.3
+++ lundump.c   2008/04/04 19:51:41     2.7.1.4
@@ -1,5 +1,5 @@
 /*
-** $Id: bugs,v 1.108 2010/05/14 15:34:57 roberto Exp roberto $
+** $Id: bugs,v 1.108 2010/05/14 15:34:57 roberto Exp roberto $
 ** load precompiled Lua chunks
 ** See Copyright Notice in lua.h
 */
@@ -161,7 +161,9 @@
 
 static Proto* LoadFunction(LoadState* S, TString* p)
 {
- Proto* f=luaF_newproto(S->L);
+ Proto* f;
+ if (++S->L->nCcalls > LUAI_MAXCCALLS) error(S,"code too deep");
+ f=luaF_newproto(S->L);
  setptvalue2s(S->L,S->L->top,f); incr_top(S->L);
  f->source=LoadString(S); if (f->source==NULL) f->source=p;
  f->linedefined=LoadInt(S);
@@ -175,6 +177,7 @@
  LoadDebug(S,f);
  IF (!luaG_checkcode(f), "bad code");
  S->L->top--;
+ S->L->nCcalls--;
  return f;
 }
]],
}

Bug{
what = [[code validator may reject (maliciously crafted) correct code]],
report = [[Greg Falcon, on 2008/03/26]],
since = [[5.0]],
example = [[
z={}
for i=1,27290 do z[i]='1,' end
z = 'if 1+1==2 then local a={' .. table.concat(z) .. '} end'
func = loadstring(z)
print(loadstring(string.dump(func)))
]],
patch = [[
--- ldebug.c    2008/04/04 15:30:05     2.29.1.4
+++ ldebug.c    2008/04/04 15:47:10
@@ -346,9 +346,18 @@
           int dest = pc+1+b;
           check(0 <= dest && dest < pt->sizecode);
           if (dest > 0) {
-            /* cannot jump to a setlist count */
-            Instruction d = pt->code[dest-1];
-            check(!(GET_OPCODE(d) == OP_SETLIST && GETARG_C(d) == 0));
+            int j;
+            /* check that it does not jump to a setlist count; this
+               is tricky, because the count from a previous setlist may
+               have the same value of an invalid setlist; so, we must
+               go all the way back to the first of them (if any) */
+            for (j = 0; j < dest; j++) {
+              Instruction d = pt->code[dest-1-j];
+              if (!(GET_OPCODE(d) == OP_SETLIST && GETARG_C(d) == 0)) break;
+            }
+            /* if 'j' is even, previous value is not a setlist (even if
+               it looks like one) */
+            check((j&1) == 0);
           }
         }
         break;
]],
}

Bug{
what = [[maliciously crafted precompiled code can inject invalid boolean
values into Lua code]],
report = [[Greg Falcon, on 2008/03/27]],
since = [[5.0]],
example = [[
maybe = string.dump(function() return ({[true]=true})[true] end)
maybe = maybe:gsub('\1\1','\1\2')
maybe = loadstring(maybe)()
assert(type(maybe) == "boolean" and maybe ~= true and maybe ~= false)
]],
patch = [[
--- lundump.c   2008/01/18 16:39:11     2.7.1.2
+++ lundump.c   2008/04/04 15:50:39
@@ -115,7 +115,7 @@
        setnilvalue(o);
        break;
    case LUA_TBOOLEAN:
-       setbvalue(o,LoadChar(S));
+       setbvalue(o,LoadChar(S)!=0);
        break;
    case LUA_TNUMBER:
        setnvalue(o,LoadNumber(S));
]],
}


Bug{
what = [['string.byte' gets confused with some out-of-range negative indices]],
report = [[Mike Pall, on 2008/06/03]],
since = [[5.1]],
example = [[
print(string.byte("abc", -5))   --> 97   98   99   (should print nothing)
]],
patch = [[
--- lstrlib.c	2007/12/28 15:32:23	1.132.1.3
+++ lstrlib.c	2008/07/05 11:53:42
@@ -35,7 +35,8 @@
 
 static ptrdiff_t posrelat (ptrdiff_t pos, size_t len) {
   /* relative string position: negative means back from end */
-  return (pos>=0) ? pos : (ptrdiff_t)len+pos+1;
+  if (pos < 0) pos += (ptrdiff_t)len + 1;
+  return (pos >= 0) ? pos : 0;
 }
 
 
]],
}


Bug{
what = [[user-requested GC step may loop forever]],
report = [[Makoto Hamanaka, on 2008/07/01]],
since = [[5.1]],
example = [[
collectgarbage("setpause", 100) -- small value
collectgarbage("setstepmul", 2000) -- large value
collectgarbage("step",0)
]],
patch = [[
--- lapi.c	2008/02/14 16:46:39	2.55.1.4
+++ lapi.c	2008/07/04 18:34:48
@@ -929,10 +929,13 @@
         g->GCthreshold = g->totalbytes - a;
       else
         g->GCthreshold = 0;
-      while (g->GCthreshold <= g->totalbytes)
+      while (g->GCthreshold <= g->totalbytes) {
         luaC_step(L);
-      if (g->gcstate == GCSpause)  /* end of cycle? */
-        res = 1;  /* signal it */
+        if (g->gcstate == GCSpause) {  /* end of cycle? */
+          res = 1;  /* signal it */
+          break;
+        }
+      }
       break;
     }
     case LUA_GCSETPAUSE: {
]],
}


Bug{
what = [['module' may change the environment of a C function]],
report = [[Peter Cawley, on 2008/07/16]],
since = [[5.1]],
example = [[
pcall(module, "xuxu")
assert(debug.getfenv(pcall) == xuxu)
]],
patch = [[
--- loadlib.c	2007/12/28 14:58:43	1.52.1.2
+++ loadlib.c	2008/08/05 19:39:00
@@ -506,8 +506,11 @@
 
 static void setfenv (lua_State *L) {
   lua_Debug ar;
-  lua_getstack(L, 1, &ar);
-  lua_getinfo(L, "f", &ar);
+  if (lua_getstack(L, 1, &ar) == 0 ||
+      lua_getinfo(L, "f", &ar) == 0 ||  /* get calling function */
+      lua_iscfunction(L, -1))
+    luaL_error(L, "function " LUA_QL("module")
+                  " not called from a Lua function");
   lua_pushvalue(L, -2);
   lua_setfenv(L, -2);
   lua_pop(L, 1);
]],
}


Bug{
what = [[internal macro 'svalue' is wrong]],
report = [[Martijn van Buul, on 2008/08/04]],
since = [[5.1]],
example = [[
/* in luaconf.h */
#define LUAI_USER_ALIGNMENT_T   union { char b[32]; }
]],
patch = [[
--- lobject.h	2007/12/27 13:02:25	2.20.1.1
+++ lobject.h	2008/08/05 19:40:48
@@ -210,3 +210,3 @@
 #define getstr(ts)	cast(const char *, (ts) + 1)
-#define svalue(o)       getstr(tsvalue(o))
+#define svalue(o)       getstr(rawtsvalue(o))
 
]],
}


-----------------------------------------------------------------
-- Lua 5.1.4

Bug{
what = [[malicious zero-length string in binary code may segfault Lua]],
report = [[Peter Cawley, on 2008/09/01]],
since = [[5.1]],
example = [[
loadstring(('').dump(function()X''end):gsub('\2%z%z%zX','\0\0\0'))()
]],
patch = [[
]],
}


Bug{
what = [[wrong code generation for some particular boolean expressions]],
report = [[Brian Kelley, on 2009/04/15]],
since = [[5.0]],
example = [[
print(((1 or false) and true) or false)   --> 1
-- should be 'true'
]],
patch = [[
--- lcode.c	2007/12/28 15:32:23	2.25.1.3
+++ lcode.c	2009/06/15 14:07:34
@@ -544,15 +544,18 @@
       pc = NO_JUMP;  /* always true; do nothing */
       break;
     }
-    case VFALSE: {
-      pc = luaK_jump(fs);  /* always jump */
-      break;
-    }
     case VJMP: {
       invertjump(fs, e);
       pc = e->u.s.info;
       break;
     }
+    case VFALSE: {
+      if (!hasjumps(e)) {
+        pc = luaK_jump(fs);  /* always jump */
+        break;
+      }
+      /* else go through */
+    }
     default: {
       pc = jumponcond(fs, e, 0);
       break;
@@ -572,14 +575,17 @@
       pc = NO_JUMP;  /* always false; do nothing */
       break;
     }
-    case VTRUE: {
-      pc = luaK_jump(fs);  /* always jump */
-      break;
-    }
     case VJMP: {
       pc = e->u.s.info;
       break;
     }
+    case VTRUE: {
+      if (!hasjumps(e)) {
+        pc = luaK_jump(fs);  /* always jump */
+        break;
+      }
+      /* else go through */
+    }
     default: {
       pc = jumponcond(fs, e, 1);
       break;
]],
}

Bug{
what = [['luaV_settable' may invalidate a reference to a table and try
to reuse it]],
report = [[Mark Feldman, on 2009/06/27]],
since = [[5.0]],
example = [[
grandparent = {}
grandparent.__newindex = function(s,_,_) print(s) end

parent = {}
parent.__newindex = parent
setmetatable(parent, grandparent)

child = setmetatable({}, parent)
child.foo = 10      --> (crash on some machines)
]],
patch = [[
--- lvm.c	2007/12/28 15:32:23	2.63.1.3
+++ lvm.c	2009/07/01 20:36:59
@@ -133,6 +133,7 @@
 
 void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val) {
   int loop;
+  TValue temp;
   for (loop = 0; loop < MAXTAGLOOP; loop++) {
     const TValue *tm;
     if (ttistable(t)) {  /* `t' is a table? */
@@ -152,7 +153,9 @@
       callTM(L, tm, t, key, val);
       return;
     }
-    t = tm;  /* else repeat with `tm' */ 
+    /* else repeat with `tm' */
+    setobj(L, &temp, tm);  /* avoid pointing inside table (may rehash) */
+    t = &temp;
   }
   luaG_runerror(L, "loop in settable");
 }
]],
}

Bug{
what = [[smart use of varargs may create functions that return too
many arguments and overflow the stack of C functions]],
report = [[Patrick Donnelly, on 2008/12/10]],
since = [[]],
example = [[
local function lunpack(i, ...)
  if i == 0 then return ...
  else
    return lunpack(i-1, 1, ...)
  end
end

Now, if C calls lunpack(n) with a huge n, it may end with
too many values in its stack and confuse its stack indices.
]],
patch = [[
]],
}

Bug{
what = [['debug.getfenv' does not check whether it has an argument]],
report = [[Patrick Donnelly, 2009/07/30]],
since = [[5.1]],
example = [[debug.getfenv()   -- should raise an error]],
patch = [[
--- ldblib.c    2008/01/21 13:11:21     1.104.1.3
+++ ldblib.c    2009/08/04 18:43:12
@@ -45,6 +45,7 @@
 
 
 static int db_getfenv (lua_State *L) {
+  luaL_checkany(L, 1);
   lua_getfenv(L, 1);
   return 1;
 }
]],
}

Bug{
what = [[GC may get stuck during a parser and avoids proper resizing of
the string table,
making its lists grow too much and degrading performance]],
report = [[Sean Conner, 2009/11/10]],
since = [[5.1]],
example = [[See http://lua-users.org/lists/lua-l/2009-11/msg00463.html]],
patch = [[
--- llex.c	2007/12/27 13:02:25	2.20.1.1
+++ llex.c	2009/11/23 14:49:40
@@ -118,8 +118,10 @@
   lua_State *L = ls->L;
   TString *ts = luaS_newlstr(L, str, l);
   TValue *o = luaH_setstr(L, ls->fs->h, ts);  /* entry for `str' */
-  if (ttisnil(o))
+  if (ttisnil(o)) {
     setbvalue(o, 1);  /* make sure `str' will not be collected */
+    luaC_checkGC(L);
+  }
   return ts;
 }
 
]]
}

Bug{
what = [['string.format' may get buffer as an argument when there are
missing arguments and format string is too long]],
report = [[Roberto I., 2010/04/12]],
since = [[5.0]],
example = [[
x = string.rep("x", 10000) .. "%d"
print(string.format(x))    -- gives wrong error message
]],
patch = [[
--- lstrlib.c	2008/07/11 17:27:21	1.132.1.4
+++ lstrlib.c	2010/05/14 15:12:53
@@ -754,6 +754,7 @@
 
 
 static int str_format (lua_State *L) {
+  int top = lua_gettop(L);
   int arg = 1;
   size_t sfl;
   const char *strfrmt = luaL_checklstring(L, arg, &sfl);
@@ -768,7 +769,8 @@
     else { /* format item */
       char form[MAX_FORMAT];  /* to store the format (`%...') */
       char buff[MAX_ITEM];  /* to store the formatted item */
-      arg++;
+      if (++arg > top)
+        luaL_argerror(L, arg, "no value");
       strfrmt = scanformat(L, strfrmt, form);
       switch (*strfrmt++) {
         case 'c': {
]]
}

Bug{
what = [['io.read(op, "*n")' may return garbage if second read fails]],
report = [[Roberto I., 2010/04/12]],
since = [[5.0]],
example = [[
print(io.read("*n", "*n"))   --<< enter "10   hi"
--> file (0x884420)	nil
]],
patch = [[
--- liolib.c	2008/01/18 17:47:43	2.73.1.3
+++ liolib.c	2010/05/14 15:29:29
@@ -276,7 +276,10 @@
     lua_pushnumber(L, d);
     return 1;
   }
-  else return 0;  /* read fails */
+  else {
+    lua_pushnil(L);  /* "result" to be removed */
+    return 0;  /* read fails */
+  }
 }
 
 
]]
}

Bug{
what = [[wrong code generation for some particular boolean expressions]],
report = [[Thierry Van Elsuwe, 2011/01/20]],
since = [[5.0]],
example = [[
print((('hi' or true) and true) or true)
--> hi     (should be true)
print(((nil and nil) or false) and true)
--> nil    (should be false)
]],
patch = [[
--- lcode.c	2009/06/15 14:12:25	2.25.1.4
+++ lcode.c	2011/01/31 14:44:25
@@ -549,13 +549,6 @@
       pc = e->u.s.info;
       break;
     }
-    case VFALSE: {
-      if (!hasjumps(e)) {
-        pc = luaK_jump(fs);  /* always jump */
-        break;
-      }
-      /* else go through */
-    }
     default: {
       pc = jumponcond(fs, e, 0);
       break;
@@ -579,13 +572,6 @@
       pc = e->u.s.info;
       break;
     }
-    case VTRUE: {
-      if (!hasjumps(e)) {
-        pc = luaK_jump(fs);  /* always jump */
-        break;
-      }
-      /* else go through */
-    }
     default: {
       pc = jumponcond(fs, e, 1);
       break;
]]
}