From b698d500baca9e670823183d3ca513565818977b Mon Sep 17 00:00:00 2001 From: James Roseborough Date: Tue, 25 Aug 2009 20:46:07 +0000 Subject: [PATCH] Fix arg check and behavior of xpcall() to leave stack intact. --- README.html | 11 ++- src/core/org/luaj/lib/BaseLib.java | 21 ++--- src/core/org/luaj/vm/LuaErrorException.java | 10 ++- src/core/org/luaj/vm/LuaState.java | 96 ++++++++++++++++----- src/j2se/lua.java | 2 +- src/test/res/pcalls.lua | 15 ++++ version.properties | 2 +- 7 files changed, 116 insertions(+), 41 deletions(-) diff --git a/README.html b/README.html index 861179c4..21bb3431 100644 --- a/README.html +++ b/README.html @@ -17,7 +17,7 @@ Getting Started with LuaJ -James Roseborough, Ian Farmer, Version 1.0 +James Roseborough, Ian Farmer, Version 1.0.1

Copyright © 2007-2009 Luaj.org. @@ -36,6 +36,8 @@ Freely available under the terms of the building · downloads +· +release notes

@@ -334,3 +336,10 @@ and LuaForge: LuaForge Luaj Project Area +

6 - Release Notes

+ +Main changes by version: +
+ + +
  1.0Initial publicly supported release.
  1.0.1Fix arg check and behavior of xpcall() to leave stack intact.
