From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from smtpng2.m.smailru.net (smtpng2.m.smailru.net [94.100.179.3]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dev.tarantool.org (Postfix) with ESMTPS id AAAE84696C4 for ; Thu, 30 Jan 2020 19:42:45 +0300 (MSK) From: Leonid Vasiliev Date: Thu, 30 Jan 2020 19:42:36 +0300 Message-Id: <772d30cbf873fca91ceef260d5c82c54ee0cbd90.1580401020.git.lvasiliev@tarantool.org> In-Reply-To: References: In-Reply-To: References: Subject: [Tarantool-patches] [PATCH 1/2] Add a Lua backtrace to error List-Id: Tarantool development patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: alexander.turenko@tarantool.org Cc: tarantool-patches@dev.tarantool.org In accordance with https://github.com/tarantool/tarantool/issues/4398 we want to have a Lua backtrace for the box.error Needed for #4398 --- src/lib/core/diag.c | 1 + src/lib/core/diag.h | 1 + src/lib/core/exception.cc | 1 + src/lua/error.c | 42 ++++++++++++++++++++++++++++++++++++++- src/lua/error.h | 3 +++ src/lua/error.lua | 20 ++++++++++++++----- test/app/fiber.result | 35 ++++++++++++++++++++++++-------- test/app/fiber.test.lua | 11 +++++++++- test/box/misc.result | 34 +++++++++++++++++++++++-------- test/box/misc.test.lua | 10 +++++++++- 10 files changed, 134 insertions(+), 24 deletions(-) diff --git a/src/lib/core/diag.c b/src/lib/core/diag.c index c350abb4a..d13f329ad 100644 --- a/src/lib/core/diag.c +++ b/src/lib/core/diag.c @@ -53,6 +53,7 @@ error_create(struct error *e, e->line = 0; } e->errmsg[0] = '\0'; + e->lua_bt = NULL; } struct diag * diff --git a/src/lib/core/diag.h b/src/lib/core/diag.h index f763957c2..4a39fe16b 100644 --- a/src/lib/core/diag.h +++ b/src/lib/core/diag.h @@ -84,6 +84,7 @@ struct error { char file[DIAG_FILENAME_MAX]; /* Error description. */ char errmsg[DIAG_ERRMSG_MAX]; + char *lua_bt; }; static inline void diff --git a/src/lib/core/exception.cc b/src/lib/core/exception.cc index 76dcea553..d316d9bb3 100644 --- a/src/lib/core/exception.cc +++ b/src/lib/core/exception.cc @@ -42,6 +42,7 @@ extern "C" { static void exception_destroy(struct error *e) { + free(e->lua_bt); delete (Exception *) e; } diff --git a/src/lua/error.c b/src/lua/error.c index d82e78dc4..11afe97f8 100644 --- a/src/lua/error.c +++ b/src/lua/error.c @@ -34,8 +34,44 @@ #include #include "utils.h" +#include + static int CTID_CONST_STRUCT_ERROR_REF = 0; +/* + * Memory for the traceback string is obtained with malloc, + * and can be freed with free. +*/ +static char* +traceback (lua_State *L) { + int top = lua_gettop(L); + + lua_getfield(L, LUA_GLOBALSINDEX, "debug"); + if (!lua_istable(L, -1)) { + lua_settop(L, top); + return NULL; + } + lua_getfield(L, -1, "traceback"); + if (!lua_isfunction(L, -1)) { + lua_settop(L, top); + return NULL; + } + + // call debug.traceback + lua_call(L, 0, 1); + + // get result of the debug.traceback call + if (!lua_isstring(L, -1)) { + lua_settop(L, top); + return NULL; + } + + char *bt = strdup(lua_tostring(L, -1)); + lua_settop(L, top); + + return bt; +} + struct error * luaL_iserror(struct lua_State *L, int narg) { @@ -53,7 +89,7 @@ luaL_iserror(struct lua_State *L, int narg) return e; } -static struct error * +struct error * luaL_checkerror(struct lua_State *L, int narg) { struct error *error = luaL_iserror(L, narg); @@ -85,6 +121,10 @@ luaT_pusherror(struct lua_State *L, struct error *e) * then set the finalizer. */ error_ref(e); + + if (e->lua_bt == NULL) + e->lua_bt = traceback(L); + assert(CTID_CONST_STRUCT_ERROR_REF != 0); struct error **ptr = (struct error **) luaL_pushcdata(L, CTID_CONST_STRUCT_ERROR_REF); diff --git a/src/lua/error.h b/src/lua/error.h index 64fa5eba3..16cdaf7fe 100644 --- a/src/lua/error.h +++ b/src/lua/error.h @@ -65,6 +65,9 @@ luaT_pusherror(struct lua_State *L, struct error *e); struct error * luaL_iserror(struct lua_State *L, int narg); +struct error * +luaL_checkerror(struct lua_State *L, int narg); + void tarantool_lua_error_init(struct lua_State *L); diff --git a/src/lua/error.lua b/src/lua/error.lua index 7f249864a..f296ecf94 100644 --- a/src/lua/error.lua +++ b/src/lua/error.lua @@ -24,6 +24,7 @@ struct error { char _file[DIAG_FILENAME_MAX]; /* Error description. */ char _errmsg[DIAG_ERRMSG_MAX]; + char *lua_bt; }; char * @@ -83,10 +84,18 @@ local function error_trace(err) return {} end return { - { file = ffi.string(err._file), line = tonumber(err._line) }; + { file = ffi.string(err._file), line = tonumber(err._line) } } end +local function error_backtrace(err) + local result = "Backtrace is absent" + if err.lua_bt ~= ffi.nullptr then + result = ffi.string(err.lua_bt) + end + return result +end + local function error_errno(err) local e = err._saved_errno if e == 0 then @@ -96,10 +105,11 @@ local function error_errno(err) end local error_fields = { - ["type"] = error_type; - ["message"] = error_message; - ["trace"] = error_trace; - ["errno"] = error_errno; + ["type"] = error_type, + ["message"] = error_message, + ["trace"] = error_trace, + ["errno"] = error_errno, + ["bt"] = error_backtrace } local function error_unpack(err) diff --git a/test/app/fiber.result b/test/app/fiber.result index 6d9604ad8..d25a266d5 100644 --- a/test/app/fiber.result +++ b/test/app/fiber.result @@ -1036,14 +1036,33 @@ st; --- - false ... -e:unpack(); ---- -- type: ClientError - code: 1 - message: Illegal parameters, oh my - trace: - - file: '[string "function err() box.error(box.error.ILLEGAL_PA..."]' - line: 1 +unpack_res = e:unpack(); +--- +... +unpack_res['code'] == 1; +--- +- true +... +unpack_res['trace'][1]['file'] == '[string "function err()' .. + ' box.error(box.error.ILLEGAL_PA..."]'; +--- +- true +... +unpack_res['trace'][1]['line'] == 1; +--- +- true +... +unpack_res['type'] == 'ClientError'; +--- +- true +... +unpack_res['message'] == 'Illegal parameters, oh my'; +--- +- true +... +unpack_res['bt'] == e.bt; +--- +- true ... flag = false; --- diff --git a/test/app/fiber.test.lua b/test/app/fiber.test.lua index 6df210d9c..c9cbd7bee 100644 --- a/test/app/fiber.test.lua +++ b/test/app/fiber.test.lua @@ -428,7 +428,16 @@ function test1() end; st, e = test1(); st; -e:unpack(); + +unpack_res = e:unpack(); + +unpack_res['code'] == 1; +unpack_res['trace'][1]['file'] == '[string "function err()' .. + ' box.error(box.error.ILLEGAL_PA..."]'; +unpack_res['trace'][1]['line'] == 1; +unpack_res['type'] == 'ClientError'; +unpack_res['message'] == 'Illegal parameters, oh my'; +unpack_res['bt'] == e.bt; flag = false; function test2() diff --git a/test/box/misc.result b/test/box/misc.result index 5ac5e0f26..b94ba5058 100644 --- a/test/box/misc.result +++ b/test/box/misc.result @@ -125,14 +125,32 @@ e --- - Illegal parameters, bla bla ... -e:unpack() ---- -- type: ClientError - code: 1 - message: Illegal parameters, bla bla - trace: - - file: '[C]' - line: 4294967295 +unpack_res = e:unpack() +--- +... +unpack_res['code'] == 1 +--- +- true +... +unpack_res['trace'][1]['file'] == '[C]' +--- +- true +... +unpack_res['trace'][1]['line'] == 4294967295 +--- +- true +... +unpack_res['type'] == 'ClientError' +--- +- true +... +unpack_res['message'] == 'Illegal parameters, bla bla' +--- +- true +... +unpack_res['bt'] == e.bt +--- +- true ... e.type --- diff --git a/test/box/misc.test.lua b/test/box/misc.test.lua index e1c2f990f..e82ac2cf9 100644 --- a/test/box/misc.test.lua +++ b/test/box/misc.test.lua @@ -35,7 +35,15 @@ box.error(box.error.ILLEGAL_PARAMS, "bla bla") box.error() e = box.error.last() e -e:unpack() + +unpack_res = e:unpack() +unpack_res['code'] == 1 +unpack_res['trace'][1]['file'] == '[C]' +unpack_res['trace'][1]['line'] == 4294967295 +unpack_res['type'] == 'ClientError' +unpack_res['message'] == 'Illegal parameters, bla bla' +unpack_res['bt'] == e.bt + e.type e.code e.message -- 2.17.1