diff options
author | Josh Gao <jmgao@google.com> | 2018-02-26 15:54:41 -0800 |
---|---|---|
committer | Josh Gao <jmgao@google.com> | 2018-02-26 18:31:45 -0800 |
commit | 1eac77e5f6306718c2c0e63f29228520b61371f9 (patch) | |
tree | 023bea45f8aa2f860227e24203203a9ec2fbb820 /sigchainlib | |
parent | d32d79d76c0e2af7c65dc67f9322fc46b5677ee3 (diff) |
sigchain: add test.
Add a gtest for the various sigchain wrappers.
Bug: http://b/73344857
Test: adb shell /data/nativetest64/art/arm64/art_sigchain_tests/sigchain_test
(with several actual failures)
Change-Id: I331da4f44008984723e2e2733e2a6dd66658e704
Diffstat (limited to 'sigchainlib')
-rw-r--r-- | sigchainlib/Android.bp | 9 | ||||
-rw-r--r-- | sigchainlib/sigchain_test.cc | 187 |
2 files changed, 196 insertions, 0 deletions
diff --git a/sigchainlib/Android.bp b/sigchainlib/Android.bp index ac5a90725e..1f490cd3b9 100644 --- a/sigchainlib/Android.bp +++ b/sigchainlib/Android.bp @@ -60,3 +60,12 @@ cc_library_static { }, }, } + +art_cc_test { + name: "art_sigchain_tests", + defaults: [ + "art_gtest_defaults", + ], + srcs: ["sigchain_test.cc"], + whole_static_libs: ["libsigchain"], +} diff --git a/sigchainlib/sigchain_test.cc b/sigchainlib/sigchain_test.cc new file mode 100644 index 0000000000..9f338ad3a2 --- /dev/null +++ b/sigchainlib/sigchain_test.cc @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#include <signal.h> +#include <sys/syscall.h> + +#include <functional> + +#include <gtest/gtest.h> + +#include "sigchain.h" + +#if !defined(__BIONIC__) +typedef sigset_t sigset64_t; + +static int sigemptyset64(sigset64_t* set) { + return sigemptyset(set); +} + +static int sigismember64(sigset64_t* set, int member) { + return sigismember(set, member); +} +#endif + +static int RealSigprocmask(int how, const sigset64_t* new_sigset, sigset64_t* old_sigset) { + // glibc's sigset_t is overly large, so sizeof(*new_sigset) doesn't work. + return syscall(__NR_rt_sigprocmask, how, new_sigset, old_sigset, 8); +} + +class SigchainTest : public ::testing::Test { + void SetUp() final { + art::AddSpecialSignalHandlerFn(SIGSEGV, &action); + } + + void TearDown() final { + art::RemoveSpecialSignalHandlerFn(SIGSEGV, action.sc_sigaction); + } + + art::SigchainAction action = { + .sc_sigaction = [](int, siginfo_t*, void*) { return true; }, + .sc_mask = {}, + .sc_flags = 0, + }; +}; + + +static void TestSignalBlocking(std::function<void()> fn) { + // Unblock SIGSEGV, make sure it stays unblocked. + sigset64_t mask; + sigemptyset64(&mask); + ASSERT_EQ(0, RealSigprocmask(SIG_SETMASK, &mask, nullptr)) << strerror(errno); + + fn(); + + if (testing::Test::HasFatalFailure()) return; + ASSERT_EQ(0, RealSigprocmask(SIG_SETMASK, nullptr, &mask)); + ASSERT_FALSE(sigismember64(&mask, SIGSEGV)); +} + +TEST_F(SigchainTest, sigprocmask_setmask) { + TestSignalBlocking([]() { + sigset_t mask; + sigfillset(&mask); + ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &mask, nullptr)); + }); +} + +TEST_F(SigchainTest, sigprocmask_block) { + TestSignalBlocking([]() { + sigset_t mask; + sigfillset(&mask); + ASSERT_EQ(0, sigprocmask(SIG_BLOCK, &mask, nullptr)); + }); +} + +// bionic-only wide variants for LP32. +#if defined(__BIONIC__) +TEST_F(SigchainTest, sigprocmask64_setmask) { + TestSignalBlocking([]() { + sigset64_t mask; + sigfillset64(&mask); + ASSERT_EQ(0, sigprocmask64(SIG_SETMASK, &mask, nullptr)); + }); +} + +TEST_F(SigchainTest, sigprocmask64_block) { + TestSignalBlocking([]() { + sigset64_t mask; + sigfillset64(&mask); + ASSERT_EQ(0, sigprocmask64(SIG_BLOCK, &mask, nullptr)); + }); +} + +TEST_F(SigchainTest, pthread_sigmask64_setmask) { + TestSignalBlocking([]() { + sigset64_t mask; + sigfillset64(&mask); + ASSERT_EQ(0, pthread_sigmask64(SIG_SETMASK, &mask, nullptr)); + }); +} + +TEST_F(SigchainTest, pthread_sigmask64_block) { + TestSignalBlocking([]() { + sigset64_t mask; + sigfillset64(&mask); + ASSERT_EQ(0, pthread_sigmask64(SIG_BLOCK, &mask, nullptr)); + }); +} +#endif + +// glibc doesn't implement most of these in terms of sigprocmask, which we rely on. +#if defined(__BIONIC__) +TEST_F(SigchainTest, pthread_sigmask_setmask) { + TestSignalBlocking([]() { + sigset_t mask; + sigfillset(&mask); + ASSERT_EQ(0, pthread_sigmask(SIG_SETMASK, &mask, nullptr)); + }); +} + +TEST_F(SigchainTest, pthread_sigmask_block) { + TestSignalBlocking([]() { + sigset_t mask; + sigfillset(&mask); + ASSERT_EQ(0, pthread_sigmask(SIG_BLOCK, &mask, nullptr)); + }); +} + +TEST_F(SigchainTest, sigset_mask) { + TestSignalBlocking([]() { + sigset(SIGSEGV, SIG_HOLD); + }); +} + +TEST_F(SigchainTest, sighold) { + TestSignalBlocking([]() { + sighold(SIGSEGV); + }); +} + +#if defined(__BIONIC__) +// Not exposed via headers, but the symbols are available if you declare them yourself. +extern "C" int sigblock(int); +extern "C" int sigsetmask(int); +#endif + +TEST_F(SigchainTest, sigblock) { + TestSignalBlocking([]() { + int mask = ~0U; + ASSERT_EQ(0, sigblock(mask)); + }); +} + +TEST_F(SigchainTest, sigsetmask) { + TestSignalBlocking([]() { + int mask = ~0U; + ASSERT_EQ(0, sigsetmask(mask)); + }); +} + +#endif |