From: Timo Sirainen Date: Wed, 5 May 2021 09:45:25 +0000 (+0300) Subject: lib: abort() on unexpected exit() X-Git-Tag: 2.3.16~160 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=f550663b374792e8dbac00c7cce1b2b0b88cddd3;p=thirdparty%2Fdovecot%2Fcore.git lib: abort() on unexpected exit() This can especially be useful in catching bugs in Lua script that could unexpectedly exit. --- diff --git a/src/lib-master/master-service.c b/src/lib-master/master-service.c index 703bf44d9b..017a4a2894 100644 --- a/src/lib-master/master-service.c +++ b/src/lib-master/master-service.c @@ -661,6 +661,9 @@ void master_service_init_finish(struct master_service *service) i_assert(!service->init_finished); service->init_finished = TRUE; + /* From now on we'll abort() if exit() is called unexpectedly. */ + lib_set_clean_exit(FALSE); + /* set default signal handlers */ if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) sigint_flags |= LIBSIG_FLAG_RESTART; diff --git a/src/lib/failures.c b/src/lib/failures.c index 4a9abd68f7..ab94700296 100644 --- a/src/lib/failures.c +++ b/src/lib/failures.c @@ -516,6 +516,7 @@ void i_panic(const char *format, ...) struct failure_context ctx; va_list args; + lib_set_clean_exit(TRUE); i_zero(&ctx); ctx.type = LOG_TYPE_PANIC; @@ -530,6 +531,7 @@ void i_fatal(const char *format, ...) struct failure_context ctx; va_list args; + lib_set_clean_exit(TRUE); i_zero(&ctx); ctx.type = LOG_TYPE_FATAL; ctx.exit_status = FATAL_DEFAULT; @@ -545,6 +547,7 @@ void i_fatal_status(int status, const char *format, ...) struct failure_context ctx; va_list args; + lib_set_clean_exit(TRUE); i_zero(&ctx); ctx.type = LOG_TYPE_FATAL; ctx.exit_status = status; diff --git a/src/lib/lib.c b/src/lib/lib.c index ab08da66e9..bd2da917c1 100644 --- a/src/lib/lib.c +++ b/src/lib/lib.c @@ -29,6 +29,7 @@ struct atexit_callback { }; static ARRAY(struct atexit_callback) atexit_callbacks = ARRAY_INIT; +static bool lib_clean_exit; #undef i_unlink int i_unlink(const char *path, const char *source_fname, @@ -132,6 +133,31 @@ static void lib_open_non_stdio_dev_null(void) fd_close_on_exec(dev_null_fd, TRUE); } +void lib_set_clean_exit(bool set) +{ + lib_clean_exit = set; +} + +void lib_exit(int status) +{ + lib_set_clean_exit(TRUE); + exit(status); +} + +static void lib_atexit_handler(void) +{ + /* We're already in exit code path. Avoid using any functions that + might cause strange breakage. Especially anything that could call + exit() again could cause infinite looping in some OSes. */ + if (!lib_clean_exit) { + const char *error = "Unexpected exit - converting to abort\n"; + if (write(STDERR_FILENO, error, strlen(error)) < 0) { + /* ignore */ + } + abort(); + } +} + void lib_init(void) { i_assert(!lib_initialized); @@ -143,6 +169,13 @@ void lib_init(void) event_filter_init(); var_expand_extensions_init(); + /* Default to clean exit. Otherwise there would be too many accidents + with e.g. command line parsing errors that try to return instead + of using lib_exit(). master_service_init_finish() will change this + again to be FALSE. */ + lib_set_clean_exit(TRUE); + atexit(lib_atexit_handler); + lib_initialized = TRUE; } @@ -168,4 +201,6 @@ void lib_deinit(void) failures_deinit(); process_title_deinit(); random_deinit(); + + lib_clean_exit = TRUE; } diff --git a/src/lib/lib.h b/src/lib/lib.h index e16b4ce48c..9c3ca34ffb 100644 --- a/src/lib/lib.h +++ b/src/lib/lib.h @@ -81,7 +81,11 @@ void lib_atexit_priority(lib_atexit_callback_t *callback, int priority); /* Manually run the atexit callbacks. lib_deinit() also does this if not explicitly called. */ void lib_atexit_run(void); -#define lib_exit(status) exit(status) +/* Unless this or lib_deinit() is called, any unexpected exit() will result + in abort(). This can be helpful in catching unexpected exits. */ +void lib_set_clean_exit(bool set); +/* Same as lib_set_clean_exit(TRUE) followed by exit(status). */ +void lib_exit(int status) ATTR_NORETURN; void lib_init(void); bool lib_is_initialized(void); diff --git a/src/master/main.c b/src/master/main.c index a537b3a3cc..4eb126fd1a 100644 --- a/src/master/main.c +++ b/src/master/main.c @@ -885,6 +885,7 @@ int main(int argc, char *argv[]) pidfile_path = i_strconcat(set->base_dir, "/"MASTER_PID_FILE_NAME, NULL); + lib_set_clean_exit(TRUE); master_service_init_log(master_service); startup_early_errors_flush(); i_get_failure_handlers(&orig_fatal_callback, &orig_error_callback,