One key to reach real-time requirements is not to prevent Lua from dynamically allocating the stack (or any other object), but to provide an allocator function capable of providing memory in a fixed time. (Others are fine tuning garbage collection, preloading libraries and replacing/not using the io library after initializing, by the way).
This can be done using the official interface.
The allocator function is set using lua_newstate. Splitting allocation into a fixed size memory pool for frequently used small objects (basically everything but string), maybe <= 32 bytes (may depend on the Lua version), and another strategy for less frequently allocated larger objects seems to work. But the best strategy may depend on your system and should be verified experimentally.
In any case, you need to deal with Lua dynamically increasing and reducing not only the stack, but many other objects as well. Handle these allocations by a proper "special purpose" alloc/free implementation, instead of using the "general purpose" algorithms in a typical non-realtime standard C library.