diff --git a/src/core/org/luaj/lib/BaseLib.java b/src/core/org/luaj/lib/BaseLib.java index 17f69c9e..eefc57b1 100644 --- a/src/core/org/luaj/lib/BaseLib.java +++ b/src/core/org/luaj/lib/BaseLib.java @@ -198,7 +198,7 @@ public class BaseLib extends LFunction { case PCALL: { vm.checkany(1); int n = vm.gettop(); - int s = vm.pcall( n-1, Lua.LUA_MULTRET, 0 ); + int s = vm.pcall( n-1, Lua.LUA_MULTRET ); if ( s == 0 ) { // success, results are on stack vm.pushboolean( true ); vm.insert( 1 ); @@ -210,26 +210,17 @@ public class BaseLib extends LFunction { } } case XPCALL: { - LValue errfun = vm.checkany(3); + LValue errfun = vm.checkany(2); vm.settop(1); - int s = vm.pcall( 0, Lua.LUA_MULTRET, 0 ); + int s = vm.xpcall( 0, Lua.LUA_MULTRET, errfun ); if ( s == 0 ) { // success, results are on stack vm.pushboolean( true ); vm.insert( 1 ); return -1; } else { // error, error message is on the stack - vm.pushlvalue( errfun ); + vm.pushboolean( false ); vm.insert( 1 ); - s = vm.pcall( vm.gettop()-1, 1, 0 ); - if ( s == 0 ) { - vm.pushboolean( false ); - vm.insert( 1 ); - return -1; - } else { // error in error handler - vm.pushboolean(false); - vm.pushstring("error in error handling"); - return 2; - } + return 2; } } case ERROR: { @@ -489,7 +480,7 @@ public class BaseLib extends LFunction { try { while ( true ) { setResult(vm,c); - if ( 0 != vm.pcall(0, 1, 0) ) { + if ( 0 != vm.pcall(0, 1) ) { setErrorResult(vm, vm.tostring(2)); return false; } diff --git a/src/core/org/luaj/vm/LuaErrorException.java b/src/core/org/luaj/vm/LuaErrorException.java index 5039aff2..a0e8d041 100644 --- a/src/core/org/luaj/vm/LuaErrorException.java +++ b/src/core/org/luaj/vm/LuaErrorException.java @@ -74,14 +74,18 @@ public class LuaErrorException extends RuntimeException { * @return */ private static String addLineInfo(LuaState vm, String message, int level) { - if ( level == 0 || message == null ) - return message; + // add position information if ( vm == null ) { if ( LThread.running != null ) vm = LThread.running.vm; else vm = LuaState.mainState; + if ( vm == null ) + return message; } - return vm != null? vm.getFileLine(level) + ": " + message: message; + if ( level > 0 ) { + message = vm.getFileLine(level); + } + return vm.luaV_call_errfunc( message ); } } diff --git a/src/core/org/luaj/vm/LuaState.java b/src/core/org/luaj/vm/LuaState.java index f7717cd6..2817702c 100644 --- a/src/core/org/luaj/vm/LuaState.java +++ b/src/core/org/luaj/vm/LuaState.java @@ -98,7 +98,7 @@ public class LuaState extends Lua { public int cc = -1; public CallInfo[] calls = new CallInfo[LUA_MINCALLS]; protected Stack upvals = new Stack(); - protected LFunction panic; + protected LValue errfunc; static LuaState mainState; public LTable _G; @@ -362,24 +362,6 @@ public class LuaState extends Lua { * lua_pcall always removes the * function and its arguments from the stack. * - * - *

- * If errfunc is 0, then the error message returned on the - * stack is exactly the original error message. Otherwise, - * errfunc is the stack index of an - * error handler function. (In the current implementation, this - * index cannot be a pseudo-index.) In case of runtime errors, this function - * will be called with the error message and its return value will be the - * message returned on the stack by lua_pcall. - * - * - *

- * Typically, the error handler function is used to add more debug - * information to the error message, such as a stack traceback. Such - * information cannot be gathered after the return of lua_pcall, - * since by then the stack has unwound. - * - * *

* The lua_pcall function returns * 0 in case of success or one of the following error codes (defined in @@ -399,7 +381,7 @@ public class LuaState extends Lua { * * */ - public int pcall( int nargs, int nreturns, int errfunc ) { + public int pcall( int nargs, int nreturns ) { // save stack state int oldtop = top; int oldbase = base; @@ -446,6 +428,46 @@ public class LuaState extends Lua { } } + + /** + * Calls a function in protected mode with an error function. + * [-(nargs + 1), +(nresults|1), -] + * + * + *

+ * Both nargs and nresults have the same + * meaning as in lua_call. If there + * are no errors during the call, lua_xpcall + * behaves exactly like lua_call. + * However, if there is any error, lua_xpcall + * catches it, pushes a single value on the stack (the error message), and + * tries to call the supplied error function. + * + *

In case of runtime errors, this function + * will be called with the error message and its return value will be the + * message returned on the stack by lua_pcall. + * + *

+ * Typically, the error handler function is used to add more debug + * information to the error message, such as a stack traceback. Such + * information cannot be gathered after the return of lua_pcall, + * since by then the stack has unwound. + * + *

+ * The return values for + * lua_xpcall are the same as those for + * lua_pcall + */ + public int xpcall( int nargs, int nreturns, LValue errfunc ) { + LValue preverrfunc = this.errfunc; + try { + this.errfunc = errfunc; + return pcall( nargs, nreturns ); + } finally { + this.errfunc = preverrfunc; + } + } + /** * Loads a Lua chunk. [-0, +1, -] * @@ -2361,6 +2383,40 @@ public class LuaState extends Lua { } } + + /** + * Call the error function, if any, to possibly modify the message + */ + public String luaV_call_errfunc(String message) { + + // error function is run at most once + if ( errfunc == null ) + return message; + + // run the error function + int oldtop = top; + int oldmask = hookmask; + LValue olderr = errfunc; + try { + hookmask = 0; + errfunc = null; + if ( cc >= 0 ) + top = base + this.calls[cc].closure.p.maxstacksize; + pushlvalue(olderr); + pushstring(message); + call(1,1); + return poplvalue().toJavaString(); + + } catch ( Throwable t ) { + return "error in error handling: "+t.getMessage(); + + } finally { + top = oldtop; + hookmask = oldmask; + errfunc = olderr; + } + } + // =========================================================================== // Debug hooks. diff --git a/src/j2se/lua.java b/src/j2se/lua.java index 7ce08c7d..dc1bd649 100644 --- a/src/j2se/lua.java +++ b/src/j2se/lua.java @@ -159,7 +159,7 @@ public class lua { // load via "require" vm.getglobal("require"); vm.pushstring(libname); - int status = vm.pcall(1, 0, 0); + int status = vm.pcall(1, 0); if ( status == 0 ) return; diff --git a/src/test/res/pcalls.lua b/src/test/res/pcalls.lua index e1cab2ea..689b0e64 100644 --- a/src/test/res/pcalls.lua +++ b/src/test/res/pcalls.lua @@ -58,3 +58,18 @@ for i = 0,4 do print( 'pcall(ge,i)', i, pcall(ge,i) ) end +-- xpcall tests +local function goodfunction() return 'from good function' end +local function badfunction() error( 'from bad function') end +local function goodhandler(msg) return '-->'..msg..'<--' end +local function badhandler(msg) error( 'from bad handler' ) end +print( 'xpcall(error,goodhandler)', ( xpcall(error,goodhandler) ) ) +print( 'xpcall(goodfunction,goodhandler)', ( xpcall(goodfunction,goodhandler) ) ) +print( 'xpcall(badfunction,goodhandler)', ( xpcall(badfunction,goodhandler) ) ) +print( 'xpcall(goodfunction,badhandler)', ( xpcall(goodfunction,badhandler) ) ) +print( 'xpcall(badfunction,badhandler)', ( xpcall(badfunction,badhandler) ) ) +print( 'xpcall(goodfunction,nil)', ( xpcall(goodfunction,nil) ) ) +print( 'xpcall(badfunction,nil)', ( xpcall(badfunction,nil) ) ) +print( 'xpcall(goodfunction)', ( pcall( function() return xpcall(goodfunction) end ) ) ) +print( 'xpcall(badfunction)', ( pcall( function() return xpcall(badfunction) end ) ) ) + diff --git a/version.properties b/version.properties index a5ef50fd..50a53647 100644 --- a/version.properties +++ b/version.properties @@ -1 +1 @@ -version: 1.0 +version: 1.0.1