| //===-- Integration tests for abort --------------------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "src/signal/signal.h" |
| #include "src/stdlib/_Exit.h" |
| #include "src/stdlib/abort.h" |
| #include "src/stdlib/abort_utils.h" |
| #include "src/sys/wait/waitpid.h" |
| #include "src/unistd/close.h" |
| #include "src/unistd/fork.h" |
| #include "src/unistd/pipe.h" |
| #include "src/unistd/read.h" |
| #include "src/unistd/write.h" |
| |
| #include "test/IntegrationTest/test.h" |
| |
| #include <signal.h> |
| #include <sys/wait.h> |
| #include <unistd.h> |
| |
| namespace { |
| |
| constexpr char HANDLER_MARKER = 'A'; |
| int handler_pipe_fd = -1; |
| |
| void expect_child_died_with_signal(pid_t pid, int signal) { |
| int status = 0; |
| ASSERT_EQ(LIBC_NAMESPACE::waitpid(pid, &status, 0), pid); |
| ASSERT_TRUE(WIFSIGNALED(status)); |
| ASSERT_EQ(WTERMSIG(status), signal); |
| } |
| |
| void child_abort() { LIBC_NAMESPACE::abort(); } |
| |
| void returning_sigabrt_handler(int) { |
| if (handler_pipe_fd >= 0) |
| LIBC_NAMESPACE::write(handler_pipe_fd, &HANDLER_MARKER, 1); |
| } |
| |
| void child_abort_with_returning_handler() { |
| auto previous = LIBC_NAMESPACE::signal(SIGABRT, returning_sigabrt_handler); |
| ASSERT_NE(previous, SIG_ERR); |
| LIBC_NAMESPACE::abort(); |
| } |
| |
| void abort_kills_child_with_sigabrt() { |
| pid_t pid = LIBC_NAMESPACE::fork(); |
| if (pid == 0) |
| child_abort(); |
| |
| ASSERT_TRUE(pid > 0); |
| expect_child_died_with_signal(pid, SIGABRT); |
| } |
| |
| void abort_reraises_sigabrt_after_returning_handler() { |
| int pipefd[2]; |
| ASSERT_EQ(LIBC_NAMESPACE::pipe(pipefd), 0); |
| |
| pid_t pid = LIBC_NAMESPACE::fork(); |
| if (pid == 0) { |
| LIBC_NAMESPACE::close(pipefd[0]); |
| handler_pipe_fd = pipefd[1]; |
| child_abort_with_returning_handler(); |
| } |
| |
| ASSERT_TRUE(pid > 0); |
| ASSERT_EQ(LIBC_NAMESPACE::close(pipefd[1]), 0); |
| |
| expect_child_died_with_signal(pid, SIGABRT); |
| |
| char marker = 0; |
| ASSERT_EQ(LIBC_NAMESPACE::read(pipefd[0], &marker, 1), ssize_t(1)); |
| ASSERT_EQ(marker, HANDLER_MARKER); |
| ASSERT_EQ(LIBC_NAMESPACE::close(pipefd[0]), 0); |
| } |
| |
| } // namespace |
| |
| TEST_MAIN([[maybe_unused]] int argc, [[maybe_unused]] char **argv, |
| [[maybe_unused]] char **envp) { |
| abort_kills_child_with_sigabrt(); |
| abort_reraises_sigabrt_after_returning_handler(); |
| return 0; |
| } |