blob: 87b23c0c0afaa8b84cb1e9f1d7e4c7f68475ba5b [file] [edit]
//===-- 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;
}