From ffbcadfb4197213d55222bca3ecc52606cd980f4 Mon Sep 17 00:00:00 2001 From: Roberto I Date: Fri, 5 Sep 2025 15:29:15 -0300 Subject: In C++, 'throw' must go to the correct handler. In C, we may have several "setjmp" nested, and the "longjmp" will go to the one given by the corresponding "jmp_buf". In C++, a "throw" will always go to the inner "catch". So, the "catch" must check whether it is the recipient of the "throw" and, if not, rethrow the exception to the outer level. --- ldo.c | 42 +++++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/ldo.c b/ldo.c index dff9488e..44937068 100644 --- a/ldo.c +++ b/ldo.c @@ -57,10 +57,18 @@ ** ======================================================= */ +/* chained list of long jump buffers */ +typedef struct lua_longjmp { + struct lua_longjmp *previous; + jmp_buf b; + volatile TStatus status; /* error code */ +} lua_longjmp; + + /* ** LUAI_THROW/LUAI_TRY define how Lua does exception handling. By ** default, Lua handles errors with exceptions when compiling as -** C++ code, with _longjmp/_setjmp when asked to use them, and with +** C++ code, with _longjmp/_setjmp when available (POSIX), and with ** longjmp/setjmp otherwise. */ #if !defined(LUAI_THROW) /* { */ @@ -69,38 +77,38 @@ /* C++ exceptions */ #define LUAI_THROW(L,c) throw(c) -#define LUAI_TRY(L,c,f,ud) \ - try { (f)(L, ud); } catch(...) { if ((c)->status == 0) (c)->status = -1; } -#define luai_jmpbuf int /* dummy field */ + +static void LUAI_TRY (lua_State *L, lua_longjmp *c, Pfunc f, void *ud) { + try { + f(L, ud); /* call function protected */ + } + catch (lua_longjmp *c1) { /* Lua error */ + if (c1 != c) /* not the correct level? */ + throw; /* rethrow to upper level */ + } + catch (...) { /* non-Lua exception */ + c->status = -1; /* create some error code */ + } +} + #elif defined(LUA_USE_POSIX) /* }{ */ -/* in POSIX, try _longjmp/_setjmp (more efficient) */ +/* in POSIX, use _longjmp/_setjmp (more efficient) */ #define LUAI_THROW(L,c) _longjmp((c)->b, 1) #define LUAI_TRY(L,c,f,ud) if (_setjmp((c)->b) == 0) ((f)(L, ud)) -#define luai_jmpbuf jmp_buf #else /* }{ */ /* ISO C handling with long jumps */ #define LUAI_THROW(L,c) longjmp((c)->b, 1) #define LUAI_TRY(L,c,f,ud) if (setjmp((c)->b) == 0) ((f)(L, ud)) -#define luai_jmpbuf jmp_buf #endif /* } */ #endif /* } */ - -/* chain list of long jump buffers */ -struct lua_longjmp { - struct lua_longjmp *previous; - luai_jmpbuf b; - volatile TStatus status; /* error code */ -}; - - void luaD_seterrorobj (lua_State *L, TStatus errcode, StkId oldtop) { if (errcode == LUA_ERRMEM) { /* memory error? */ setsvalue2s(L, oldtop, G(L)->memerrmsg); /* reuse preregistered msg. */ @@ -151,7 +159,7 @@ l_noret luaD_throwbaselevel (lua_State *L, TStatus errcode) { TStatus luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) { l_uint32 oldnCcalls = L->nCcalls; - struct lua_longjmp lj; + lua_longjmp lj; lj.status = LUA_OK; lj.previous = L->errorJmp; /* chain new error handler */ L->errorJmp = &lj; -- cgit v1.2.3-55-g6feb