Home | History | Annotate | Line # | Download | only in unittests
scoped_ignore_signal-selftests.c revision 1.1
      1 /* Self tests for scoped_ignored_signal for GDB, the GNU debugger.
      2 
      3    Copyright (C) 2021-2023 Free Software Foundation, Inc.
      4 
      5    This file is part of GDB.
      6 
      7    This program is free software; you can redistribute it and/or modify
      8    it under the terms of the GNU General Public License as published by
      9    the Free Software Foundation; either version 3 of the License, or
     10    (at your option) any later version.
     11 
     12    This program is distributed in the hope that it will be useful,
     13    but WITHOUT ANY WARRANTY; without even the implied warranty of
     14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15    GNU General Public License for more details.
     16 
     17    You should have received a copy of the GNU General Public License
     18    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     19 
     20 #include "defs.h"
     21 #include "gdbsupport/scoped_ignore_signal.h"
     22 #include "gdbsupport/selftest.h"
     23 #include "gdbsupport/scope-exit.h"
     24 #include <unistd.h>
     25 #include <signal.h>
     26 
     27 namespace selftests {
     28 namespace scoped_ignore_sig {
     29 
     30 #ifdef SIGPIPE
     31 
     32 /* True if the SIGPIPE handler ran.  */
     33 static volatile sig_atomic_t got_sigpipe = 0;
     34 
     35 /* SIGPIPE handler for testing.  */
     36 
     37 static void
     38 handle_sigpipe (int)
     39 {
     40   got_sigpipe = 1;
     41 }
     42 
     43 /* Test scoped_ignore_sigpipe.  */
     44 
     45 static void
     46 test_sigpipe ()
     47 {
     48   auto *osig = signal (SIGPIPE, handle_sigpipe);
     49   SCOPE_EXIT { signal (SIGPIPE, osig); };
     50 
     51 #ifdef HAVE_SIGPROCMASK
     52   /* Make sure SIGPIPE isn't blocked.  */
     53   sigset_t set, old_state;
     54   sigemptyset (&set);
     55   sigaddset (&set, SIGPIPE);
     56   sigprocmask (SIG_UNBLOCK, &set, &old_state);
     57   SCOPE_EXIT { sigprocmask (SIG_SETMASK, &old_state, nullptr); };
     58 #endif
     59 
     60   /* Create pipe, and close read end so that writes to the pipe fail
     61      with EPIPE.  */
     62 
     63   int fd[2];
     64   char c = 0xff;
     65   int r;
     66 
     67   r = pipe (fd);
     68   SELF_CHECK (r == 0);
     69 
     70   close (fd[0]);
     71   SCOPE_EXIT { close (fd[1]); };
     72 
     73   /* Check that writing to the pipe results in EPIPE.  EXPECT_SIG
     74      indicates whether a SIGPIPE signal is expected.  */
     75   auto check_pipe_write = [&] (bool expect_sig)
     76   {
     77     got_sigpipe = 0;
     78     errno = 0;
     79 
     80     r = write (fd[1], &c, 1);
     81     SELF_CHECK (r == -1 && errno == EPIPE
     82 		&& got_sigpipe == expect_sig);
     83   };
     84 
     85   /* Check that without a scoped_ignore_sigpipe in scope we indeed get
     86      a SIGPIPE signal.  */
     87   check_pipe_write (true);
     88 
     89   /* Now check that with a scoped_ignore_sigpipe in scope, SIGPIPE is
     90      ignored/blocked.  */
     91   {
     92     scoped_ignore_sigpipe ignore1;
     93 
     94     check_pipe_write (false);
     95 
     96     /* Check that scoped_ignore_sigpipe nests correctly.  */
     97     {
     98       scoped_ignore_sigpipe ignore2;
     99 
    100       check_pipe_write (false);
    101     }
    102 
    103     /* If nesting works correctly, this write results in no
    104        SIGPIPE.  */
    105     check_pipe_write (false);
    106   }
    107 
    108   /* No scoped_ignore_sigpipe is in scope anymore, so this should
    109      result in a SIGPIPE signal.  */
    110   check_pipe_write (true);
    111 }
    112 
    113 #endif /* SIGPIPE */
    114 
    115 } /* namespace scoped_ignore_sig */
    116 } /* namespace selftests */
    117 
    118 void _initialize_scoped_ignore_signal_selftests ();
    119 void
    120 _initialize_scoped_ignore_signal_selftests ()
    121 {
    122 #ifdef SIGPIPE
    123   selftests::register_test ("scoped_ignore_sigpipe",
    124 			    selftests::scoped_ignore_sig::test_sigpipe);
    125 #endif
    126 }
    127