1 // Copyright 2010 Google Inc. 2 // All rights reserved. 3 // 4 // Redistribution and use in source and binary forms, with or without 5 // modification, are permitted provided that the following conditions are 6 // met: 7 // 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 the 12 // documentation and/or other materials provided with the distribution. 13 // * Neither the name of Google Inc. nor the names of its contributors 14 // may be used to endorse or promote products derived from this software 15 // without specific prior written permission. 16 // 17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 29 #include "utils/process/status.hpp" 30 31 extern "C" { 32 #include <sys/resource.h> 33 #include <sys/wait.h> 34 35 #include <signal.h> 36 #include <unistd.h> 37 } 38 39 #include <cstdlib> 40 41 #include <atf-c++.hpp> 42 43 using utils::process::status; 44 45 46 namespace { 47 48 49 /// Body of a subprocess that exits with a particular exit status. 50 /// 51 /// \tparam ExitStatus The status to exit with. 52 template< int ExitStatus > 53 void child_exit(void) 54 { 55 std::exit(ExitStatus); 56 } 57 58 59 /// Body of a subprocess that sends a particular signal to itself. 60 /// 61 /// \tparam Signo The signal to send to self. 62 template< int Signo > 63 void child_signal(void) 64 { 65 ::kill(::getpid(), Signo); 66 } 67 68 69 /// Spawns a process and waits for completion. 70 /// 71 /// \param hook The function to run within the child. Should not return. 72 /// 73 /// \return The termination status of the spawned subprocess. 74 status 75 fork_and_wait(void (*hook)(void)) 76 { 77 pid_t pid = ::fork(); 78 ATF_REQUIRE(pid != -1); 79 if (pid == 0) { 80 hook(); 81 std::abort(); 82 } else { 83 int stat_loc; 84 ATF_REQUIRE(::waitpid(pid, &stat_loc, 0) != -1); 85 const status s = status(pid, stat_loc); 86 ATF_REQUIRE_EQ(pid, s.dead_pid()); 87 return s; 88 } 89 } 90 91 92 } // anonymous namespace 93 94 95 ATF_TEST_CASE_WITHOUT_HEAD(fake_exited) 96 ATF_TEST_CASE_BODY(fake_exited) 97 { 98 const status fake = status::fake_exited(123); 99 ATF_REQUIRE_EQ(-1, fake.dead_pid()); 100 ATF_REQUIRE(fake.exited()); 101 ATF_REQUIRE_EQ(123, fake.exitstatus()); 102 ATF_REQUIRE(!fake.signaled()); 103 } 104 105 106 ATF_TEST_CASE_WITHOUT_HEAD(fake_signaled) 107 ATF_TEST_CASE_BODY(fake_signaled) 108 { 109 const status fake = status::fake_signaled(567, true); 110 ATF_REQUIRE_EQ(-1, fake.dead_pid()); 111 ATF_REQUIRE(!fake.exited()); 112 ATF_REQUIRE(fake.signaled()); 113 ATF_REQUIRE_EQ(567, fake.termsig()); 114 ATF_REQUIRE(fake.coredump()); 115 } 116 117 118 ATF_TEST_CASE_WITHOUT_HEAD(integration__exited); 119 ATF_TEST_CASE_BODY(integration__exited) 120 { 121 const status exit_success = fork_and_wait(child_exit< EXIT_SUCCESS >); 122 ATF_REQUIRE(exit_success.exited()); 123 ATF_REQUIRE_EQ(EXIT_SUCCESS, exit_success.exitstatus()); 124 ATF_REQUIRE(!exit_success.signaled()); 125 126 const status exit_failure = fork_and_wait(child_exit< EXIT_FAILURE >); 127 ATF_REQUIRE(exit_failure.exited()); 128 ATF_REQUIRE_EQ(EXIT_FAILURE, exit_failure.exitstatus()); 129 ATF_REQUIRE(!exit_failure.signaled()); 130 } 131 132 133 ATF_TEST_CASE_WITHOUT_HEAD(integration__signaled); 134 ATF_TEST_CASE_BODY(integration__signaled) 135 { 136 const status sigterm = fork_and_wait(child_signal< SIGTERM >); 137 ATF_REQUIRE(!sigterm.exited()); 138 ATF_REQUIRE(sigterm.signaled()); 139 ATF_REQUIRE_EQ(SIGTERM, sigterm.termsig()); 140 ATF_REQUIRE(!sigterm.coredump()); 141 142 const status sigkill = fork_and_wait(child_signal< SIGKILL >); 143 ATF_REQUIRE(!sigkill.exited()); 144 ATF_REQUIRE(sigkill.signaled()); 145 ATF_REQUIRE_EQ(SIGKILL, sigkill.termsig()); 146 ATF_REQUIRE(!sigkill.coredump()); 147 } 148 149 150 ATF_TEST_CASE_WITHOUT_HEAD(integration__coredump); 151 ATF_TEST_CASE_BODY(integration__coredump) 152 { 153 struct rlimit rl; 154 rl.rlim_cur = RLIM_INFINITY; 155 rl.rlim_max = RLIM_INFINITY; 156 if (::setrlimit(RLIMIT_CORE, &rl) == -1) 157 skip("Cannot unlimit the core file size; check limits manually"); 158 159 const status coredump = fork_and_wait(child_signal< SIGQUIT >); 160 ATF_REQUIRE(!coredump.exited()); 161 ATF_REQUIRE(coredump.signaled()); 162 ATF_REQUIRE_EQ(SIGQUIT, coredump.termsig()); 163 #if !defined(WCOREDUMP) 164 expect_fail("Platform does not support checking for coredump"); 165 #endif 166 ATF_REQUIRE(coredump.coredump()); 167 } 168 169 170 ATF_INIT_TEST_CASES(tcs) 171 { 172 ATF_ADD_TEST_CASE(tcs, fake_exited); 173 ATF_ADD_TEST_CASE(tcs, fake_signaled); 174 175 ATF_ADD_TEST_CASE(tcs, integration__exited); 176 ATF_ADD_TEST_CASE(tcs, integration__signaled); 177 ATF_ADD_TEST_CASE(tcs, integration__coredump); 178 } 179