If SIGINT is received during the execution of a bind -x command, the memory allocated for the saved parser state is leaked and the READLINE_* variables remain in the environment
* pcomplete.c,bashline.c: - uw_restore_parser_state,uw_rl_set_signals: move from pcomplete.c to bashline.c * bashline.h: - extern declarations for uw_restore_parser_state, uw_rl_set_signals * bashline.c: - unbind_bindx_vars,uw_unbind_bindx_vars: new function to unbind shell variables set by bind -x commands - bash_execute_unix_command: use unbind_bindx_vars, add unwind-protects for rl_set_signals, restore_parser_state, unbind_bindx_vars The existing use of uw_restore_parser_state in gen_shell_function_matches creates a 'restrict' copy of the pointer to the saved parser state. I don't really understand why that is, so I didn't do that in bash_execute_unix_command, but wanted to note here just in case. --- bashline.c | 40 ++++++++++++++++++++++++++++++++++------ bashline.h | 3 +++ pcomplete.c | 12 ------------ 3 files changed, 37 insertions(+), 18 deletions(-) diff --git a/bashline.c b/bashline.c index 02f36e3a..70d6778f 100644 --- a/bashline.c +++ b/bashline.c @@ -4428,6 +4428,34 @@ readline_set_char_offset (int ind, int *varp) } } +void +uw_restore_parser_state (void *ps) +{ + restore_parser_state (ps); +} + +void +uw_rl_set_signals (void *ignore) +{ + rl_set_signals (); +} + +static void +unbind_bindx_vars (void) +{ + check_unbind_variable ("READLINE_LINE"); + check_unbind_variable ("READLINE_POINT"); + check_unbind_variable ("READLINE_MARK"); + check_unbind_variable ("READLINE_ARGUMENT"); + array_needs_making = 1; +} + +static void +uw_unbind_bindx_vars (void *ignore) +{ + unbind_bindx_vars (); +} + int bash_execute_unix_command (int count, int key) { @@ -4507,11 +4535,16 @@ bash_execute_unix_command (int count, int key) } array_needs_making = 1; + begin_unwind_frame ("bindx"); save_parser_state (&ps); + add_unwind_protect (uw_unbind_bindx_vars, NULL); + add_unwind_protect (uw_restore_parser_state, &ps); + add_unwind_protect (uw_rl_set_signals, NULL); rl_clear_signals (); r = parse_and_execute (savestring (cmd), "bash_execute_unix_command", SEVAL_NOHIST); rl_set_signals (); restore_parser_state (&ps); + discard_unwind_frame ("bindx"); v = find_variable ("READLINE_LINE"); maybe_make_readline_line (v ? value_cell (v) : 0); @@ -4524,12 +4557,7 @@ bash_execute_unix_command (int count, int key) if (v && legal_number (value_cell (v), &mi)) readline_set_char_offset (mi, &rl_mark); - check_unbind_variable ("READLINE_LINE"); - check_unbind_variable ("READLINE_POINT"); - check_unbind_variable ("READLINE_MARK"); - check_unbind_variable ("READLINE_ARGUMENT"); - array_needs_making = 1; - + unbind_bindx_vars (); /* and restore the readline buffer and display after command execution. */ /* If we clear the last line of the prompt above, redraw only that last line. If the command returns 124, we redraw unconditionally as in diff --git a/bashline.h b/bashline.h index d9fb7379..2079799a 100644 --- a/bashline.h +++ b/bashline.h @@ -56,6 +56,9 @@ extern char **bash_default_completion (const char *, int, int, int, int); extern void set_directory_hook (void); /* Used by programmable completion code. */ +extern void uw_rl_set_signals (void *); +extern void uw_restore_parser_state (void *); + extern char *command_word_completion_function (const char *, int); extern char *bash_groupname_completion_function (const char *, int); extern char *bash_servicename_completion_function (const char *, int); diff --git a/pcomplete.c b/pcomplete.c index 410a7b7d..717a1479 100644 --- a/pcomplete.c +++ b/pcomplete.c @@ -1030,18 +1030,6 @@ build_arg_list (const char *cmd, const char *cname, const char *text, WORD_LIST return ret; } -static void -uw_restore_parser_state (void *ps) -{ - restore_parser_state (ps); -} - -static void -uw_rl_set_signals (void *ignore) -{ - rl_set_signals (); -} - /* Build a command string with $0 == cs->funcname (function to execute for completion list) $1 == command name (command being completed) -- 2.41.0
0001-unwind-protect-for-bind-x-commands.patch
Description: Binary data