1/* 2 * Copyright (C) 2018 The Android Open Source Project 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in 12 * the documentation and/or other materials provided with the 13 * distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 30#include <signal.h> 31#include <sys/syscall.h> 32 33#include <functional> 34 35#include <gtest/gtest.h> 36 37#include "sigchain.h" 38 39#if !defined(__BIONIC__) 40typedef sigset_t sigset64_t; 41 42static int sigemptyset64(sigset64_t* set) { 43 return sigemptyset(set); 44} 45 46static int sigismember64(sigset64_t* set, int member) { 47 return sigismember(set, member); 48} 49#endif 50 51static int RealSigprocmask(int how, const sigset64_t* new_sigset, sigset64_t* old_sigset) { 52 // glibc's sigset_t is overly large, so sizeof(*new_sigset) doesn't work. 53 return syscall(__NR_rt_sigprocmask, how, new_sigset, old_sigset, 8); 54} 55 56class SigchainTest : public ::testing::Test { 57 void SetUp() final { 58 art::AddSpecialSignalHandlerFn(SIGSEGV, &action); 59 } 60 61 void TearDown() final { 62 art::RemoveSpecialSignalHandlerFn(SIGSEGV, action.sc_sigaction); 63 } 64 65 art::SigchainAction action = { 66 .sc_sigaction = [](int, siginfo_t*, void*) { return true; }, 67 .sc_mask = {}, 68 .sc_flags = 0, 69 }; 70}; 71 72 73static void TestSignalBlocking(std::function<void()> fn) { 74 // Unblock SIGSEGV, make sure it stays unblocked. 75 sigset64_t mask; 76 sigemptyset64(&mask); 77 ASSERT_EQ(0, RealSigprocmask(SIG_SETMASK, &mask, nullptr)) << strerror(errno); 78 79 fn(); 80 81 if (testing::Test::HasFatalFailure()) return; 82 ASSERT_EQ(0, RealSigprocmask(SIG_SETMASK, nullptr, &mask)); 83 ASSERT_FALSE(sigismember64(&mask, SIGSEGV)); 84} 85 86TEST_F(SigchainTest, sigprocmask_setmask) { 87 TestSignalBlocking([]() { 88 sigset_t mask; 89 sigfillset(&mask); 90 ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &mask, nullptr)); 91 }); 92} 93 94TEST_F(SigchainTest, sigprocmask_block) { 95 TestSignalBlocking([]() { 96 sigset_t mask; 97 sigfillset(&mask); 98 ASSERT_EQ(0, sigprocmask(SIG_BLOCK, &mask, nullptr)); 99 }); 100} 101 102// bionic-only wide variants for LP32. 103#if defined(__BIONIC__) 104TEST_F(SigchainTest, sigprocmask64_setmask) { 105 TestSignalBlocking([]() { 106 sigset64_t mask; 107 sigfillset64(&mask); 108 ASSERT_EQ(0, sigprocmask64(SIG_SETMASK, &mask, nullptr)); 109 }); 110} 111 112TEST_F(SigchainTest, sigprocmask64_block) { 113 TestSignalBlocking([]() { 114 sigset64_t mask; 115 sigfillset64(&mask); 116 ASSERT_EQ(0, sigprocmask64(SIG_BLOCK, &mask, nullptr)); 117 }); 118} 119 120TEST_F(SigchainTest, pthread_sigmask64_setmask) { 121 TestSignalBlocking([]() { 122 sigset64_t mask; 123 sigfillset64(&mask); 124 ASSERT_EQ(0, pthread_sigmask64(SIG_SETMASK, &mask, nullptr)); 125 }); 126} 127 128TEST_F(SigchainTest, pthread_sigmask64_block) { 129 TestSignalBlocking([]() { 130 sigset64_t mask; 131 sigfillset64(&mask); 132 ASSERT_EQ(0, pthread_sigmask64(SIG_BLOCK, &mask, nullptr)); 133 }); 134} 135#endif 136 137// glibc doesn't implement most of these in terms of sigprocmask, which we rely on. 138#if defined(__BIONIC__) 139TEST_F(SigchainTest, pthread_sigmask_setmask) { 140 TestSignalBlocking([]() { 141 sigset_t mask; 142 sigfillset(&mask); 143 ASSERT_EQ(0, pthread_sigmask(SIG_SETMASK, &mask, nullptr)); 144 }); 145} 146 147TEST_F(SigchainTest, pthread_sigmask_block) { 148 TestSignalBlocking([]() { 149 sigset_t mask; 150 sigfillset(&mask); 151 ASSERT_EQ(0, pthread_sigmask(SIG_BLOCK, &mask, nullptr)); 152 }); 153} 154 155TEST_F(SigchainTest, sigset_mask) { 156 TestSignalBlocking([]() { 157 sigset(SIGSEGV, SIG_HOLD); 158 }); 159} 160 161TEST_F(SigchainTest, sighold) { 162 TestSignalBlocking([]() { 163 sighold(SIGSEGV); 164 }); 165} 166 167#if defined(__BIONIC__) 168// Not exposed via headers, but the symbols are available if you declare them yourself. 169extern "C" int sigblock(int); 170extern "C" int sigsetmask(int); 171#endif 172 173TEST_F(SigchainTest, sigblock) { 174 TestSignalBlocking([]() { 175 int mask = ~0U; 176 ASSERT_EQ(0, sigblock(mask)); 177 }); 178} 179 180TEST_F(SigchainTest, sigsetmask) { 181 TestSignalBlocking([]() { 182 int mask = ~0U; 183 ASSERT_EQ(0, sigsetmask(mask)); 184 }); 185} 186 187#endif 188