Jump to content

LuaBind and exception handling


Josh
 Share

Recommended Posts

Has anyone here done exception handling with LuaBind? With BlitzMax I was able to use Try/Catch to display the script line a program crashes on, but I can't get this working in C++. Below is my Lua interpreter code. This is a class that corresponds to a single Lua state, and has functions that are easier to call: The Invoke() function at the bottom is where most of the action is.

#include "../le3.h"

namespace le3
{	
Interpreter::Interpreter() : L(NULL)
{
	L=lua_open();
	luaopen_debug(L);
	luaL_openlibs(L);
	luabind::open(L);

	//Bind classes
	bind_LE3_Vec2(L);
	bind_LE3_Vec3(L);
	bind_LE3_Vec4(L);
	bind_LE3_AABB(L);
	bind_LE3_Plane(L);
	bind_LE3_Quat(L);
	bind_LE3_Mat3(L);
	bind_LE3_Mat4(L);
	bind_LE3_Transform(L);
	bind_LE3_Entity(L);
	bind_LE3_Pivot(L);

	//Bind global functions
	using namespace luabind;
	module(L)
	[
		//Global functions
		def("Print", (void(*)(const std::string&)) &le3::Print),
		def("LoadModel", (Model*(*)(const std::string&, const int& flags)) &le3::LoadModel),
		def("GenerateError", &GenerateError),

		//Model
		class_<Model,Entity>("Model")
	];
}

Interpreter::~Interpreter()
{
	if (L!=NULL)
	{
		lua_close(L);
		L = NULL;
	}
}

int Interpreter::GetStackSize()
{
	return lua_gettop(L);
}

void Interpreter::SetStackSize(const int& size)
{
	int currentsize = GetStackSize();
	if (size<currentsize) lua_pop(L,currentsize-size);
}

void Interpreter::HandleError()
{
	Print("Error: "+std::string(lua_tostring(L,-1)));
}

void Interpreter::HandleException()
{
	std::string err = "Lua debugger not found.";
	lua_getglobal(L,"debug");
	if (lua_istable(L,-1)!=0)
	{					
		lua_getfield(L,-1,"traceback");
		if (lua_isfunction(L,-1)!=0)
		{
			if (lua_pcall(L,0,1,0)==0)
			{
				if (lua_isstring(L,-1)!=0)
				{
					err = lua_tostring(L,-1);
				}
			}
		}
	}
	Print("Error: "+err);
}

bool Interpreter::ExecuteString(std::string& source)
{
	bool result = false;
	int errorhandler = 0;
	int size = GetStackSize();

	if (luaL_loadbuffer(L,source.c_str(),source.length(),"")==0)
	{
		result = Invoke(0,0);
	}
	else
	{
		HandleError();
	}
	SetStackSize(size);
	return result;
}

bool Interpreter::ExecuteFile(const std::string& path)
{
	bool result = false;
	int errorhandler = 0;
	int size = GetStackSize();
	Bank* bank = LoadBank(path);		

	if (bank==NULL) return false;
	if (luaL_loadbuffer(L,bank->buf,bank->GetSize(),path.c_str())==0)
	{
		result = Invoke(0,0);
	}
	else
	{
		HandleError();
	}
	delete bank;
	SetStackSize(size);
	return result;
}

bool Interpreter::Invoke(const int& in, const int& out)
{
	try
	{
		if (lua_pcall(L,in,out,0)==0)
		{
			return true;
		}
		else
		{
			HandleError();
		}
	}
	catch(luabind::error& e)
	{
		HandleException();
	}
}
}

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

If I throw an exception in the try block, it gets caught. If the Lua script calls a C++ function that throws an exception, no exception is caught by the catch statement.

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

I created a project that runs a Lua script and creates an error:

 

 

In "le3.cpp" the GenerateError() function will try to call a function with a null pointer:

void GenerateError()
{
Interpreter* i = NULL;
i->GetStackSize();	
}

The GenerateError() function is exposed via LuaBind and is called by "test.lua". I want to be able to tell what line the script was executing when the program crashes, and to be able to get all the variables and call stack within Lua for debugging purposes.

 

The Lua script is run in the Interpreter::ExecuteFile() function, which calls Interpreter::Invoke():

	bool Interpreter::ExecuteFile(const std::string& path)
{
	bool result = false;
	int errorhandler = 0;
	int size = GetStackSize();

	if (luaL_loadfile(L,path.c_str())==0)
	{
		result = Invoke(0,0);
	}
	else
	{
		HandleError();
	}
	SetStackSize(size);
	return result;
}

bool Interpreter::Invoke(const int& in, const int& out)
{
	try
	{
		if (lua_pcall(L,in,out,0)==0)
		{
			return true;
		}
		else
		{
			HandleError();
		}
	}
	//catch (luabind::error& e)
	catch(...)
	{
		HandleException();
	}
	return false;
}

If anyone has experience doing this with C++ any advice is appreciated. I had try/catch working with Lua and BlitzMax, but this is a bit different.

 

I'm going to use the debug info to construct a nice debug interface in the script editor, so you can click around and see everything that's going on in the script program.

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

