[Tarantool-patches] [PATCH 1/6] error: Add a Lua backtrace to error
Leonid Vasiliev
lvasiliev at tarantool.org
Tue Mar 24 15:45:59 MSK 2020
Lua bactrace was added to a tarantool error.
In accordance with https://github.com/tarantool/tarantool/issues/4398
we want to have a Lua backtrace for the box.error
@TarantoolBot document
Title: error.bt
Lua backtrace was added to a tarantool error.
Needed for #4398
---
src/lib/core/diag.c | 20 ++++++++++++++++++++
src/lib/core/diag.h | 5 +++++
src/lib/core/exception.cc | 1 +
src/lua/error.c | 45 ++++++++++++++++++++++++++++++++++++++++++++-
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, 160 insertions(+), 24 deletions(-)
diff --git a/src/lib/core/diag.c b/src/lib/core/diag.c
index c350abb..c392c1e 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 *
@@ -76,3 +77,22 @@ error_vformat_msg(struct error *e, const char *format, va_list ap)
vsnprintf(e->errmsg, sizeof(e->errmsg), format, ap);
}
+void
+error_set_lua_bt(struct error *e, const char *lua_bt)
+{
+ if (e == NULL)
+ return;
+
+ if (lua_bt == NULL) {
+ free(e->lua_bt);
+ e->lua_bt = NULL;
+ return;
+ }
+
+ size_t bt_len = strlen(lua_bt);
+ e->lua_bt = realloc(e->lua_bt, bt_len + 1);
+ if (e->lua_bt == NULL)
+ return;
+ strcpy(e->lua_bt, lua_bt);
+ return;
+}
diff --git a/src/lib/core/diag.h b/src/lib/core/diag.h
index f763957..c917871 100644
--- a/src/lib/core/diag.h
+++ b/src/lib/core/diag.h
@@ -84,6 +84,8 @@ struct error {
char file[DIAG_FILENAME_MAX];
/* Error description. */
char errmsg[DIAG_ERRMSG_MAX];
+ /* Lua backtrace */
+ char *lua_bt;
};
static inline void
@@ -126,6 +128,9 @@ error_format_msg(struct error *e, const char *format, ...);
void
error_vformat_msg(struct error *e, const char *format, va_list ap);
+void
+error_set_lua_bt(struct error *e, const char *lua_bt);
+
/**
* Diagnostics Area - a container for errors
*/
diff --git a/src/lib/core/exception.cc b/src/lib/core/exception.cc
index 76dcea5..d316d9b 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 d82e78d..3a12e20 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,13 @@ luaT_pusherror(struct lua_State *L, struct error *e)
* then set the finalizer.
*/
error_ref(e);
+
+ if (e->lua_bt == NULL) {
+ char *lua_bt = traceback(L);
+ error_set_lua_bt(e, lua_bt);
+ free(lua_bt);
+ }
+
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 64fa5eb..16cdaf7 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 7f24986..765ce73 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 7331f61..3908733 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 b8e9abc..f3616ec 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 047591b..f432d51 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 e1c2f99..e82ac2c 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.7.4
More information about the Tarantool-patches
mailing list