poke-devel
[Top][All Lists]
Advanced

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

Re: fix invalid uses of siglongjmp


From: Jose E. Marchesi
Subject: Re: fix invalid uses of siglongjmp
Date: Sun, 28 Jun 2020 12:39:16 +0200
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux)

Hi Bruno.

    In pk-repl.c there are three cases of invalid siglongjmp invocations
    (assuming a single-threaded poke).

Thanks for the patch and the explanation.
OK for master.


    To reproduce one of them, press Ctrl-D and then very quickly
    Ctrl-C. I see this:
    
      Type ".exit" to leave the program.
      (poke) 
      ^C
      (poke) .load gmo.pk
      /media/develdata/devel/inst-x86_64-64/share/poke/gmo.pk: Datei oder 
Verzeichnis nicht gefunden
      (poke) 
      *** stack smashing detected ***: ./poke/poke terminated
      Abgebrochen (Speicherabzug geschrieben)
    
    The three cases are:
      (1) If the user presses Ctrl-C between the moment the signal handler
          is installed and the moment the first sigsetjmp is terminated.
      (2) If the user presses Ctrl-C between the moment a round of the REP loop
          is terminated and the next round of the REP loop is started.
      (3) If the user presses Ctrl-C after the function pk_repl has terminated.
          (This is the scenario above.)
    
    In case (1) and (3), it is better for the program to behave like if no
    handler was installed, that is, terminate the program.
    
    In case (2), the user does not want to terminate poke; instead he wants
    to (reliably!) get at the poke prompt again.
    
    The attached proposed patch implements this. With it, I see this:
    
      Type ".exit" to leave the program.
      (poke) 
      ^C
    
    A remark regarding the use of 'volatile': 'volatile' is needed for every
    global variable that is accessed from a signal handler. (Think about the
    main thread and the signal handler being executed on different CPUs.
    Without 'volatile' and no memory barrier, the CPU that executes the main
    thread might never propagate changes to the variable to the other CPUs.)
    Unfortunately, I can't mark a sigjmpbuf variable as 'volatile' easily,
    without introducing compilation warnings...
    
    Bruno
    
    >From 5174f470b65a61496f66ff3227b8f2dea749fdc2 Mon Sep 17 00:00:00 2001
    From: Bruno Haible <bruno@clisp.org>
    Date: Sat, 27 Jun 2020 17:04:22 +0200
    Subject: [PATCH] Fix invalid uses of siglongjmp.
    
    * poke/pk-repl.c (ctrlc_buf_valid): New variable.
    (poke_sigint_handler): If ctrlc_buf_valid is false, terminate the process.
    (pk_repl): Set ctrlc_buf_valid to false before installing the signal handler
    and to true while ctrlc_buf is valid. Move the sigsetjmp invocation out of 
the
    loop.
    ---
     poke/pk-repl.c | 42 ++++++++++++++++++++++++++++++++----------
     1 file changed, 32 insertions(+), 10 deletions(-)
    
    diff --git a/poke/pk-repl.c b/poke/pk-repl.c
    index 08505cb..38a53a5 100644
    --- a/poke/pk-repl.c
    +++ b/poke/pk-repl.c
    @@ -37,7 +37,10 @@
     #include "pk-utils.h"
     #include "pk-map.h"
     
    -static sigjmp_buf ctrlc_buf;
    +/* The non-local entry point for reentering the REPL.  */
    +static sigjmp_buf /*volatile*/ ctrlc_buf;
    +/* When nonzero, ctrlc_buf contains a valid value.  */
    +static int volatile ctrlc_buf_valid;
     
     /* This function is called repeatedly by the readline library, when
        generating potential command line completions.
    @@ -202,13 +205,28 @@ banner (void)
     }
     
     static void
    -poke_sigint_handler (int status)
    +poke_sigint_handler (int sig)
     {
    -  rl_free_line_state ();
    -  rl_cleanup_after_signal ();
    -  rl_line_buffer[rl_point = rl_end = rl_mark = 0] = 0;
    -  printf ("\n");
    -  siglongjmp (ctrlc_buf, 1);
    +  if (ctrlc_buf_valid)
    +    {
    +      /* Abort the current command, and return to the REPL.  */
    +      rl_free_line_state ();
    +      rl_cleanup_after_signal ();
    +      rl_line_buffer[rl_point = rl_end = rl_mark = 0] = 0;
    +      printf ("\n");
    +      siglongjmp (ctrlc_buf, 1);
    +    }
    +  else
    +    {
    +      /* The default behaviour for SIGINT is to terminate the process.
    +         Let's do that here.  */
    +      struct sigaction sa;
    +      sa.sa_handler = SIG_DFL;
    +      sa.sa_flags = 0;
    +      sigemptyset (&sa.sa_mask);
    +      sigaction (SIGINT, &sa, NULL);
    +      raise (SIGINT);
    +    }
     }
     
     /* Return a copy of TEXT, with every instance of the space character
    @@ -272,11 +290,12 @@ pk_repl (void)
       banner ();
     
       /* Arrange for the current line to be cancelled on SIGINT.  */
    +  ctrlc_buf_valid = 0;
       struct sigaction sa;
       sa.sa_handler = poke_sigint_handler;
       sa.sa_flags = 0;
       sigemptyset (&sa.sa_mask);
    -  sigaction (SIGINT, &sa, 0);
    +  sigaction (SIGINT, &sa, NULL);
     
     #if defined HAVE_READLINE_HISTORY_H
       char *poke_history = NULL;
    @@ -300,13 +319,14 @@ pk_repl (void)
       rl_filename_quote_characters = " ";
       rl_filename_quoting_function = escape_metacharacters;
     
    +  sigsetjmp (ctrlc_buf, 1);
    +  ctrlc_buf_valid = 1;
    +
       while (!poke_exit_p)
         {
           char *prompt;
           char *line;
     
    -      while (sigsetjmp (ctrlc_buf, 1) != 0);
    -
           pk_term_flush ();
           rl_completion_entry_function = poke_completion_function;
           prompt = pk_prompt ();
    @@ -345,6 +365,8 @@ pk_repl (void)
         free (poke_history);
       }
     #endif
    +
    +  ctrlc_buf_valid = 0;
     }
     
     static int saved_point;



reply via email to

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