I found if I call debug.traceback in the C++ function before the error is caused, I can show the call stack of the Lua program. However, Luabind is "eating" my exceptions so they never come back to the main program. The code on Rasterbar's site for MSVC has no effect.

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

You can't catch OS and hardware errors with standard C++ catches, but when you add a signal handler, you can catch all C++/OS/hardware errors:

 

http://www.ibm.com/developerworks/linux/library/l-cppexcep.html

 

http://stackoverflow.com/questions/457577/catching-access-violation-exceptions

Ryzen 9 RX 6800M ■ 16GB XF8 Windows 11 ■
Ultra ■ LE 2.53DWS 5.6  Reaper ■ C/C++ C# ■ Fortran 2008 ■ Story ■
■ Homepage: https://canardia.com ■

Link to comment
Share on other sites

try

{

MakeLE2IntoLE3();

}

 

catch(luabind::Error &YourException)

{

lua_State* L = e.state();

}

 

Check your luabind errors with: lua_error()

 

Although this isn't the only exception luabind will throw, its the most common one ;P

AMD Phenom II X4 B55 3.20 GHz - 8.00 GB Patriot Gamer Series RAM - AMD Radeon HD 6800 Series 1 GB GDDR5 - Windows 7 Professional 64 Bit

Link to comment
Share on other sites

That doesn't do anything. No matter what, if I throw an exception in a C++ function Lua calls, it just prints the exception in the Lua error log, and doesn't actually throw anything for my catch statement to catch. I added that thing rasterbar said to in the main function and it has no effect.

	#ifdef _MSC_VER
_set_se_translator(straight_to_debugger);
#endif

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

I created a new C++ function:

	void RuntimeError(const std::string& error)
{
	throw std::exception(error.c_str());
}

Here is the Lua script that calls it:

print("Creating an error...")

RuntimeError("An error has occurred!")

Here is the code that runs the script:

	bool Interpreter::Invoke(const int& in, const int& out)
{
	try
	{
		if (lua_pcall(L,in,out,0)==0)
		{
			return true;
		}
		else
		{
			//If you throw an exception, it gets displayed here, which isn't what we want:
			HandleError();
		}
	}
	//Exceptions should be getting caught here:
	catch(luabind::error& e)
	{
		Print("Caught the exception!");
		exit(1);
	}
	return false;
}

Instead of catching an exception, the Lua error log just prints out "std-exception: 'An error has occurred!'"

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

That's not what's supposed to happen. LuaBind is supposed to throw a LuaBind exception my catch statement would catch. I don't want to parse the error log and guess which messages might be exceptions.

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

I see, I know you can do custom exception handling in luabind as well. Try this:

 

luabind::register_exception_handler<MyException>(&FunctionToCallWhenExceptionOccurs);

 

You can also replace the luabind error text with your own and then make it actually return and stop the program maybe?

 

My point was to do it like this:

 

// lua class

try
{
   luacode
}

catch
{
   LuaException = true;
}

// in any other class

try
{
   LuaClass::Init();

   if(LuaClass::LuaException)
   {
       throw;
   }
}

catch(blah)
{
   return 0; // or w/e
}

 

Its annoying, but Entity also has multiple levels of exceptions. So when I inherit these classes into my scene classes, all the exceptions forward to my engine and throws my UI notification dialog I made.

AMD Phenom II X4 B55 3.20 GHz - 8.00 GB Patriot Gamer Series RAM - AMD Radeon HD 6800 Series 1 GB GDDR5 - Windows 7 Professional 64 Bit

Link to comment
Share on other sites

If any of the functions you register throws an exception when called, that exception will be caught by luabind and converted to an error string and lua_error() will be invoked.

Ahhhhh, it makes sense now.

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

I don't know if it's possible to call debug.trace once an exception has been thrown, before lua_pcall returns, but it is possible to make my own RuntimeError() function which first performs a debug.trace if it is being called from a Lua state.

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

  • 1 month later...

I take it you just dropped LuaBind and went with toLua++ right?

52t__nvidia.png nVidia 530M cpu.gif Intel Core i7 - 2.3Ghz 114229_30245_16_hardware_memory_ram_icon.png 8GB DDR3 RAM Windows7_Start.gif Windows 7 Ultimate (64x)

-----

IconVisualStudio16.png Visual Studio 2010 Ultimate google-Chrome.png Google Chrome PhotoshopLinkIndicator.png Creative Suite 5 icon28.gif FL Studio 10 MicrosoftOfficeLive.png Office 15

-----

csharp.png Expert cpp.png Professional lua_icon.png Expert BMX Programmer

-----

i-windows-live-messenger-2009.pngskype-icon16.pngaim_online.pnggmail.pngicon_48x48_prism-facebook.pngtunein-web.pngyahoo.giftwitter16.png

Link to comment
Share on other sites

Yes. Object slicing with ToLua isn't an issue as long as you keep the object in Lua memory somehow, so I just add all relevant object to a global table.

My job is to make tools you love, with the features you want, and performance you can't live without.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...