Rapptz / sol

A C++11 Lua wrapper
MIT License
209 stars 32 forks source link

Example of catching exception? #65

Closed mallochine closed 9 years ago

mallochine commented 9 years ago

I wrote some purposefully bad Lua code. I tried catching a sol::error after calling "open_file" but the C++ just SEGFAULTs.

mallochine commented 9 years ago

Hold on. I might be using the wrong type when catching the exception.

mallochine commented 9 years ago

Yeah, this is weird.

Only "catch (...)" works. These things don't work:

catch (std::exception& exception) { catch (std::exception exception) { catch (const std::exception& exception) { catch (sol::error) catch (const sol::error&)

what's going on?

Rapptz commented 9 years ago

Provide the C++ and Lua code.

mallochine commented 9 years ago

Abridged version, as some of the code is proprietary.

template<typename... Ret, typename... Args>
inline typename sol::return_type<Ret...>::type LuaCall(
  const sol::state& lua,
  const string& func_name,
  Args&&... args)
  try {
    typename sol::return_type<Ret...>::type result;
    sol::function func = lua.get<sol::function>(func_name);
    return func.call<Ret...>(std::forward<Args>(args)...);
  } catch (...) {
    typename sol::return_type<Ret...>::type empty_result;
    LOG(INFO) << "Helo world";
    return empty_result;
  }
LuaCall<bool>(lua, "blablabla_function_does_not_exist")

EDIT: you could just pass in function that doesn't exist.

mallochine commented 9 years ago

Some more debug:

try {
  ...
} catch (...) {
  LOG(INFO) << __cxa_current_exception_type();
  LOG(INFO) << "----------------------------";
  LOG(INFO) << __cxa_current_exception_type()->name();
}

This results in:

0xfffffffe
----------------------------
Segmentation fault
mallochine commented 9 years ago

I'm also using ThePhd's latest version on his "develop" branch

mallochine commented 9 years ago

My clang version is 3.6.1

ThePhD commented 9 years ago

As a final question, are you still using luajit or just regular lua ?

mallochine commented 9 years ago

libluajit-5.1.a. It might have been something in your "develop" branch, but not sure.

ThePhD commented 9 years ago

Calling your function in VC++ works fine: a proper error occurs from luajit and is caught by sol::error Going to test with g++ and clang++ when I get a chance.

mallochine commented 9 years ago

an additional detail: luajit is linked statically.

ThePhD commented 9 years ago

Works in g++. Attempting clang++ once I build luajit and everything with it....

mallochine commented 9 years ago

Thanks, let me know once you have some idea on how to fix this

mallochine commented 9 years ago

Did you try with statically linked luajit?

ThePhD commented 9 years ago

I can't get my clang-for-windows to behave properly with any standard library. Going to need someone else to attempt to build and run. For reference, this is the test I'm using:

#include <sol.hpp>
#include <iostream>

int main( ) {
    sol::state lua;
    lua.open_libraries(sol::lib::base);

    try {
        lua.script( R"(
-- Correct name is "test", but renamed to "__test" to force Lua to throw an exception.
function __test()
return true
end
        )" );
        sol::function func = lua.get<sol::function>( "test" );
        bool value = func.call<bool>( );
        (void)value;
    }
    catch ( const sol::error& e ) {
        std::cout << e.what( ) << std::endl;
    }
    catch ( const std::exception& e ) {
        std::cout << e.what( ) << std::endl;
    }

    return 0;
}
mallochine commented 9 years ago

seems good. I'll try with that small code tomorrow morning. There isn't clang compiler binary you can download for windows?

mallochine commented 9 years ago

@ThePhD

Just tried now, and didn't work:

void sanity_test_lua() {
  sol::state lua;
  lua.open_libraries(sol::lib::base);
  lua.script("function __test() return true end");
  try {
    sol::function func = lua.get<sol::function>("test");
    bool value = func.call<bool>();
    (void) value;
  } catch (const sol::error& err) {
    LOG(INFO) << "Pass.";
  } catch (const std::exception& err) {
    LOG(INFO) << "Pass.";
  } catch (...) {
    LOG(FATAL) << "Should not be in this catch block!";
  }
}
mallochine commented 9 years ago

As a sanity check: If I change "test" to "__test", then the code doesn't hit any of the catch blocks.

ThePhD commented 9 years ago

It's going to take me a while to test this. None of my Clang for Windows builds can handle either the Visual Studio 2015 RC standard library (char16/32_t aren't defined properly for the newer versions of VC++ that have support for it) and also reject MinGW builds (with 5.1.0, nothing links properly).

I have to backtrack to an Ubuntu VM, get clang, and then try the code, which will take me some time.

mallochine commented 9 years ago

Hm, it appears that the test code I posted was stupid. The following does work on gcc (good news for you? :) )

This is the test code I'm using now. The difference is I removed the catch-all "catch (...)"

void sanity_test_lua() {
  sol::state lua;
  lua.open_libraries(sol::lib::base);
  lua.script("function __test() return true end");
  try {
    sol::function func = lua.get<sol::function>("test");
    bool value = func.call<bool>();
    (void) value;
  } catch (const sol::error& err) {
    LOG(INFO) << "Pass.";
    return;
  } catch (const std::exception& err) {
    LOG(INFO) << "Pass.";
    return;
  }
  LOG(FATAL) << "Should not have reached here!.";
}

Maybe I'll try the clang version now.

mallochine commented 9 years ago

Oh, as it turns out, that small test passes on the clang version now. Sorry for all the trouble mate. Let me figure out what went wrong with the other code I did then.

mallochine commented 9 years ago

I'll close this issue once I'm able to fix the original code.

mallochine commented 9 years ago

So, the code works when it's part of the unit test, but not when it's part of the production code. Hm.......

mallochine commented 9 years ago

OK, so there must be something really funky with adding Lua into the project I'm working on.

This code results in SEGFAULT:

void InitLuaVm() {
  sol::state lua;
  lua.open_libraries(sol::lib::base);
  try {
    lua.open_file("garbage.lua");
  } catch (const sol::error& err) {
    LOG(INFO) << "Pass: sol::error: " << err.what(); // Probably here, since err would be junk value.
    return;
  }
  LOG(FATAL) << "Should not have reached here!";

This code results in a LOG(FATAL) somewhere in some other system component (Zeus??)

void InitLuaVm() {
  sol::state lua;
  lua.open_libraries(sol::lib::base);
  try {
    lua.open_file(
      "/home/nutanix/hmain/installer/config/arithmos/deletable_entities.lua");
  } catch (const sol::error& err) {
    LOG(INFO) << ".........................";
    return;
  }
  LOG(FATAL) << "Should not have reached here!";
ThePhD commented 9 years ago

Okay, so "probably here" doesn't help me find out if you have a problem or the library has a problem. I do not know what "other system component" means, I do not know what "Zeus" is.

After much toil, everything compiles and runs on my machine. The problem might lie in your deletable_entities.lua file. Perhaps it doesn't exist where you think it does. Perhaps the code makes the luajit-2.0.3 parser flip out and crash. I have no way of knowing this.

All I know is that as it stands the code is alright. Until you can spend some time properly debugging your lua code, commenting out things until you can exactly pinpoint the problem, we're just going to be wasting time stabbing into the dark.

Please spend some time properly debugging your code.

mallochine commented 9 years ago

Well, this results in FATAL. And I am trying to debug, but it is not simple. This code base is 40k of C++, and that other component Zeus is an open sourced Apache project that's also fairly large.

  sol::state lua;
  lua.open_libraries(sol::lib::base);
  try {
    lua.script("end end end end end");
  } catch (const sol::error& err) {
    return;
  }
  LOG(FATAL) << "Should not have reached here!";
mallochine commented 9 years ago

So maybe this is a general problem with LuaJIT and C++ exceptions.

What I did was replace your header with the equivalent C code. The following code reproduces the exact same problem, a segfault (probably around "err"):

  lua_State *my_lua = lua_open();
  try {
    int result = luaL_dostring(my_lua, "end end end end end");
    LOG(INFO) << "Lua result: " << result;
    lua_error(my_lua);
  } catch (std::exception& err) {
    LOG(INFO) << "Oops: " << err.what();
  }
  lua_close(my_lua);
ThePhD commented 9 years ago

At the bottom of the LuaJIT extension page, you can read more about how they deal with exceptions: http://luajit.org/extensions.html. It does not explicitly mention LLVM as a safe target, just GCC-binaries and WinSDK/VC++ binaries (on x64 Windows for those).

It could be you're hitting an edge case with luajit here. You may also want to try to upgrade to luajit-2.0.4 (since you're on 2.0.3): the changelog for 2.0.4 is long and 2.0.3 is over a year old now, which may not account for the changes of the latest stable clang (3.6). It should also be noted that the luajit I use I build from source, and piece together things manually myself on Windows for the x64 build. In either case, this is a luajit issue, and one we can't help you with.

Good luck.

mallochine commented 9 years ago

Well, we're already using LuaJIT-2.0.4. Thanks for your patience during this issue though. I can close this issue now.

EDIT: we also build luajit-2.0.4 from source, and then statically link it.

mallochine commented 9 years ago

Well I just retried using GCC 4.4.7, and still running into the exact same issue. FYI to anybody who finds this thread from Google.