I am little newbie in C++ scripting but I know some things.
I'm compiling a plugin that use a function to call an Lua callback using the LuaBind, but the client crashes when function doesn't exists on main.lua, also I'm trying to add an error handler to that functions... I don't know what I can do to solve it.
Here is my code:
{
try
{
luabind::call_function<int>(L, "onServerFrame", elapsedTime);
}
catch (luabind::error& e)
{
std::string error = lua_tostring(e.state(), -1);
std::cout << error << "\n";
}
}
Solved. Thanks to my friend habi.
luabind::object func = g[name];
if( func ) { if( luabind::type(func) == LUA_TFUNCTION ) luabind::call_function<void>(L,"onServerFrame", elapsedTime);}
Related
I am trying to retrieve a stack trace in my program, and store it for later use (debugging purposes). But the call to boost::stacktrace::frame::name() never returns, and I have no clue why. When I use this exact code in a simple project, it runs nicely. Any ideas?
boost::stacktrace::stacktrace stacktrace;
stringstream stacktraceText;
for (const auto& entry : stacktrace)
{
if (entry.empty() == false)
{
auto name = entry.name();
stacktraceText << name << "\n";
}
else
{
stacktraceText += L"<missing symbol info>\n";
}
}
I have one problem. In c++ app, I am using sd-bus and signal does not call my callback function.
I hooked to org.freedesktop.login1, interface is org.freedesktop.DBus.Properties, member is PropertiesChanged and path is /org/freedesktop/login1/seat/seat0
In my connect method I have this:
sd_bus_add_match(m_bus, NULL, "interface='org.freedesktop.DBus.Properties',member='PropertiesChanged',path='/org/freedesktop/login1/seat/seat0',type='signal'", on_properties_changed, NULL)
On properties changed method is this:
static int on_properties_changed(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
printf("got some signal");
}
So, when I ran this program, I also ran following command in cmd:ΒΈ
gdbus monitor --system --dest org.freedesktop.login1 --object-path /org/freedesktop/login1/seat/seat0
However, when I switch from userA to userB, I got following line in cmd window:
/org/freedesktop/login1/seat/seat0: org.freedesktop.DBus.Properties.PropertiesChanged ('org.freedesktop.login1.Seat', {'ActiveSession': <('c7', objectpath '/org/freedesktop/login1/session/c7')>}, #as [])
Also when I tried this
busctl --system --match "interface='org.freedesktop.DBus.Properties',member='PropertiesChanged',path='/org/freedesktop/login1/seat/seat0',type='signal' monitor
then I also get proper response
Type=signal Endian=l Flags=1 Version=1 Priority=0 Cookie=2281
Sender=:1.0 Path=/org/freedesktop/login1/seat/seat0 Interface=org.freedesktop.DBus.Properties Member=PropertiesChanged
UniqueName=:1.0
MESSAGE "sa{sv}as" {
STRING "org.freedesktop.login1.Seat";
ARRAY "{sv}" {
DICT_ENTRY "sv" {
STRING "ActiveSession";
VARIANT "(so)" {
STRUCT "so" {
STRING "c2";
OBJECT_PATH "/org/freedesktop/login1/session/c2";
};
};
};
};
ARRAY "s" {
};
};
But in c++ that callback function is not called. Any idea why is it not called?
I am using Ubuntu 16.04 and my systemd version is 229.
I found a solution to this problem. Problem was that I wasn't hooked to any event loop.
So I created new function run() and in this function I say this:
while(m_running) {
sd_bus_message *m = NULL;
r = sd_bus_process(m_bus, &m);
if (r < 0) {
//error handling
}
r = sd_bus_wait(m_bus, (uint64_t)-1);
if (r < 0) {
//error handling
}
}
and now I call this function after I connect to signal, and callback function of sd_bus_add_match is normally called
I've used the example from http://www.rasterbar.com/products/luabind/docs.html#deriving-in-lua to define a class in c++ that I can derive from in lua:
class base
{
public:
base(const char* s)
{ std::cout << s << "\n"; }
virtual void f(int a)
{ std::cout << "f(" << a << ")\n"; }
};
struct base_wrapper : base, luabind::wrap_base
{
base_wrapper(const char* s)
: base(s)
{}
virtual void f(int a)
{
call<void>("f", a);
}
static void default_f(base* ptr, int a)
{
return ptr->base::f(a);
}
};
...
module(L)
[
class_<base, base_wrapper>("base")
.def(constructor<const char*>())
.def("f", &base::f, &base_wrapper::default_f)
];
I've then created a derived class in lua:
class 'base_derived' (base)
function base_derived:__init(str)
base.__init(self,str)
end
function base_derived:f()
this_function_doesnt_exist()
end
Any call to 'f' is supposed to throw a lua error, which works fine if I do it in lua:
local x = base_derived("Test")
x:f() -- Throws "attempt to call a nil value..." error
I'd like to do the equivalent of that, but in c++:
auto g = luabind::globals(l);
auto r = g["base_derived"];
if(r)
{
luabind::object o = r("Test");
auto gm = luabind::object_cast<base_wrapper*>(o);
if(gm != nullptr)
{
try
{
luabind::call_member<void>(o,"f",5);
}
catch(luabind::error &e)
{
std::cout<<"[LUA] Error: "<<e.what()<<std::endl;
}
}
o.push(l);
}
However the 'luabind::call_member'-call causes an abort in 'luabind/detail/call_member.hpp', line 258:
// Code snippet of luabind/detail/call_member.hpp
~proxy_member_void_caller()
{
if (m_called) return;
m_called = true;
// don't count the function and self-reference
// since those will be popped by pcall
int top = lua_gettop(L) - 2;
// pcall will pop the function and self reference
// and all the parameters
push_args_from_tuple<1>::apply(L, m_args);
if (pcall(L, boost::tuples::length<Tuple>::value + 1, 0))
{
assert(lua_gettop(L) == top + 1);
#ifndef LUABIND_NO_EXCEPTIONS
////////////////////////////////////////////
throw luabind::error(L); // LINE 258
////////////////////////////////////////////
#else
error_callback_fun e = get_error_callback();
if (e) e(L);
assert(0 && "the lua function threw an error and exceptions are disabled."
"If you want to handle this error use luabind::set_error_callback()");
std::terminate();
#endif
}
// pops the return values from the function
stack_pop pop(L, lua_gettop(L) - top);
}
The exception in that line isn't actually thrown, but it is what causes the abort.
However, the abort only happens if the lua-functions causes a lua error. If I comment the 'this_function_doesnt_exist()'-call, both the lua- and c++-versions run just fine.
Why is the 'throw luabind::error(L);' causing an abort and what can I do to safely call the function from c++ even with potential lua errors?
// Edit:
This is the call stack at the time of the abort (When 'luabind::call_member(o,"f",5);' is called):
> vcruntime140d.dll!__CxxFrameHandler(EHExceptionRecord * pExcept, unsigned __int64 RN, _CONTEXT * pContext, _xDISPATCHER_CONTEXT * pDC) Line 213 C++
ntdll.dll!RtlpExecuteHandlerForException() Unknown
ntdll.dll!RtlDispatchException() Unknown
ntdll.dll!KiUserExceptionDispatch() Unknown
KernelBase.dll!RaiseException() Unknown
vcruntime140d.dll!_CxxThrowException(void * pExceptionObject, const _s__ThrowInfo * pThrowInfo) Line 136 C++
server.dll!luabind::detail::proxy_member_void_caller<boost::tuples::tuple<int const * __ptr64,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type> >::~proxy_member_void_caller<boost::tuples::tuple<int const * __ptr64,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type,boost::tuples::null_type> >() Line 258 C++
And this is the abort message:
See line 254:
if (pcall(L, boost::tuples::length<Tuple>::value + 1, 0))
Here, pcall is asking lua to execute your x:f(5) equivalent call. Apparently this code returns an error because pcall() returns something different than zero. This is expected because you are indeed creating an error in lua by calling this_function_doesnt_exist(). This also explains why the abort does not happen when you comment the this_function_doesnt_exist() call.
Then, to the C++ code:
throw luabind::error(L);
This error is thrown from a destructor: ~proxy_member_void_caller(), and it turns out that throwing an exception from a destructor is bad practice. This problem is known for luabind (see this question) to trigger the call of abort without even throwing.
The solution is to add noexcept(false)to the signature of ~proxy_member_void_caller(), like this:
~proxy_member_void_caller() noexcept(false)
I am writing up some tests for a C++ program and I would like to check that my program throws certain types of exceptions when given certain inputs. I have seen that this is doable using external libraries such as googletest, but I would like to know how this was implemented.
I would like to separate the test data from the test code as much as possible. In particular, I would like something like this:
void RunTests(InputList inputs) {
for (int i = 0; i < inputs.length; i++) {
if (FunctionIAmTesting(inputs[i].value) has the expected exception behavior) {
// Pass
} else {
// Fail
}
}
}
InputList inputs = InputList({
Input(5), // no exception when 5 is an input
Input<MyExceptionClass>(0), // MyExceptionClass thrown when 0 is an input
Input<MyOtherExceptionClass>(-1) // MyOtherExceptionClass thrown when -1 is an input
});
RunTests(inputs);
If you know what the type of exception you are looking for then you can target an exception of that type in the catch () statement.
try {
// Test code.
// Unexpected success
std::cerr << "Expected a RelevantException to be thrown." << std::endl;
}
catch (RelevantException& e)
{
// Expected exception, continue.
}
catch (...) // Catch all
{
// Unexpected exception
std::cerr << "Unexpected exception encountered, expected "
"RelevantException." << std::endl;
}
A several years back I wrote some simple library for "mocking" objects. And my goal was to check everything related to function calls. In the tests I wrote something like that:
MyMockedObject my;
mock::expect(my, "foo").in(10).out(20).returns(30);
mock::expect(my, "bar").throws(logic_error("bar failed"));
int v;
// test that my::baz() invokes my.foo(10, v)
// then my.bar which fails with the exception
my.baz();
Your task seems to be a little bit easier. All that you need is a way how to describe your expectations and some hack in the test runner to verify them at the end of a test (accordingly to the input). Your expectations are exceptions, just construct them somehow and associate with the input. In your example you did a half part of your work.
typedef std::map<Input, Exception> Expectations;
typedef std::pair<Input, Exception> Expectation;
// somewhere before the tests
expectations.insert(make_pair(Input(5)), NoThrowAnything);
expectations.insert(make_pair(Input(0)), MyException("some message"));
expectations.insert(make_pair(Input(-1)), MyOtherException("another message"));
void run_test(const Expectation& expect)
{
try {
// run the real test here based on Input (expect.first)
check_expectation(expect);
} catch (const Exception& ex) {
check_expectation(expect, ex);
}
}
void run_all_tests(const Expectations& expects)
{
for (e : expects) {
try {
run_test(e);
} catch (const ExpectationException ex) {
// failed expectation
}
}
}
void check_expectation(const Expectation& expect)
{
if (expect.second != NoThrowAnything) {
throw ExpectationFailure(expect);
}
}
void check_expectation(const Expectation& expect, const Exception& ex)
{
if (expect.second != ex) {
throw ExpectationMismatch(expect, ex);
}
}
In Lua I have a function called utils.debug() and what I would like to do is use it in my Lua code as follows:
function Foo:doSomething
if (/* something */) then
print("Success!")
else
utils.debug()
end
end
function Foo:doSomethingElse
if (/* something else */) then
print("Awesome!")
else
utils.debug()
end
end
I would like to use it throughout my Lua code to help me debug. As a result, I would like my C++ code to know where in the Lua code the utils.debug() was called from. I looked into lua_Debug and lua_getinfo and they seem pretty close to what I want, but I'm missing a piece:
int MyLua::debug(lua_State* L)
{
lua_Debug ar;
lua_getstack(L, 1, &ar);
lua_getinfo(L, ??????, &ar);
// print out relevant info from 'ar'
// such as in what function it was called, line number, etc
}
Is this what the lua_Debug struct is for or is there another facility or method I should use to do this?
This is what I use to produce a Lua stack trace:
lua_Debug info;
int level = 0;
while (lua_getstack(l, level, &info)) {
lua_getinfo(l, "nSl", &info);
fprintf(stderr, " [%d] %s:%d -- %s [%s]\n",
level, info.short_src, info.currentline,
(info.name ? info.name : "<unknown>"), info.what);
++level;
}
See the documentation for lua_getinfo for more info.