Lua 和例外處理入侵注意事項 |
|
截至作為 C++ 建構的 5.1 版。
struct lua_longjmp { struct lua_longjmp *previous; int dummy; volatile int status; };它的作用是追蹤受保護的呼叫堆疊。我們從一個空的全球緩衝器開始。
// chain a new local buffer, status = 0 // global buffer now points to it try { // call } catch (...) { // force local status to non 0 (e.g. -1) } // restore global buffer // return local status
// if empty global buffer then panic // store status in global buffer // throw its address !
如果它們真的都沒有在 Lua 層級被捕捉,後來捕捉它們將會從 Lua 的呼叫堆疊中猛烈解纏,讓我們得到不一致的 Lua 狀態。這就是我當時調整 Lua 5.0.2 的情況。
為了確保 Lua 狀態一致且同時將例外傳遞到另一端,我們需要將它的副本儲存在安全的地方,正常解纏到最上層,最後拋出副本。然而,因為 catch 會比對類型(Stroustrup 14.3),當我們 `catch (...)` 時我們就會失去類型資訊,以及複製一般例外的能力。
為了實作上面討論的複製機制,我們可以將異類例外的類型範圍縮小到標準的 `std::exception`。如果程式設計師需要捕捉其他例外,他可以將它們包進 `std::exception` 子類別。其餘的例外仍必須默默忽略。
這個解決方案的優點在於其簡潔,且能良好運作於層級式例外類別(每個根類別有一個包裝器)。然而,它僅限於雙方都能同意 `std::exception` 包裝的情況。
注意:這表示包裝器產生器需要適應這個架構。
作為一個暫時性的解決方案,你也可以將例外空間縮小到一組自訂例外,也就是在 Lua 建置時間手動調整。
待辦事項:檢查 `std::exception` 的副本
回過頭來看,它似乎是我們這個案例的適當解決方案,對於休閒應用程式應該也足夠。但它需要在錯誤系統之間轉換,因此會有重複的部分。
如果 Lua 原始碼變得(或分支)防例外,我們就能讓它從 Lua 捕捉 C++ 例外,透過明確的方式或透過繫結到最終的 Lua 例外架構。在下一個區塊中概述一個解決方案。
catch (struct lua_longjump * p_lj) { // force local status to non 0 } catch (...) { // do soft unwinding throw }
注意:`p_lj` 應該指向目前的 `lj`。
待辦事項:斷言那件事。
這應該可以確保我們不會吃下外星的例外,除非某人扭曲的決定從她的程式庫四處拋出 `(struct lua_longjump)*`。
要設計我們的演算法,我們需要找出 `pcall` 取得並釋放的要點資源。
pcall 堆疊大綱
pcall 巢狀時,頂層和底層會包覆。
D_pcall 清除
if (status != 0) { /* an error occurred? */ StkId oldtop = restorestack(L, old_top); luaF_close(L, oldtop); /* close eventual pending closures */ luaD_seterrorobj(L, status, oldtop); L->nCcalls = oldnCcalls; L->ci = restoreci(L, old_ci); L->base = L->ci->base; L->savedpc = L->ci->savedpc; L->allowhook = old_allowhooks; restore_stack_limit(L); } L->errfunc = old_errfunc;
它會還原之前取得的狀態
// ptrdiff_t old_top, ptrdiff_t ef unsigned short oldnCcalls = L->nCcalls; ptrdiff_t old_ci = saveci(L, L->ci); lu_byte old_allowhooks = L->allowhook; ptrdiff_t old_errfunc = L->errfunc; L->errfunc = ef;
現在,我們可以使用資源取得就是初始化的模式,在物件毀損時自動執行清除碼。這是與例外整合的自然方法(Stroustrup 14.4.1)。
Stroustrup 14.9 是基本要素。