[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: guarantees of exception safety in Lua
- From: Roberto Ierusalimschy <roberto@...>
- Date: Mon, 27 Oct 2008 10:18:11 -0200
> I was wondering what guarantees of exception safety[1] are provided in Lua.
We do extensive testing about the safety of Lua. When we compile Lua
in test mode, the allocation function (not luaM_realloc_) is redefined
so that it throws an error when the total memory reaches a limit. Then
we perform several tasks like this: we set this limit to memory_in_use
(so that any attempt to allocate more memory fails) and then go on
increasing it by 3 bytes each time, until we can complete the task. This
ensures that we have memory fails in practically every allocation point
in the code.
> 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)
This result is expected, is it not? "test" was interrupted by an
exception (memory allocation error, caught by pcall) after
incrementing x but before decrementing it. What value did you expect?
> 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.
The Lua stack is not visible for the users. Memory allocation errors
may occur almost anywhere inside a Lua script.
> 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);
This patch is not correct: "Lua assumes that the allocator never fails
when osize >= nsize." (http://www.lua.org/manual/5.1/manual.html#lua_Alloc)
-- Roberto