3

I want to pop / clean the Lua call stack while within a C function called from Lua. Is this possible?

Background:
I want my C library and its extension scripts to use the same test framework. (I am aware various unit testing tools exist for Lua. I don't care; I want one report) I'm wrapping CUnit in a thin layer of Lua. CUnit provides a choice of fatal and non-fatal test assertions. Fatal assertions cause an immediate longjmp out of the test and back into the framework runner. This seems like it would do bad things to the Lua VM if I did not clean the stack first.

The stack will probably look something like:

#0. C:   assert_wrapper_fcn(test, fatal)
#1. Lua: assert_fcn(bool)
#2. Lua: test_fcn()
#3. C:   runner(&test_fcn)

I want to clean up everything between #0 and #3. I know the method signatures of test_fcn() and assert_fcn(bool), but that's it.

gibbss
  • 2,013
  • 1
  • 15
  • 22
  • 2
    "*This seems like it would do bad things to the Lua VM if I did not clean the stack first.*" It will do *far worse* things than that. The call stack is the least of your concerns. Long-jumping out of the Lua interpreter (past Lua's own `setjmp`'s) is likely to break pretty much everything in Lua. – Nicol Bolas Nov 15 '12 at 21:19
  • Yes that is an issue too. I have very little idea how Lua's error handling system works. Really, I should have phrased the question in terms of resetting the state of the interpreter. – gibbss Nov 16 '12 at 17:47
  • 1
    You can't. Lua is not "`longjmp` over me" safe. Lua has no provisions for handling the case when an application decides to half-execute a function without its knowledge. If you want to keep your Lua interpreter in a sane state, then you need to play by Lua's rules. And that's true for pretty much any C library; you can't just randomly exit the middle of one and expect it to be content with that. – Nicol Bolas Nov 16 '12 at 18:10

3 Answers3

8

To empty the stack is really easy. Just use lua_settop with 0 as argument.

lua_settop(L, 0);
prapin
  • 6,395
  • 5
  • 26
  • 44
2

Not sure I'm understanding the question quite right... but to clear out Lua's stack:

int stackSize = lua_gettop(L);
lua_pop(L, stackSize);
Graham Perks
  • 23,007
  • 8
  • 61
  • 83
  • Is this sufficient if I re-enter Lua from C later? If I understand what you are saying, I can just nuke the stack from C to abandon the state then safely use lua_call() again. Does this clear the registry as well? – gibbss Nov 15 '12 at 21:00
  • Looks like @gibbss means the C call stack, not the Lua internal values stack. On the registry question: no, that does not clear the registry (which is separate from the stack, that's why it's referred through a _pseudo_-index), but the point of the registry is that it is a table that you can edit from C and that survives between Lua-C transitions. – Hisham H M Nov 16 '12 at 14:41
  • 1
    This is an accurate answer to the question asked, though apparently the approach I proposed has some serious problems. – gibbss Nov 16 '12 at 17:56
2

My suggestion is to use Lua's own assert system, and then trap that in your runner and then forward the error to your unit testing framework:

Launch your Lua code with lua_pcall.

From within your Lua code, trigger fatal errors with the standard assert command.

From where you launched your Lua code, check the result of lua_pcall and when you get != 0, trigger your CUnit fatal assertion failure.

This will avoid mixing any longjmp's between Lua and CUnit.

Hisham H M
  • 6,398
  • 1
  • 29
  • 30
  • This is not a bad idea -- and with a little work the error handler can still report Lua line numbers. – gibbss Nov 16 '12 at 17:51