[Tarantool-patches] [PATCH 1/2] Add a Lua backtrace to error
Leonid Vasiliev
lvasiliev at tarantool.org
Thu Jan 30 19:42:36 MSK 2020
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 <fiber.h>
#include "utils.h"
+#include <string.h>
+
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
More information about the Tarantool-patches
mailing list