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