Skip to content

Commit

Permalink
[lua] Clean up uncaught error handling (#11082)
Browse files Browse the repository at this point in the history
* [lua] Clean up uncaught error handling

Removes usage of os.exit, which makes it safer and applicable both
to lua scripts embedded in another application and standalone scripts.
This removes the need for the lua-standalone flag.

* [lua] Mark Exception.toString with @:keep

If it is dce'd, we get a mess when lua prints an uncaught error

* [lua] Prevent error handler polluting error stack

* Add tests for #10979

* Prevent test failures on lua 5.1

Lua 5.1 has slightly different error messages and doesn't print custom
error objects.

* Minor fix
  • Loading branch information
tobil4sk committed Apr 4, 2023
1 parent f2b013e commit a6aee34
Show file tree
Hide file tree
Showing 16 changed files with 116 additions and 42 deletions.
6 changes: 0 additions & 6 deletions src-json/define.json
Original file line number Diff line number Diff line change
Expand Up @@ -402,12 +402,6 @@
"doc": "Enable the jit compiler for lua (version 5.2 only).",
"platforms": ["lua"]
},
{
"name": "LuaStandalone",
"define": "lua-standalone",
"doc": "Print uncaught error before exiting the lua script.",
"platforms": ["lua"]
},
{
"name": "LuaVanilla",
"define": "lua-vanilla",
Expand Down
42 changes: 16 additions & 26 deletions src/generators/genlua.ml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ type ctx = {
mutable separator : bool;
mutable found_expose : bool;
mutable lua_jit : bool;
mutable lua_standalone : bool;
mutable lua_vanilla : bool;
mutable lua_ver : float;
}
Expand Down Expand Up @@ -1884,7 +1883,6 @@ let alloc_ctx com =
separator = false;
found_expose = false;
lua_jit = Common.defined com Define.LuaJit;
lua_standalone = Common.defined com Define.LuaStandalone;
lua_vanilla = Common.defined com Define.LuaVanilla;
lua_ver = try
float_of_string (Common.defined_value com Define.LuaVer)
Expand Down Expand Up @@ -2148,36 +2146,28 @@ let generate com =
print_file (Common.find_file com "lua/_lua/_hx_dyn_add.lua");
end;

if ctx.lua_standalone && Option.is_some com.main then begin
print_file (Common.find_file com "lua/_lua/_hx_handle_error.lua");
end;
print_file (Common.find_file com "lua/_lua/_hx_handle_error.lua");

println ctx "_hx_static_init();";

List.iter (generate_enumMeta_fields ctx) com.types;

Option.may (fun e ->
let luv_run =
(* Runs libuv loop if needed *)
mk_lua_code ctx.com.basic "_hx_luv.run()" [] ctx.com.basic.tvoid Globals.null_pos
in
if ctx.lua_standalone then begin
spr ctx "_G.xpcall(";
let fn =
{
tf_args = [];
tf_type = com.basic.tvoid;
tf_expr = mk (TBlock [e;luv_run]) com.basic.tvoid e.epos;
}
in
gen_value ctx { e with eexpr = TFunction fn; etype = TFun ([],com.basic.tvoid) };
spr ctx ", _hx_handle_error)";
end else begin
gen_expr ctx e;
newline ctx;
gen_expr ctx luv_run;
end;
newline ctx
spr ctx "local success, err = _G.xpcall(";
let luv_run =
(* Runs libuv loop if needed *)
mk_lua_code ctx.com.basic "_hx_luv.run()" [] ctx.com.basic.tvoid Globals.null_pos
in
let fn =
{
tf_args = [];
tf_type = com.basic.tvoid;
tf_expr = mk (TBlock [e;luv_run]) com.basic.tvoid e.epos;
}
in
gen_value ctx { e with eexpr = TFunction fn; etype = TFun ([],com.basic.tvoid) };
println ctx ", _hx_handle_error)";
println ctx "if not success then _G.error(err) end";
) com.main;

if anyExposed then
Expand Down
16 changes: 6 additions & 10 deletions std/lua/_lua/_hx_handle_error.lua
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
function _hx_handle_error(obj)
if obj.value then
_G.print("runtime error:\n " .. _hx_tostring(obj.value));
else
_G.print("runtime error:\n " .. tostring(obj));
end

if _G.debug and _G.debug.traceback then
_G.print(_G.debug.traceback());
end
_G.os.exit(1)
local message = tostring(obj)
if _G.debug and _G.debug.traceback then
-- level 2 to skip _hx_handle_error
message = _G.debug.traceback(message, 2)
end
return setmetatable({}, { __tostring = function() return message end })
end
1 change: 1 addition & 0 deletions std/lua/_std/haxe/Exception.hx
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class Exception {
return __nativeException;
}

@:keep // required for uncaught error handling
public function toString():String {
return message;
}
Expand Down
5 changes: 5 additions & 0 deletions tests/misc/lua/projects/Issue10979/HaxeException.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class HaxeException {
static function main() {
throw "Exception thrown from Haxe";
}
}
6 changes: 6 additions & 0 deletions tests/misc/lua/projects/Issue10979/NativeError.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
class NativeError {
static function main() {
final object:Dynamic = null;
trace(object.value);
}
}
38 changes: 38 additions & 0 deletions tests/misc/lua/projects/Issue10979/RunScript.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using StringTools;

function isLua5_1() {
final proc = new sys.io.Process("lua", ["-v"]);
final out = proc.stderr.readLine();
proc.close();
return out.startsWith("Lua 5.1.");
}

function matchesExpectedMessage(actual:String) {
// lua 5.1 doesn't print custom error objects
if (actual == "(error object is not a string)") {
return true;
}
return new EReg(Sys.args()[1], "").match(actual);
}

function main() {
final proc = new sys.io.Process("lua", [Sys.args()[0]]);

// ignore "lua: "
final exceptionMessage = proc.stderr.readLine().substr(5);

final hasExpectedMessage = matchesExpectedMessage(exceptionMessage);
// we don't want a bare error without a stack trace
final hasStackTrace = try {
proc.stderr.readLine().contains('stack traceback');
} catch (_:haxe.io.Eof) {
false;
};

Sys.println('Error code: ${proc.exitCode()}');
Sys.println('Has expected exception message: ${hasExpectedMessage}');
// 5.1 interpreter doesn't handle custom objects
Sys.println('Has call stack: ${hasStackTrace || isLua5_1()}');

proc.close();
}
4 changes: 4 additions & 0 deletions tests/misc/lua/projects/Issue10979/embedded-native.hxml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
--lua bin/native-error.lua
--main NativeError

--cmd lua runner.lua 'bin/native-error' '%./bin/native%-error%.lua:%d+: attempt to index .+'
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Success: false
Has expected exception message: true
Has call stack: true
4 changes: 4 additions & 0 deletions tests/misc/lua/projects/Issue10979/embedded.hxml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
--lua bin/haxe-exception.lua
--main HaxeException

--cmd lua runner.lua 'bin/haxe-exception' 'Exception thrown from Haxe'
3 changes: 3 additions & 0 deletions tests/misc/lua/projects/Issue10979/embedded.hxml.stdout
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Success: false
Has expected exception message: true
Has call stack: true
10 changes: 10 additions & 0 deletions tests/misc/lua/projects/Issue10979/runner.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
-- error in loaded script should be caught here, instead of exiting everything
local success, err = pcall(require, arg[1])

local exception_message = string.match(tostring(err), '^[^\n]+')
local has_expected_message = string.match(exception_message, arg[2]) ~= nil
local has_stack_trace = string.match(tostring(err), 'stack traceback') ~= nil

print('Success: '..tostring(success))
print('Has expected exception message: '..tostring(has_expected_message))
print('Has call stack: '..tostring(has_stack_trace))
7 changes: 7 additions & 0 deletions tests/misc/lua/projects/Issue10979/standalone-native.hxml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
--lua bin/native-error.lua
--main NativeError

--next
--run RunScript
bin/native-error.lua
bin/native-error\.lua:\d+: attempt to index .*
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Error code: 1
Has expected exception message: true
Has call stack: true
7 changes: 7 additions & 0 deletions tests/misc/lua/projects/Issue10979/standalone.hxml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
--lua bin/haxe-exception.lua
--main HaxeException

--next
--run RunScript
bin/haxe-exception.lua
Exception thrown from Haxe
3 changes: 3 additions & 0 deletions tests/misc/lua/projects/Issue10979/standalone.hxml.stdout
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Error code: 1
Has expected exception message: true
Has call stack: true

0 comments on commit a6aee34

Please sign in to comment.