lua-users home
lua-l archive

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


I have recently noticed a serious problem in Lua 5.1.4's luaD_precall
function using Valgrind.

The bug is basically a corrupt (outdated) stack pointer to a function,
after the stack has been grown before calling a C function, though it
may affect other types of calls as well.

In this specific case, my Lua script was calling an arbitrary C
function. Here's the valgrind log and call stack:

==28698== Invalid read of size 4
==28698==    at 0x9ABD: luaD_precall (ldo.c:455)
==28698==    by 0x9D8B: luaD_call (ldo.c:518)
==28698==    by 0x1736A: callTMres (lvm.c:110)
==28698==    by 0x1773C: luaV_gettable (lvm.c:148)
==28698==    by 0x18D5E: luaV_execute (lvm.c:486)
==28698==    by 0x9E78: f_coresume (ldo.c:532)
==28698==    by 0x8A8C: luaD_rawrunprotected (ldo.c:141)
==28698==    by 0xA081: lua_resume (ldo.c:588)
==28698==    by 0x319BC: CVM::Update() (CVM.cpp:1358)
==28698==    by 0x370F9: CHypervisorWorker::Update() (CHypervisor.cpp:185)
==28698==    by 0x3734E: CHypervisorWorker::ThreadFunc(void*)
(CHypervisor.cpp:130)
==28698==    by 0x2BC054: _pthread_start (in /usr/lib/libSystem.B.dylib)

==28698==  Address 0x55cf24 is 356 bytes inside a block of size 540 free'd
==28698==    at 0xD8A87: realloc (vg_replace_malloc.c:525)
==28698==    by 0x1D415: l_alloc (lauxlib.c:715)
==28698==    by 0xF1C9: luaM_realloc_ (lmem.c:79)
==28698==    by 0x8F5B: luaD_reallocstack (ldo.c:256)
==28698==    by 0x90C1: luaD_growstack (ldo.c:275)
==28698==    by 0x99D2: luaD_precall (ldo.c:442)
==28698==    by 0x9D8B: luaD_call (ldo.c:518)
==28698==    by 0x1736A: callTMres (lvm.c:110)
==28698==    by 0x1773C: luaV_gettable (lvm.c:148)
==28698==    by 0x18D5E: luaV_execute (lvm.c:486)
==28698==    by 0x9E78: f_coresume (ldo.c:532)
==28698==    by 0x8A8C: luaD_rawrunprotected (ldo.c:141)

After some debugging, I found out that 0x55CF40 was the old L->top
pointer before growing/reallocation (and was updated to 0x582280).

Basically, what's happening is the following (luaD_precall):

...
else {  /* if is a C function, call it */
  CallInfo *ci;
  int n;
  luaD_checkstack(L, LUA_MINSTACK);  /* ensure minimum stack size */

During the call, apparently the stack is too small, so luaD_checkstack
calls luaD_growstack (as you can see in the valgrind log). That's all
fine, and luaD_precall continues:

...
    if (ttisfunction(func))

Well, luaD_growstack rellocates the stack, and updates (among others)
L->top.. however, the variable 'func' was passed into luaD_precall by
luaD_call and subsequently passed in by callTMres:

...
luaD_call(L, L->top - 3, 1, 0);

That second argument will form the variable 'func' in luaD_call and
luaD_precall. You can see that 'func' will point at the stack as it
was in callTMres BEFORE the stack was reallocated. As the stack is
reallocated later on in luaD_precall, 'func' is never updated and
leads to a corrupted pointer.

I appreciate any input on this potential bug. Will be looking for a
fix/patch today.