From 663a44a7fea7602b894160ec0608bca378c97d10 Mon Sep 17 00:00:00 2001
From: Benoit Germain <bnt.germain@gmail.com>
Date: Thu, 8 Jul 2021 14:55:04 +0200
Subject: fix function transfer with lua_dump for Lua 5.4 failing for functions
big enough to necessitate a buffer reallocation
---
src/tools.c | 40 ++++++++++++++++++++++++++--------------
1 file changed, 26 insertions(+), 14 deletions(-)
(limited to 'src/tools.c')
diff --git a/src/tools.c b/src/tools.c
index 18015c1..1436e8d 100644
--- a/src/tools.c
+++ b/src/tools.c
@@ -297,7 +297,8 @@ static char const* luaG_pushFQN( lua_State* L, int t, int last, size_t* length)
int i = 1;
luaL_Buffer b;
STACK_CHECK( L, 0);
- luaL_buffinit( L, &b);
+ // Lua 5.4 pushes &b as light userdata on the stack. be aware of it...
+ luaL_buffinit( L, &b); // ... {} ... &b?
for( ; i < last; ++ i)
{
lua_rawgeti( L, t, i);
@@ -309,7 +310,8 @@ static char const* luaG_pushFQN( lua_State* L, int t, int last, size_t* length)
lua_rawgeti( L, t, i);
luaL_addvalue( &b);
}
- luaL_pushresult( &b);
+ // &b is popped at that point (-> replaced by the result)
+ luaL_pushresult( &b); // ... {} ... "<result>"
STACK_END( L, 1);
return lua_tolstring( L, -1, length);
}
@@ -631,14 +633,6 @@ static lua_Integer get_mt_id( Universe* U, lua_State* L, int i)
return id;
}
-
-static int buf_writer( lua_State *L, const void* b, size_t n, void* B ) {
- (void)L;
- luaL_addlstring((luaL_Buffer*) B, (const char *)b, n);
- return 0;
-}
-
-
// function sentinel used to transfer native functions from/to keeper states
static int func_lookup_sentinel( lua_State* L)
{
@@ -1138,14 +1132,32 @@ static char const* vt_names[] =
};
#endif // USE_DEBUG_SPEW
+// Lua 5.4.3 style of dumping (see lstrlib.c)
+// we have to do it that way because we can't unbalance the stack between buffer operations
+// namely, this means we can't push a function on top of the stack *after* we initialize the buffer!
+// luckily, this also works with earlier Lua versions
+static int buf_writer( lua_State* L, void const* b, size_t size, void* ud)
+{
+ luaL_Buffer* B = (luaL_Buffer*) ud;
+ if( !B->L)
+ {
+ luaL_buffinit( L, B);
+ }
+ luaL_addlstring( B, (char const*) b, size);
+ return 0;
+}
+
static void copy_func( Universe* U, lua_State* L2, uint_t L2_cache_i, lua_State* L, uint_t i, LookupMode mode_, char const* upName_)
{
int n, needToPush;
- luaL_Buffer b;
+ luaL_Buffer B;
+ B.L = NULL;
+
ASSERT_L( L2_cache_i != 0); // ... {cache} ... p
STACK_GROW( L, 2);
STACK_CHECK( L, 0);
+
// 'lua_dump()' needs the function at top of stack
// if already on top of the stack, no need to push again
needToPush = (i != (uint_t)lua_gettop( L));
@@ -1154,18 +1166,18 @@ static void copy_func( Universe* U, lua_State* L2, uint_t L2_cache_i, lua_State*
lua_pushvalue( L, i); // ... f
}
- luaL_buffinit( L, &b);
//
// "value returned is the error code returned by the last call
// to the writer" (and we only return 0)
// not sure this could ever fail but for memory shortage reasons
- if( lua504_dump( L, buf_writer, &b, 0) != 0)
+ // last parameter is Lua 5.4-specific (no stripping)
+ if( lua504_dump( L, buf_writer, &B, 0) != 0)
{
luaL_error( L, "internal error: function dump failed.");
}
// pushes dumped string on 'L'
- luaL_pushresult( &b); // ... f b
+ luaL_pushresult( &B); // ... f b
// if not pushed, no need to pop
if( needToPush)
--
cgit v1.2.3-55-g6feb