lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


I was wondering what guarantees of exception safety[1] are provided in Lua.

To help in testing, the below patch to Lua prints "[r]" upon each
allocation attempt and implements a function failalloc(n) that
schedules a memory allocation failure in the next n-th allocation.
This is used in the following example.  Here, g() has a memory
allocation failure when trying to grow that stack in the OP_CALL.
This causes the program to prints out that x is 2 despite the intended
invariant that x == 1.

  local function g()
    local x=1,2,3,4,5,6,7,8,9,10, 11,12,13,14,15,16,17,18,19,20,
            21,22,23,24,25,26,27,28
  end
  local x = 1
  local function test()
    x = x + 1
    g()
    x = x - 1
  end

  failalloc(1)
  local ok,msg = pcall(test)
  failalloc(0)

  print(x, ok, msg)

Although the Lua Reference Manual[2] defines the behavior of stack
growing for C functions, I don't think it does so for Lua functions.

[1] http://en.wikipedia.org/wiki/Exception_handling
[2] http://www.lua.org/manual/5.1/manual.html#3.2

diff -ur lua-5.1.4/src/lbaselib.c lua-mem/src/lbaselib.c
--- lua-5.1.4/src/lbaselib.c    2008-02-14 11:46:22.000000000 -0500
+++ lua-mem/src/lbaselib.c      2008-10-25 16:36:44.437500000 -0400
@@ -19,7 +19,12 @@
 #include "lauxlib.h"
 #include "lualib.h"

+extern int g_failalloc;

+static int luaB_failalloc(lua_State *L) {
+    g_failalloc = lua_tonumber(L, 1);
+    return 0;
+}


 /*
@@ -449,6 +454,7 @@
   {"collectgarbage", luaB_collectgarbage},
   {"dofile", luaB_dofile},
   {"error", luaB_error},
+  {"failalloc", luaB_failalloc},
   {"gcinfo", luaB_gcinfo},
   {"getfenv", luaB_getfenv},
   {"getmetatable", luaB_getmetatable},
diff -ur lua-5.1.4/src/lmem.c lua-mem/src/lmem.c
--- lua-5.1.4/src/lmem.c        2007-12-27 08:02:25.000000000 -0500
+++ lua-mem/src/lmem.c  2008-10-25 17:04:41.062500000 -0400
@@ -6,6 +6,7 @@


 #include <stddef.h>
+#include <stdio.h>

 #define lmem_c
 #define LUA_CORE
@@ -42,6 +43,7 @@

 #define MINSIZEARRAY   4

+int g_failalloc = 0;

 void *luaM_growaux_ (lua_State *L, void *block, int *size, size_t size_elems,
                      int limit, const char *errormsg) {
@@ -69,13 +71,14 @@
 }


-
 /*
 ** generic allocation routine.
 */
 void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) {
   global_State *g = G(L);
   lua_assert((osize == 0) == (block == NULL));
+  printf("[r]");
+  if (g_failalloc && --g_failalloc == 0) { luaD_throw(L, LUA_ERRMEM); }
   block = (*g->frealloc)(g->ud, block, osize, nsize);
   if (block == NULL && nsize > 0)
     luaD_throw(L, LUA_ERRMEM);