bug-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] completion display interrupt leak handling


From: Grisha Levit
Subject: [PATCH] completion display interrupt leak handling
Date: Sat, 17 Jun 2023 04:28:41 -0400

When readline's display of completion matches is interrupted, the match
list is only freed for the '?' completion type but not for '!' and '@'
types.  I couldn't find a specific reason for that to be the case so
hope this patch is an OK fix.

Also add freeing saved_line_buffer from rl_complete_internal to the
signal handler and freeing of matches in one spot where menu completion
doesn't do it.


* lib/readline/complete.c
- complete_sigcleanarg_t: new struct to hold _rl_complete_sigcleanup
  argument
- _rl_complete_sigcleanup: use new struct instead of *matches pointer,
  now also handles freeing saved_line
- rl_complete_internal: set up _rl_sigcleanup whenever display_matches
  is called so we no longer leak matches and saved_line_buffer when
  getting a SIGINT
- rl_menu_complete: free contents of matches instead of just pointer
  when completion-query-items exceeded
---
 lib/readline/complete.c | 61 ++++++++++++++++++++++++++---------------
 1 file changed, 39 insertions(+), 22 deletions(-)

diff --git a/lib/readline/complete.c b/lib/readline/complete.c
index bf7cc856..f8f08aa6 100644
--- a/lib/readline/complete.c
+++ b/lib/readline/complete.c
@@ -494,12 +494,19 @@ _rl_reset_completion_state (void)
   rl_completion_quote_character = 0;
 }

+typedef struct {
+    char **matches;
+    char *saved_line;
+} complete_sigcleanarg_t;
+
 static void
 _rl_complete_sigcleanup (int sig, void *ptr)
 {
+  complete_sigcleanarg_t *arg = ptr;
   if (sig == SIGINT) /* XXX - for now */
     {
-      _rl_free_match_list ((char **)ptr);
+      _rl_free_match_list (arg->matches);
+      FREE (arg->saved_line);
       _rl_complete_display_matches_interrupt = 1;
     }
 }
@@ -2008,7 +2015,8 @@ rl_complete_internal (int what_to_do)
   int start, end, delimiter, found_quote, i, nontrivial_lcd;
   char *text, *saved_line_buffer;
   char quote_char;
-  int tlen, mlen, saved_last_completion_failed;
+  int tlen, mlen, saved_last_completion_failed, do_display;
+  complete_sigcleanarg_t cleanarg;

   RL_SETSTATE(RL_STATE_COMPLETING);

@@ -2088,6 +2096,8 @@ rl_complete_internal (int what_to_do)
   if (matches && matches[0] && *matches[0])
     last_completion_failed = 0;

+  do_display = 0;
+
   switch (what_to_do)
     {
     case TAB:
@@ -2121,13 +2131,13 @@ rl_complete_internal (int what_to_do)
  {
    if (what_to_do == '!')
      {
-       display_matches (matches);
+       do_display = 1;
        break;
      }
    else if (what_to_do == '@')
      {
        if (nontrivial_lcd == 0)
- display_matches (matches);
+ do_display = 1;
        break;
      }
    else if (rl_editing_mode != vi_mode)
@@ -2151,23 +2161,7 @@ rl_complete_internal (int what_to_do)
    append_to_match (matches[0], delimiter, quote_char, nontrivial_lcd);
    break;
  }
-
-      if (rl_completion_display_matches_hook == 0)
- {
-   _rl_sigcleanup = _rl_complete_sigcleanup;
-   _rl_sigcleanarg = matches;
-   _rl_complete_display_matches_interrupt = 0;
- }
-      display_matches (matches);
-      if (_rl_complete_display_matches_interrupt)
-        {
-          matches = 0; /* already freed by rl_complete_sigcleanup */
-          _rl_complete_display_matches_interrupt = 0;
-   if (rl_signal_event_hook)
-     (*rl_signal_event_hook) (); /* XXX */
-        }
-      _rl_sigcleanup = 0;
-      _rl_sigcleanarg = 0;
+      do_display = 1;
       break;

     default:
@@ -2180,6 +2174,29 @@ rl_complete_internal (int what_to_do)
       return 1;
     }

+  if (do_display)
+    {
+      if (rl_completion_display_matches_hook == 0)
+ {
+   _rl_sigcleanup = _rl_complete_sigcleanup;
+   cleanarg.matches = matches;
+   cleanarg.saved_line = saved_line_buffer;
+   _rl_sigcleanarg = &cleanarg;
+   _rl_complete_display_matches_interrupt = 0;
+ }
+      display_matches (matches);
+      if (_rl_complete_display_matches_interrupt)
+ {
+   matches = 0; /* already freed by rl_complete_sigcleanup */
+   saved_line_buffer = 0;
+   _rl_complete_display_matches_interrupt = 0;
+   if (rl_signal_event_hook)
+     (*rl_signal_event_hook) (); /* XXX */
+ }
+      _rl_sigcleanup = 0;
+      _rl_sigcleanarg = 0;
+    }
+
   _rl_free_match_list (matches);

   /* Check to see if the line has changed through all of this
manipulation. */
@@ -2864,7 +2881,7 @@ rl_menu_complete (int count, int ignore)
    if (rl_completion_query_items > 0 && match_list_size >=
rl_completion_query_items)
      {
        rl_ding ();
-       FREE (matches);
+       _rl_free_match_list (matches);
        matches = (char **)0;
        full_completion = 1;
        return (0);

Attachment: 0001-improve-completion-interrupt-handling.patch
Description: Text Data


reply via email to

[Prev in Thread] Current Thread [Next in Thread]