Fix arg check and behavior of xpcall() to leave stack intact.

This commit is contained in:
James Roseborough
2009-08-25 20:46:07 +00:00
parent 92459d0cbc
commit b698d500ba
7 changed files with 116 additions and 41 deletions

View File

@@ -17,7 +17,7 @@
Getting Started with LuaJ
</h1>
James Roseborough, Ian Farmer, Version 1.0
James Roseborough, Ian Farmer, Version 1.0.1
<p>
<small>
Copyright &copy; 2007-2009 Luaj.org.
@@ -36,6 +36,8 @@ Freely available under the terms of the
<a href="#4">building</a>
&middot;
<a href="#5">downloads</a>
&middot;
<a href="#6">release notes</a>
<!-- ====================================================================== -->
<p>
@@ -334,3 +336,10 @@ and LuaForge:
<a href="http://luaforge.net/frs/?group_id=457">LuaForge Luaj Project Area</a>
</pre>
<h1>6 - <a name="6">Release Notes</a></h1>
Main changes by version:
<table cellspacing="10"><tr><td><table cellspacing="4">
<tr><td>&nbsp;&nbsp;<b>1.0</b></td><td>Initial publicly supported release.</td></tr>
<tr><td>&nbsp;&nbsp;<b>1.0.1</b></td><td>Fix arg check and behavior of xpcall() to leave stack intact.</td></tr>
</table></td></tr></table>

View File

@@ -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;
}

View File

@@ -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 );
}
}

View File

@@ -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 {
* <a href="#lua_pcall"><code>lua_pcall</code></a> always removes the
* function and its arguments from the stack.
*
*
* <p>
* If <code>errfunc</code> is 0, then the error message returned on the
* stack is exactly the original error message. Otherwise,
* <code>errfunc</code> is the stack index of an
* <em>error handler function</em>. (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 <a href="#lua_pcall"><code>lua_pcall</code></a>.
*
*
* <p>
* 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 <a href="#lua_pcall"><code>lua_pcall</code></a>,
* since by then the stack has unwound.
*
*
* <p>
* The <a href="#lua_pcall"><code>lua_pcall</code></a> 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 {
*
* </ul>
*/
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.
* <span class="apii">[-(nargs + 1), +(nresults|1), <em>-</em>]</span>
*
*
* <p>
* Both <code>nargs</code> and <code>nresults</code> have the same
* meaning as in <a href="#lua_call"><code>lua_call</code></a>. If there
* are no errors during the call, <a href="#lua_xpcall"><code>lua_xpcall</code></a>
* behaves exactly like <a href="#lua_call"><code>lua_call</code></a>.
* However, if there is any error, <a href="#lua_xpcall"><code>lua_xpcall</code></a>
* catches it, pushes a single value on the stack (the error message), and
* tries to call the supplied error function.
*
* <p>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 <a href="#lua_pcall"><code>lua_pcall</code></a>.
*
* <p>
* 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 <a href="#lua_pcall"><code>lua_pcall</code></a>,
* since by then the stack has unwound.
*
* <p>
* The return values for
* <a href="#lua_xpcall"><code>lua_xpcall</code></a> are the same as those for
* <a href="#lua_pcall"><code>lua_pcall</code></a>
*/
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. <span class="apii">[-0, +1, <em>-</em>]</span>
*
@@ -2362,6 +2384,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.
// These should be obfuscated out when sethook is never called

View File

@@ -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;

View File

@@ -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 ) ) )

View File

@@ -1 +1 @@
version: 1.0
version: 1.0.1