From 44ded6ac52347ed10925a99876dd9e9beaa6ed74 Mon Sep 17 00:00:00 2001 From: Thierry Fournier Date: Wed, 26 Feb 2025 10:24:52 +0100 Subject: [PATCH] fix: stack overflow in table.concat function The previous implementation of tableConcat was pushing all values and separators onto the Lua stack before concatenating them, which caused stack overflow with large tables. This fix changes the implementation to build the result string incrementally rather than pushing all values onto the stack first, preventing stack overflow with large tables. Example that would previously fail but now works correctly: ``` package main import "github.com/yuin/gopher-lua" func main() { var L *lua.LState var err error L = lua.NewState() defer L.Close() err = L.DoString(` local t = {} for i = 1, 10000 do t[i] = tostring(i) end local s = table.concat(t, ',') `) if err != nil { println(err.Error()) } } ``` --- tablelib.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tablelib.go b/tablelib.go index f3f46070..f175c696 100644 --- a/tablelib.go +++ b/tablelib.go @@ -2,6 +2,7 @@ package lua import ( "sort" + "strings" ) func OpenTable(L *LState) int { @@ -66,19 +67,18 @@ func tableConcat(L *LState) int { L.Push(emptyLString) return 1 } - //TODO should flushing? - retbottom := L.GetTop() + var sb strings.Builder for ; i <= j; i++ { v := tbl.RawGetInt(i) if !LVCanConvToString(v) { L.RaiseError("invalid value (%s) at index %d in table for concat", v.Type().String(), i) } - L.Push(v) + sb.WriteString(LVAsString(v)) if i != j { - L.Push(sep) + sb.WriteString(LVAsString(sep)) } } - L.Push(stringConcat(L, L.GetTop()-retbottom, L.reg.Top()-1)) + L.Push(LString(sb.String())) return 1 }