Using MenuItem added with C crashes if Lua runtime is enabled

, ,

Hello!

I'm making project using C API and recently I needed access to system keyboard which unfortunately is available only in Lua.
I successfully initialized Lua runtime but I have problem with MenuItems.
I tried to narrow down the issue and prepared minimal example when it occurs.
Looks like if I add menu item using C API, e.g.:

void Test(void* data)
{

}
(...)
if (event == kEventInit)
{
    pd->system->addMenuItem("Test", Test, NULL);
}

And when I try to use it in simulator it crashes both on device and simulator.
Unfortunately error message is not helpful:

Update error: attempt to call a nil value
stack traceback:

I'm using Windows 10 with VS 2022.

I was able to bypass that problem by calling it on Lua side, i.e.:

function custom.addMenuItem(name, f)
	local menu = playdate.getSystemMenu()
	local menuItem, error = menu:addMenuItem(name, f)
end

And calling it from C:

	pdAPI->lua->pushString("Test");
	pdAPI->lua->pushFunction(Test);
	const char* err;
	if (!pdAPI->lua->callFunction("custom.addMenuItem", 2, &err))
	{
		pdAPI->system->logToConsole(err);
	}

Unfortunately this workaround doesn't work... at least when you try to call any other function inside Menu Item callback :confused:
e.g. when I change Test function to:

int GetInt()
{
	return 42;
}

void Test(void* data)
{
	int test= GetInt();
}

Then it crashes with:

Update error: failed expression: ((n) < (L->top - L->ci->func)) && "not enough elements in the stack" at C:\GitLab-Runner\ci-builds\HeHsk-Bm\0\playdate\PlayDate\Core\minilua\ldo.c:545
stack traceback:
	[C]: in ?

This looks like a bug that we fixed in 1.13.1. Can you update your SDK and see if it's working correctly there?

Hello Dave!

Unfortunately original problem wasn't fixed. On 1.13.1 SDK it still occurs, if you add MenuItem via C and project is also using Lua runtime then it crashes with the same error.

This update fixed workaround I came with tho. I mean adding MenuItem from within Lua with C function passed as argument works.

Thank you for checking! I'll see if I can figure out what's going on here, will let you know what I find. :slight_smile:

1 Like

Oh, sorry for misleading reply. Looks like on simple example it fixed the problem, but on my real "complex" project it didn't. I digged a bit more and looks like issue with Lua stack still persists.
Interesting part is that crash doesn't occur when I make call to pdAPI (tested on pdAPI->system->logToConsole(...)). If I don't then it crashes :confused:

Example code (main.c):

int GetInt()
{
	return 32;
}


void Test(void* data)
{
	int a = GetInt();
	//pdAPI->system->logToConsole("%d", a); => if I uncomment this line then it doesn't crash!
}

void AddTestMenu()
{
	pdAPI->lua->pushString("Test");
	pdAPI->lua->pushFunction(Test);
	const char* err;
	if (!pdAPI->lua->callFunction("custom.addMenuItem", 2, &err))
	{
		pdAPI->system->logToConsole(err);
	}
}

(main.lua):

function custom.addMenuItem(name, f)
	local menu = playdate.getSystemMenu()
	local menuItem, error = menu:addMenuItem(name, f)
end

aha! Found it. The problem is the menu callback should be a lua_CFunction, which returns an int telling Lua how many items it pushed on the stack. But Test() has a void return (and assumes the caller knows this) so it doesn't bother clearing out the return value register which is still 32 from the GetInt() call. Lua thinks you're saying you put 32 items on the stack so it's complaining that it can't find them. When you add the logToConsole call it apparently does clear that value, so no error. If you change Test() to return 0 everything should be fine.

Back to the attempt to call a nil value error: that's our bug. Our code assumes that if there's a Lua environment active then all menu callbacks are Lua functions. It looks for a Lua function for those menu items set with the C API and comes up with nil. We'll get that fix as soon as we can. Well done finding a workaround on this one! :slight_smile:

Great, thank you! I can wait for fix instead of going deeper into that workaround :smiley:

@dave @giezu I ran into this today. My usecase is trying to use the Panels library in a C api game. Panels being only available in lua.

Any update on this?

Thanks for the reminder! I finally got a chance to take a look at this, submitted a fix for the next release--hopefully we'll be able to get that it. Sorry it took a while!

Can complain about timing when you reply on my birthday. Thanks!