Skip to content

Instantly share code, notes, and snippets.

@nicolasnoble
Created September 16, 2022 04:48
Show Gist options
  • Save nicolasnoble/b84ee61c6ca52104d3b9b706d7446df1 to your computer and use it in GitHub Desktop.
Save nicolasnoble/b84ee61c6ca52104d3b9b706d7446df1 to your computer and use it in GitHub Desktop.
Weird Lua garbage collector behavior.
#include <stdio.h>
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
static int outergc(lua_State *L) {
void * n = lua_touserdata(L, lua_upvalueindex(1));
void * o = lua_touserdata(L, -1);
printf("Outer gc called on %p with upvalue = %p\n", o, n);
return 0;
}
static int innergc(lua_State *L) {
void * n = lua_touserdata(L, -1);
printf("Inner gc called on %p\n", n);
return 0;
}
int main() {
lua_State *L = luaL_newstate();
luaL_openlibs(L);
lua_checkstack(L, 10);
lua_newtable(L);
// 1 = {}
lua_pushstring(L, "_proxy");
// 1 = {}, 2 = "_proxy"
void * o = lua_newuserdata(L, 1);
// 1 = {}, 2 = "_proxy", 3 = proxy
printf("Created outer object: %p\n", o);
lua_newtable(L);
// 1 = {}, 2 = "_proxy", 3 = proxy, 4 = {}
lua_pushstring(L, "__gc");
// 1 = {}, 2 = "_proxy", 3 = proxy, 4 = {}, 5 = "__gc"
void * n = lua_newuserdata(L, 1);
// 1 = {}, 2 = "_proxy", 3 = proxy, 4 = {}, 5 = "__gc", 6 = upvalue
printf("Created inner object: %p\n", n);
lua_newtable(L);
// 1 = {}, 2 = "_proxy", 3 = proxy, 4 = {}, 5 = "__gc", 6 = upvalue, 7 = {}
lua_pushstring(L, "__gc");
// 1 = {}, 2 = "_proxy", 3 = proxy, 4 = {}, 5 = "__gc", 6 = upvalue, 7 = {}, 8 = "__gc"
lua_pushcfunction(L, innergc);
// 1 = {}, 2 = "_proxy", 3 = proxy, 4 = {}, 5 = "__gc", 6 = upvalue, 7 = {}, 8 = "__gc", 9 = innergc
lua_settable(L, 7);
// 1 = {}, 2 = "_proxy", 3 = proxy, 4 = {}, 5 = "__gc", 6 = upvalue, 7 = {__gc = innergc}
lua_setmetatable(L, -1);
// 1 = {}, 2 = "_proxy", 3 = proxy, 4 = {}, 5 = "__gc", 6 = upvalue_with_gc
lua_pushcclosure(L, outergc, 1);
// 1 = {}, 2 = "_proxy", 3 = proxy, 4 = {}, 5 = "__gc", 6 = outergc_with_upvalue_with_gc
lua_settable(L, 4);
// 1 = {}, 2 = "_proxy", 3 = proxy, 4 = { __gc = outergc_with_upvalue_with_gc }
lua_setmetatable(L, 3);
// 1 = {}, 2 = "_proxy", 3 = proxy_with_gc
lua_settable(L, 1);
// 1 = { _proxy = proxy_with_gc }
lua_pop(L, 1);
// empty stack
lua_gc(L, LUA_GCCOLLECT, 0);
printf("Closing...\n");
lua_close(L);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment