Search code examples
luacoronasdkellipsis

Lua Ellipsis Expression limited at 248


I am learning Lua for a university class in mobile application development and recently we covered the ellipsis operator (...) allowing a dynamic amount of arguments. Out of curiosity I decided to try and find out if there was a limit to how many arguments it could handle, as it turns out it is 248.

For example:

function pr(...)
    print(...)
end

pr(1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1)

I thought maybe it was OS dependent or related to stack size so I tested this on both Linux and Windows, on both 32bit and 64bit versions of each. The number of elements allowed stayed at 248. It would seem to be a hard-coded limit. If I try > 248 then I get the error I get is:

main.lua:30 function or expression too complex near <eof>

I cant imagine anyone needing more than 248 expressions in most cases but for those cases, is there a way around this? Also, why is it 248? That number doesn't seem special.


Solution

  • The stack frame limit

    The limitation you are coming into is not directly about the maximum number of function parameters allowed. Its about the maximum size of a Lua stack frame.

    The following example demonstrates this. Local variables in Lua also use up slots in a function's stack frame1 and by declaring 200 local variables we now only need 48 parameters in the print function to reach the limit:

    local x001,x002,x003,x004,x005,x006,x007,x008,x009,x010
    local x011,x012,x013,x014,x015,x016,x017,x018,x019,x020
    local x021,x022,x023,x024,x025,x026,x027,x028,x029,x030
    local x031,x032,x033,x034,x035,x036,x037,x038,x039,x040
    local x041,x042,x043,x044,x045,x046,x047,x048,x049,x050
    local x051,x052,x053,x054,x055,x056,x057,x058,x059,x060
    local x061,x062,x063,x064,x065,x066,x067,x068,x069,x070
    local x071,x072,x073,x074,x075,x076,x077,x078,x079,x080
    local x081,x082,x083,x084,x085,x086,x087,x088,x089,x090
    local x091,x092,x093,x094,x095,x096,x097,x098,x099,x100
    local x101,x102,x103,x104,x105,x106,x107,x108,x109,x110
    local x111,x112,x113,x114,x115,x116,x117,x118,x119,x120
    local x121,x122,x123,x124,x125,x126,x127,x128,x129,x130
    local x131,x132,x133,x134,x135,x136,x137,x138,x139,x140
    local x141,x142,x143,x144,x145,x146,x147,x148,x149,x150
    local x151,x152,x153,x154,x155,x156,x157,x158,x159,x160
    local x161,x162,x163,x164,x165,x166,x167,x168,x169,x170
    local x171,x172,x173,x174,x175,x176,x177,x178,x179,x180
    local x181,x182,x183,x184,x185,x186,x187,x188,x189,x190
    local x191,x192,x193,x194,x195,x196,x197,x198,x199,x200
    print(
    1,1,1,1,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1
    )
    

    This is also why the error message reads function or expression too complex instead of too many arguments passed to function or something along those lines.

    Why 248?

    The maximum size of the stack frame is actually 249. In llimits.h, Lua defines MAXSTACK to 250 and in lcode.c, the checkstack function only allows stackframes that are smaller than that..

     if (newstack >= MAXSTACK)
          luaX_syntaxerror(fs->ls, "function or expression too complex");
    

    This matches with the results we are getting in our experiments. The bytecode for a function call f(a1,a2,...,an) will require N+1 registers on the stack: one to point towards the function that we are calling and N to point towards the arguments to the function and 248+1 = 249 <= 250. (We would also need extra registers if using the return value of the function)

    According to Roberto Ierusalimschy, the reason for this relatively small limit of 250 is for performance reasons. Keeping the stack frame size under 256 means that only 8 bits are needed to store a stack frame offset and since each Lua bytecode contains 2 or 3 of these stack offsets as parameters, using less bytes to store the offsets is very important.

    How to pass more than 250 parameters to a function

    Coming back to your original question, it is actually possible to pass more than 256 parameters to a variadic function. If instead of using lots of comma-separated parameters you unpack a table or use some other function that returns multiple results then the limit we have to face is the size of the whole Lua stack instead of the size of a single stack frame. This limit (LUA_MAXSTACK) is user-configurable in luaconf.h and by default its 1000000.

    function rep(n)
      local t = {}
      for i = 1, n do
        t[i] = i
      end
      return t
    end
    
    function foo(...)
    end
    
    foo(table.unpack(rep(999986))) -- Pretty close to 1000000
    

    1: Remember that the whole body of a Lua script behaves as if it were inside a function so the Lua "toplevel" is still subject to those "stack frame" limitations.