From 5a4e13eda683f1f0182035b7d56666465fd1c7f8 Mon Sep 17 00:00:00 2001 From: Marko Lindqvist Date: Sun, 26 Jun 2022 01:57:54 +0300 Subject: [PATCH 55/55] Rework readline cleanup on server quit - Introduce readline_atexit() - Call rl_callback_handler_remove() from readline_atexit() - Do not register rl_callback_handler_remove() as atexit function - Free last input line (the one where the "quit" command was given) in readline_atexit() - Call readline_atexit() from server_quit(), before exit() This clear things before any atexit handlers installed by tools wrapping freeciv - Also register readline_atexit() as atexit function, to make sure it gets called at least once even when server_quit() is bypassed for any reason See osdn #44948 Signed-off-by: Marko Lindqvist --- server/sernet.c | 44 +++++++++++++++++++++++++++++++++++--------- server/sernet.h | 6 ++++-- server/srv_main.c | 1 + 3 files changed, 40 insertions(+), 11 deletions(-) diff --git a/server/sernet.c b/server/sernet.c index 9a53f4eb5e..686d13efeb 100644 --- a/server/sernet.c +++ b/server/sernet.c @@ -161,18 +161,15 @@ static void handle_stdin_close(void) #define HISTORY_LENGTH 100 static char *history_file = NULL; - static bool readline_handled_input = FALSE; - static bool readline_initialized = FALSE; +static char *current_internal = NULL; /*************************************************************************//** Readline callback for input. *****************************************************************************/ static void handle_readline_input_callback(char *line) { - char *line_internal; - if (no_input) { return; } @@ -187,15 +184,44 @@ static void handle_readline_input_callback(char *line) } con_prompt_enter(); /* just got an 'Enter' hit */ - line_internal = local_to_internal_string_malloc(line); - (void) handle_stdin_input(NULL, line_internal); - free(line_internal); - free(line); + current_internal = local_to_internal_string_malloc(line); + free(line); /* This is already freed if we exit() with /quit command */ + (void) handle_stdin_input(NULL, current_internal); + free(current_internal); /* Since handle_stdin_input() returned, + * we can be sure this was not freed in atexit. */ + current_internal = NULL; readline_handled_input = TRUE; } #endif /* FREECIV_HAVE_LIBREADLINE */ +/*************************************************************************//** + Clear readline stuff at exit. To cater for as many different cases as + possible, we call this both like any function call from server_quit() + before exit(), and as a atexit handler. Former is to get everything + cleared already before exit(), before any other atexit handler comes + to play. Latter is to make sure that the function gets called also when + in those rare cases where we exit some other way than server_quit() - + that's important for always restoring terminal to a working state. + + That means that in usual case this function gets called twice. + Make sure that it doesn't try double frees or similar when that happens. +*****************************************************************************/ +void readline_atexit(void) +{ +#ifdef FREECIV_HAVE_READLINE + if (readline_initialized) { + rl_callback_handler_remove(); + readline_initialized = FALSE; + } + + if (current_internal != NULL) { + free(current_internal); + current_internal = NULL; + } +#endif /* FREECIV_HAVE_LIBREADLINE */ +} + /*************************************************************************//** Close the connection (very low-level). See also server_conn_close_callback(). @@ -542,7 +568,7 @@ enum server_events server_sniff_all_input(void) rl_attempted_completion_function = freeciv_completion; readline_initialized = TRUE; - atexit(rl_callback_handler_remove); + atexit(readline_atexit); } } #endif /* FREECIV_HAVE_LIBREADLINE */ diff --git a/server/sernet.h b/server/sernet.h index 015844d3b8..fcbe8e60ef 100644 --- a/server/sernet.h +++ b/server/sernet.h @@ -1,4 +1,4 @@ -/********************************************************************** +/*********************************************************************** Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -42,8 +42,10 @@ int server_make_connection(int new_sock, void handle_conn_pong(struct connection *pconn); void handle_client_heartbeat(struct connection *pconn); +void readline_atexit(void); + #ifdef __cplusplus } #endif /* __cplusplus */ -#endif /* FC__SERNET_H */ +#endif /* FC__SERNET_H */ diff --git a/server/srv_main.c b/server/srv_main.c index da156a4a7f..957496883e 100644 --- a/server/srv_main.c +++ b/server/srv_main.c @@ -1877,6 +1877,7 @@ void fc__noreturn server_quit(void) free_nls(); con_log_close(); cmdline_option_values_free(); + readline_atexit(); exit(EXIT_SUCCESS); } -- 2.35.1