[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: Lua C Functions
- From: William Ahern <william@...>
- Date: Mon, 11 Jul 2016 12:35:42 -0700
On Sat, Jul 09, 2016 at 12:29:25PM -0400, ThePhD wrote:
> Dear Alysson,
>
> Thank you for the clarification! I was unsure, since almost every
> example I had seen did this and it was not really specified anywhere
> exactly. My fear was that if the function called it might "leave" the
> arguments on the stack below where the results were, and eventually trash
> the VM with overflows. I'm glad this is not the case, and this will allow
> me to improve my code.
When you return from a function Lua will clean up the stack, capturing the
top N values on the stack according to the return value and discarding the
remainder, if any.
However, where you can run into trouble is repeatedly calling from the same
call frame context lua_call, lua_resume (whether or not from the same C
function invocation), and similar routines. You _can_ easily overflow the
stack if, for example, you don't the pop return values from prior calls.
This happened to me when I first began using Lua. I was issuing callbacks on
a coroutine and not managing the stack correctly. After too many callbacks
I'd overflow the stack. But it didn't always happen and it was a headache to
track down as I didn't have a strong grasp on Lua's stack semantics. It was
made more complex case because some callbacks would often yield to be
resumed by an event loop, so the stack management code was split across
multiple different C functions.
This is the exception to the rule. When you `return lua_yield(L, N)` from
your C routine, either directly or indirectly from another function
invocation, then Lua will preserve the stack and only pop the number of
values (N) you want to yield. This is by design because the stack is
normally where you keep your state for when the coroutine is resumed. That's
in contrast to, e.g., a simple closure used as an iterator, where you keep
your state in upvalues. (Neither strategy is mutually exclusive--a closure
invocation can be yielded and resumed like any other function, and also make
use of its upvalues before and after resumption.)
My quick fix back then was to do `lua_settop(L, 0)` before each callback.
Since then I prefer to add an assert that verifies my stack discipline code
is working correctly.