lua-users home
lua-l archive

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


 

I have a reproducible situation where luai_userstatefree is called on a thread that never had luai_userstatethread called on it. This looks like a bug in Lua, and it can cause heap corruption.

 

The problem occurs if the allocator returns NULL in a call to lua_newthread. If the second allocation inside lua_newthread fails, then the thread is kept around in a non-initialized state. When you shutdown with lua_close, then luai_userstatefree is called on this thread, even though luai_userstatethread was never called!

 

Below are the steps to reproduce the bug on a stock 5.1.4 source. All it does is open a state, attempt to create a thread, and then close the state:

 

luaconf.h:

 

#include "stdio.h"

#define luai_userstateopen(L)       ((void)L)

#define luai_userstateclose(L)            ((void)L)

#define luai_userstatethread(L,L1)      (fprintf(stderr,"luai_userstatethread\n"))

#define luai_userstatefree(L)       (fprintf(stderr,"luai_userstatefree\n"))

#define luai_userstateresume(L,n)   ((void)L)

#define luai_userstateyield(L,n)    ((void)L)

 

 

 

Lua.c:

 

#define lua_c

 

#include "lua.h"

 

static int trigger = 0;

 

// A simple override of l_alloc

static void *allocator (void *ud, void *ptr, size_t osize, size_t nsize) {

  (void)ud;

  (void)osize;

  if (nsize == 0) {

    free(ptr);

    return NULL;

  }

  else if (nsize>osize && (--trigger==0))

  {

        // Simulate an out-of-memory condition

        return 0;

  }

  else

    return realloc(ptr, nsize);

}

 

static int pmain (lua_State *L) {

 

  // setting trigger to 2 will cause the 2nd allocation to fail.

  // setting trigger to 0 will cause no memory error,

  // and you will see the correct behavior.

  trigger = 2;         

 

  lua_newthread(L);

 

  return 0;

}

 

int main (int argc, char **argv) {

  lua_State *L = lua_newstate(allocator, NULL);

  lua_cpcall(L, &pmain, 0);

  lua_close(L);

 

  fgetc(stdin);

  // At this point the console will display how many times

  // luai_userstatethread and luai_userstatefree where called

  return 0;

}

 

 

 

-Erik