From: Tomas Krizek Date: Fri, 19 Mar 2021 15:47:34 +0000 (+0100) Subject: daemon: allow kr_assume() configuration X-Git-Tag: v5.4.0~18^2~14 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=30472874c9636c7b58be71b299f3d0e49392be0b;p=thirdparty%2Fknot-resolver.git daemon: allow kr_assume() configuration - add lua options debugging.assumption_abort and debugging.assumption_fork to make the behaviour configurable - select default values based on meson buildtype: - debug/debugoptimized (default, e.g. used in CI) - abort and don't fork - plain/release - don't abort, but fork if abort is user-configured --- diff --git a/.luacheckrc b/.luacheckrc index 67bc18f6b..885b29e78 100644 --- a/.luacheckrc +++ b/.luacheckrc @@ -38,6 +38,7 @@ new_read_globals = { 'reorder_RR', 'option', 'env', + 'debugging', 'kres', 'libknot_SONAME', 'libzscanner_SONAME', diff --git a/daemon/engine.c b/daemon/engine.c index 9ac8445b1..c63ea2a04 100644 --- a/daemon/engine.c +++ b/daemon/engine.c @@ -85,6 +85,7 @@ static int l_help(lua_State *L) "modules\n modules configuration\n" "kres\n resolver services\n" "trust_anchors\n configure trust anchors\n" + "debugging\n debugging configuration\n" ; lua_pushstring(L, help_str); return 1; diff --git a/daemon/lua/kres-gen.lua b/daemon/lua/kres-gen.lua index 679d028cb..e520790f1 100644 --- a/daemon/lua/kres-gen.lua +++ b/daemon/lua/kres-gen.lua @@ -299,7 +299,11 @@ struct kr_server_selection { void (*error)(struct kr_query *, const struct kr_transport *, enum kr_selection_error); struct local_state *local_state; }; + kr_layer_t kr_layer_t_static; +_Bool kr_dbg_assumption_abort; +_Bool kr_dbg_assumption_fork; + typedef int32_t (*kr_stale_cb)(int32_t ttl, const knot_dname_t *owner, uint16_t type, const struct kr_query *qry); diff --git a/daemon/lua/kres-gen.sh b/daemon/lua/kres-gen.sh index 52539a5ed..9263d4ee4 100755 --- a/daemon/lua/kres-gen.sh +++ b/daemon/lua/kres-gen.sh @@ -131,8 +131,12 @@ ${CDEFS} ${LIBKRES} types <<-EOF struct kr_server_selection EOF -# a static variable; the line might not be simple to generate -printf "kr_layer_t kr_layer_t_static;" +# static variables; these lines might not be simple to generate +printf " +kr_layer_t kr_layer_t_static; +_Bool kr_dbg_assumption_abort; +_Bool kr_dbg_assumption_fork; +" printf " typedef int32_t (*kr_stale_cb)(int32_t ttl, const knot_dname_t *owner, uint16_t type, diff --git a/daemon/lua/sandbox.lua.in b/daemon/lua/sandbox.lua.in index 993f36d5e..0c86c4242 100644 --- a/daemon/lua/sandbox.lua.in +++ b/daemon/lua/sandbox.lua.in @@ -129,6 +129,22 @@ setmetatable(env, { __index = function (_, k) return os.getenv(k) end }) +debugging = {} +setmetatable(debugging, { + __index = function(_, k) + if k == 'assumption_abort' then return ffi.C.kr_dbg_assumption_abort + elseif k == 'assumption_fork' then return ffi.C.kr_dbg_assumption_fork + else panic('invalid debugging option: ' .. tostring(k)) + end + end, + __newindex = function(_, k, v) + if k == 'assumption_abort' then ffi.C.kr_dbg_assumption_abort = v + elseif k == 'assumption_fork' then ffi.C.kr_dbg_assumption_fork = v + else panic('invalid debugging option: ' .. tostring(k)) + end + end +}) + -- Quick access to interfaces -- `net.` => `net.interfaces()[iface]` -- `net = {addr1, ..}` => `net.listen(name, addr1)` @@ -406,7 +422,10 @@ setmetatable(cache, { -- Make sandboxed environment local function make_sandbox(defined) - local __protected = { worker = true, env = true, modules = true, cache = true, net = true, trust_anchors = true } + local __protected = { + worker = true, env = true, debugging = true, modules = true, + cache = true, net = true, trust_anchors = true + } -- Compute and export the list of top-level names (hidden otherwise) local nl = "" diff --git a/lib/utils.c b/lib/utils.c index f61ec40fd..85c929932 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -38,7 +38,8 @@ /* Logging & debugging */ bool kr_verbose_status = false; -bool kr_debug_assumption = true; +bool kr_dbg_assumption_abort = DBG_ASSUMPTION_ABORT; +bool kr_dbg_assumption_fork = DBG_ASSUMPTION_FORK; void kr_fail(bool is_fatal, const char *expr, const char *func, const char *file, int line) { @@ -47,8 +48,10 @@ void kr_fail(bool is_fatal, const char *expr, const char *func, const char *file else kr_log_error("assumption \"%s\" failed in %s@%s:%d\n", expr, func, file, line); - if (is_fatal || (kr_debug_assumption && fork() == 0)) + if (is_fatal || (kr_dbg_assumption_abort && !kr_dbg_assumption_fork)) abort(); + else if (kr_dbg_assumption_abort && kr_dbg_assumption_fork) + fork() == 0 ? abort() : (void)0; } /* diff --git a/lib/utils.h b/lib/utils.h index 8316a5bcd..588405000 100644 --- a/lib/utils.h +++ b/lib/utils.h @@ -61,8 +61,16 @@ typedef void (*trace_log_f)(const struct kr_request *request, const char *msg); #define kr_assume(expression) kr_assume_func((expression), #expression, \ __func__, __FILE__, __LINE__) -/** Whether kr_assume() checks should result fork and abort. */ -KR_EXPORT extern bool kr_debug_assumption; +/** Whether kr_assume() checks should abort. */ +KR_EXPORT extern bool kr_dbg_assumption_abort; + +/** Whether kr_assume() should fork the process before issuing abort (if configured). + * + * This can be useful for debugging rare edge-cases in production. When both + * kr_debug_assumption_abort and kr_debug_assumption_fork are set to true, it is + * possible to both obtain a coredump (from forked child) and recover from the + * non-fatal error in the parent process. */ +KR_EXPORT extern bool kr_dbg_assumption_fork; /** Use kr_require() and kr_assume() instead of directly this function. */ KR_EXPORT KR_COLD void kr_fail(bool is_fatal, const char* expr, const char *func, diff --git a/meson.build b/meson.build index 52c7edf72..809fecc27 100644 --- a/meson.build +++ b/meson.build @@ -178,6 +178,8 @@ conf_data.set('ENABLE_SENDMMSG', sendmmsg.to_int()) conf_data.set('ENABLE_XDP', xdp.to_int()) conf_data.set('ENABLE_CAP_NG', capng.found().to_int()) conf_data.set('ENABLE_DOH2', nghttp2.found().to_int()) +conf_data.set('DBG_ASSUMPTION_ABORT', get_option('debug').to_int()) +conf_data.set('DBG_ASSUMPTION_FORK', (not get_option('debug')).to_int()) kresconfig = configure_file( output: 'kresconfig.h',