Home | History | Annotate | Line # | Download | only in unittests
      1 /* Self tests for scoped_ignored_signal for GDB, the GNU debugger.
      2 
      3    Copyright (C) 2021-2024 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 "gdbsupport/scoped_ignore_signal.h"
     21 #include "gdbsupport/selftest.h"
     22 #include "gdbsupport/scope-exit.h"
     23 #include <unistd.h>
     24 #include <signal.h>
     25 
     26 namespace selftests {
     27 namespace scoped_ignore_sig {
     28 
     29 #ifdef SIGPIPE
     30 
     31 /* True if the SIGPIPE handler ran.  */
     32 static volatile sig_atomic_t got_sigpipe = 0;
     33 
     34 /* SIGPIPE handler for testing.  */
     35 
     36 static void
     37 handle_sigpipe (int)
     38 {
     39   got_sigpipe = 1;
     40 }
     41 
     42 /* Test scoped_ignore_sigpipe.  */
     43 
     44 static void
     45 test_sigpipe ()
     46 {
     47   auto *osig = signal (SIGPIPE, handle_sigpipe);
     48   SCOPE_EXIT { signal (SIGPIPE, osig); };
     49 
     50 #ifdef HAVE_SIGPROCMASK
     51   /* Make sure SIGPIPE isn't blocked.  */
     52   sigset_t set, old_state;
     53   sigemptyset (&set);
     54   sigaddset (&set, SIGPIPE);
     55   sigprocmask (SIG_UNBLOCK, &set, &old_state);
     56   SCOPE_EXIT { sigprocmask (SIG_SETMASK, &old_state, nullptr); };
     57 #endif
     58 
     59   /* Create pipe, and close read end so that writes to the pipe fail
     60      with EPIPE.  */
     61 
     62   int fd[2];
     63   char c = 0xff;
     64   int r;
     65 
     66   r = pipe (fd);
     67   SELF_CHECK (r == 0);
     68 
     69   close (fd[0]);
     70   SCOPE_EXIT { close (fd[1]); };
     71 
     72   /* Check that writing to the pipe results in EPIPE.  EXPECT_SIG
     73      indicates whether a SIGPIPE signal is expected.  */
     74   auto check_pipe_write = [&] (bool expect_sig)
     75   {
     76     got_sigpipe = 0;
     77     errno = 0;
     78 
     79     r = write (fd[1], &c, 1);
     80     SELF_CHECK (r == -1 && errno == EPIPE
     81 		&& got_sigpipe == expect_sig);
     82   };
     83 
     84   /* Check that without a scoped_ignore_sigpipe in scope we indeed get
     85      a SIGPIPE signal.  */
     86   check_pipe_write (true);
     87 
     88   /* Now check that with a scoped_ignore_sigpipe in scope, SIGPIPE is
     89      ignored/blocked.  */
     90   {
     91     scoped_ignore_sigpipe ignore1;
     92 
     93     check_pipe_write (false);
     94 
     95     /* Check that scoped_ignore_sigpipe nests correctly.  */
     96     {
     97       scoped_ignore_sigpipe ignore2;
     98 
     99       check_pipe_write (false);
    100     }
    101 
    102     /* If nesting works correctly, this write results in no
    103        SIGPIPE.  */
    104     check_pipe_write (false);
    105   }
    106 
    107   /* No scoped_ignore_sigpipe is in scope anymore, so this should
    108      result in a SIGPIPE signal.  */
    109   check_pipe_write (true);
    110 }
    111 
    112 #endif /* SIGPIPE */
    113 
    114 } /* namespace scoped_ignore_sig */
    115 } /* namespace selftests */
    116 
    117 void _initialize_scoped_ignore_signal_selftests ();
    118 void
    119 _initialize_scoped_ignore_signal_selftests ()
    120 {
    121 #ifdef SIGPIPE
    122   selftests::register_test ("scoped_ignore_sigpipe",
    123 			    selftests::scoped_ignore_sig::test_sigpipe);
    124 #endif
    125 }
    126