gtest-death-test.cc (googletest-release-1.10.0) | : | gtest-death-test.cc (googletest-release-1.11.0) | ||
---|---|---|---|---|
skipping to change at line 35 | skipping to change at line 35 | |||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
// | // | |||
// This file implements death tests. | // This file implements death tests. | |||
#include "gtest/gtest-death-test.h" | #include "gtest/gtest-death-test.h" | |||
#include <functional> | ||||
#include <utility> | #include <utility> | |||
#include "gtest/internal/gtest-port.h" | #include "gtest/internal/gtest-port.h" | |||
#include "gtest/internal/custom/gtest.h" | #include "gtest/internal/custom/gtest.h" | |||
#if GTEST_HAS_DEATH_TEST | #if GTEST_HAS_DEATH_TEST | |||
# if GTEST_OS_MAC | # if GTEST_OS_MAC | |||
# include <crt_externs.h> | # include <crt_externs.h> | |||
# endif // GTEST_OS_MAC | # endif // GTEST_OS_MAC | |||
skipping to change at line 250 | skipping to change at line 251 | |||
static std::string DeathTestThreadWarning(size_t thread_count) { | static std::string DeathTestThreadWarning(size_t thread_count) { | |||
Message msg; | Message msg; | |||
msg << "Death tests use fork(), which is unsafe particularly" | msg << "Death tests use fork(), which is unsafe particularly" | |||
<< " in a threaded context. For this test, " << GTEST_NAME_ << " "; | << " in a threaded context. For this test, " << GTEST_NAME_ << " "; | |||
if (thread_count == 0) { | if (thread_count == 0) { | |||
msg << "couldn't detect the number of threads."; | msg << "couldn't detect the number of threads."; | |||
} else { | } else { | |||
msg << "detected " << thread_count << " threads."; | msg << "detected " << thread_count << " threads."; | |||
} | } | |||
msg << " See " | msg << " See " | |||
"https://github.com/google/googletest/blob/master/googletest/docs/" | "https://github.com/google/googletest/blob/master/docs/" | |||
"advanced.md#death-tests-and-threads" | "advanced.md#death-tests-and-threads" | |||
<< " for more explanation and suggested solutions, especially if" | << " for more explanation and suggested solutions, especially if" | |||
<< " this is the last message you see before your test times out."; | << " this is the last message you see before your test times out."; | |||
return msg.GetString(); | return msg.GetString(); | |||
} | } | |||
# endif // !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA | # endif // !GTEST_OS_WINDOWS && !GTEST_OS_FUCHSIA | |||
// Flag characters for reporting a death test that did not die. | // Flag characters for reporting a death test that did not die. | |||
static const char kDeathTestLived = 'L'; | static const char kDeathTestLived = 'L'; | |||
static const char kDeathTestReturned = 'R'; | static const char kDeathTestReturned = 'R'; | |||
skipping to change at line 867 | skipping to change at line 868 | |||
i != arguments.end(); | i != arguments.end(); | |||
++i) { | ++i) { | |||
args_.insert(args_.end() - 1, posix::StrDup(i->c_str())); | args_.insert(args_.end() - 1, posix::StrDup(i->c_str())); | |||
} | } | |||
} | } | |||
char* const* Argv() { | char* const* Argv() { | |||
return &args_[0]; | return &args_[0]; | |||
} | } | |||
int size() { | int size() { | |||
return args_.size() - 1; | return static_cast<int>(args_.size()) - 1; | |||
} | } | |||
private: | private: | |||
std::vector<char*> args_; | std::vector<char*> args_; | |||
}; | }; | |||
// Waits for the child in a death test to exit, returning its exit | // Waits for the child in a death test to exit, returning its exit | |||
// status, or 0 if no child process exists. As a side effect, sets the | // status, or 0 if no child process exists. As a side effect, sets the | |||
// outcome data member. | // outcome data member. | |||
int FuchsiaDeathTest::Wait() { | int FuchsiaDeathTest::Wait() { | |||
skipping to change at line 893 | skipping to change at line 894 | |||
return 0; | return 0; | |||
// Create a port to wait for socket/task/exception events. | // Create a port to wait for socket/task/exception events. | |||
zx_status_t status_zx; | zx_status_t status_zx; | |||
zx::port port; | zx::port port; | |||
status_zx = zx::port::create(0, &port); | status_zx = zx::port::create(0, &port); | |||
GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); | GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); | |||
// Register to wait for the child process to terminate. | // Register to wait for the child process to terminate. | |||
status_zx = child_process_.wait_async( | status_zx = child_process_.wait_async( | |||
port, kProcessKey, ZX_PROCESS_TERMINATED, ZX_WAIT_ASYNC_ONCE); | port, kProcessKey, ZX_PROCESS_TERMINATED, 0); | |||
GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); | GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); | |||
// Register to wait for the socket to be readable or closed. | // Register to wait for the socket to be readable or closed. | |||
status_zx = stderr_socket_.wait_async( | status_zx = stderr_socket_.wait_async( | |||
port, kSocketKey, ZX_SOCKET_READABLE | ZX_SOCKET_PEER_CLOSED, | port, kSocketKey, ZX_SOCKET_READABLE | ZX_SOCKET_PEER_CLOSED, 0); | |||
ZX_WAIT_ASYNC_ONCE); | ||||
GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); | GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); | |||
// Register to wait for an exception. | // Register to wait for an exception. | |||
status_zx = exception_channel_.wait_async( | status_zx = exception_channel_.wait_async( | |||
port, kExceptionKey, ZX_CHANNEL_READABLE, ZX_WAIT_ASYNC_ONCE); | port, kExceptionKey, ZX_CHANNEL_READABLE, 0); | |||
GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); | GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); | |||
bool process_terminated = false; | bool process_terminated = false; | |||
bool socket_closed = false; | bool socket_closed = false; | |||
do { | do { | |||
zx_port_packet_t packet = {}; | zx_port_packet_t packet = {}; | |||
status_zx = port.wait(zx::time::infinite(), &packet); | status_zx = port.wait(zx::time::infinite(), &packet); | |||
GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); | GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); | |||
if (packet.key == kExceptionKey) { | if (packet.key == kExceptionKey) { | |||
skipping to change at line 944 | skipping to change at line 944 | |||
status_zx = stderr_socket_.read( | status_zx = stderr_socket_.read( | |||
0, &captured_stderr_.front() + old_length, kBufferSize, | 0, &captured_stderr_.front() + old_length, kBufferSize, | |||
&bytes_read); | &bytes_read); | |||
captured_stderr_.resize(old_length + bytes_read); | captured_stderr_.resize(old_length + bytes_read); | |||
} while (status_zx == ZX_OK); | } while (status_zx == ZX_OK); | |||
if (status_zx == ZX_ERR_PEER_CLOSED) { | if (status_zx == ZX_ERR_PEER_CLOSED) { | |||
socket_closed = true; | socket_closed = true; | |||
} else { | } else { | |||
GTEST_DEATH_TEST_CHECK_(status_zx == ZX_ERR_SHOULD_WAIT); | GTEST_DEATH_TEST_CHECK_(status_zx == ZX_ERR_SHOULD_WAIT); | |||
status_zx = stderr_socket_.wait_async( | status_zx = stderr_socket_.wait_async( | |||
port, kSocketKey, ZX_SOCKET_READABLE | ZX_SOCKET_PEER_CLOSED, | port, kSocketKey, ZX_SOCKET_READABLE | ZX_SOCKET_PEER_CLOSED, 0); | |||
ZX_WAIT_ASYNC_ONCE); | ||||
GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); | GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); | |||
} | } | |||
} else { | } else { | |||
GTEST_DEATH_TEST_CHECK_(packet.signal.observed & ZX_SOCKET_PEER_CLOSED); | GTEST_DEATH_TEST_CHECK_(packet.signal.observed & ZX_SOCKET_PEER_CLOSED); | |||
socket_closed = true; | socket_closed = true; | |||
} | } | |||
} | } | |||
} while (!process_terminated && !socket_closed); | } while (!process_terminated && !socket_closed); | |||
ReadAndInterpretStatusByte(); | ReadAndInterpretStatusByte(); | |||
zx_info_process_t buffer; | zx_info_process_t buffer; | |||
status_zx = child_process_.get_info( | status_zx = child_process_.get_info(ZX_INFO_PROCESS, &buffer, sizeof(buffer), | |||
ZX_INFO_PROCESS, &buffer, sizeof(buffer), nullptr, nullptr); | nullptr, nullptr); | |||
GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); | GTEST_DEATH_TEST_CHECK_(status_zx == ZX_OK); | |||
GTEST_DEATH_TEST_CHECK_(buffer.exited); | GTEST_DEATH_TEST_CHECK_(buffer.flags & ZX_INFO_PROCESS_FLAG_EXITED); | |||
set_status(buffer.return_code); | set_status(static_cast<int>(buffer.return_code)); | |||
return status(); | return status(); | |||
} | } | |||
// The AssumeRole process for a Fuchsia death test. It creates a child | // The AssumeRole process for a Fuchsia death test. It creates a child | |||
// process with the same executable as the current process to run the | // process with the same executable as the current process to run the | |||
// death test. The child process is given the --gtest_filter and | // death test. The child process is given the --gtest_filter and | |||
// --gtest_internal_run_death_test flags such that it knows to run the | // --gtest_internal_run_death_test flags such that it knows to run the | |||
// current death test only. | // current death test only. | |||
DeathTest::TestRole FuchsiaDeathTest::AssumeRole() { | DeathTest::TestRole FuchsiaDeathTest::AssumeRole() { | |||
const UnitTestImpl* const impl = GetUnitTestImpl(); | const UnitTestImpl* const impl = GetUnitTestImpl(); | |||
skipping to change at line 1228 | skipping to change at line 1227 | |||
std::vector<char*> args_; | std::vector<char*> args_; | |||
}; | }; | |||
// A struct that encompasses the arguments to the child process of a | // A struct that encompasses the arguments to the child process of a | |||
// threadsafe-style death test process. | // threadsafe-style death test process. | |||
struct ExecDeathTestArgs { | struct ExecDeathTestArgs { | |||
char* const* argv; // Command-line arguments for the child's call to exec | char* const* argv; // Command-line arguments for the child's call to exec | |||
int close_fd; // File descriptor to close; the read end of a pipe | int close_fd; // File descriptor to close; the read end of a pipe | |||
}; | }; | |||
# if GTEST_OS_MAC | # if GTEST_OS_QNX | |||
inline char** GetEnviron() { | ||||
// When Google Test is built as a framework on MacOS X, the environ variable | ||||
// is unavailable. Apple's documentation (man environ) recommends using | ||||
// _NSGetEnviron() instead. | ||||
return *_NSGetEnviron(); | ||||
} | ||||
# else | ||||
// Some POSIX platforms expect you to declare environ. extern "C" makes | ||||
// it reside in the global namespace. | ||||
extern "C" char** environ; | extern "C" char** environ; | |||
inline char** GetEnviron() { return environ; } | # else // GTEST_OS_QNX | |||
# endif // GTEST_OS_MAC | ||||
# if !GTEST_OS_QNX | ||||
// The main function for a threadsafe-style death test child process. | // The main function for a threadsafe-style death test child process. | |||
// This function is called in a clone()-ed process and thus must avoid | // This function is called in a clone()-ed process and thus must avoid | |||
// any potentially unsafe operations like malloc or libc functions. | // any potentially unsafe operations like malloc or libc functions. | |||
static int ExecDeathTestChildMain(void* child_arg) { | static int ExecDeathTestChildMain(void* child_arg) { | |||
ExecDeathTestArgs* const args = static_cast<ExecDeathTestArgs*>(child_arg); | ExecDeathTestArgs* const args = static_cast<ExecDeathTestArgs*>(child_arg); | |||
GTEST_DEATH_TEST_CHECK_SYSCALL_(close(args->close_fd)); | GTEST_DEATH_TEST_CHECK_SYSCALL_(close(args->close_fd)); | |||
// We need to execute the test program in the same environment where | // We need to execute the test program in the same environment where | |||
// it was originally invoked. Therefore we change to the original | // it was originally invoked. Therefore we change to the original | |||
// working directory first. | // working directory first. | |||
const char* const original_dir = | const char* const original_dir = | |||
UnitTest::GetInstance()->original_working_dir(); | UnitTest::GetInstance()->original_working_dir(); | |||
// We can safely call chdir() as it's a direct system call. | // We can safely call chdir() as it's a direct system call. | |||
if (chdir(original_dir) != 0) { | if (chdir(original_dir) != 0) { | |||
DeathTestAbort(std::string("chdir(\"") + original_dir + "\") failed: " + | DeathTestAbort(std::string("chdir(\"") + original_dir + "\") failed: " + | |||
GetLastErrnoDescription()); | GetLastErrnoDescription()); | |||
return EXIT_FAILURE; | return EXIT_FAILURE; | |||
} | } | |||
// We can safely call execve() as it's a direct system call. We | // We can safely call execv() as it's almost a direct system call. We | |||
// cannot use execvp() as it's a libc function and thus potentially | // cannot use execvp() as it's a libc function and thus potentially | |||
// unsafe. Since execve() doesn't search the PATH, the user must | // unsafe. Since execv() doesn't search the PATH, the user must | |||
// invoke the test program via a valid path that contains at least | // invoke the test program via a valid path that contains at least | |||
// one path separator. | // one path separator. | |||
execve(args->argv[0], args->argv, GetEnviron()); | execv(args->argv[0], args->argv); | |||
DeathTestAbort(std::string("execve(") + args->argv[0] + ", ...) in " + | DeathTestAbort(std::string("execv(") + args->argv[0] + ", ...) in " + | |||
original_dir + " failed: " + | original_dir + " failed: " + | |||
GetLastErrnoDescription()); | GetLastErrnoDescription()); | |||
return EXIT_FAILURE; | return EXIT_FAILURE; | |||
} | } | |||
# endif // !GTEST_OS_QNX | # endif // GTEST_OS_QNX | |||
# if GTEST_HAS_CLONE | # if GTEST_HAS_CLONE | |||
// Two utility routines that together determine the direction the stack | // Two utility routines that together determine the direction the stack | |||
// grows. | // grows. | |||
// This could be accomplished more elegantly by a single recursive | // This could be accomplished more elegantly by a single recursive | |||
// function, but we want to guard against the unlikely possibility of | // function, but we want to guard against the unlikely possibility of | |||
// a smart compiler optimizing the recursion away. | // a smart compiler optimizing the recursion away. | |||
// | // | |||
// GTEST_NO_INLINE_ is required to prevent GCC 4.6 from inlining | // GTEST_NO_INLINE_ is required to prevent GCC 4.6 from inlining | |||
// StackLowerThanAddress into StackGrowsDown, which then doesn't give | // StackLowerThanAddress into StackGrowsDown, which then doesn't give | |||
// correct answer. | // correct answer. | |||
static void StackLowerThanAddress(const void* ptr, | static void StackLowerThanAddress(const void* ptr, | |||
bool* result) GTEST_NO_INLINE_; | bool* result) GTEST_NO_INLINE_; | |||
// Make sure sanitizers do not tamper with the stack here. | ||||
// Ideally, we want to use `__builtin_frame_address` instead of a local variable | ||||
// address with sanitizer disabled, but it does not work when the | ||||
// compiler optimizes the stack frame out, which happens on PowerPC targets. | ||||
// HWAddressSanitizer add a random tag to the MSB of the local variable address, | // HWAddressSanitizer add a random tag to the MSB of the local variable address, | |||
// making comparison result unpredictable. | // making comparison result unpredictable. | |||
GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ | ||||
GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ | GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ | |||
static void StackLowerThanAddress(const void* ptr, bool* result) { | static void StackLowerThanAddress(const void* ptr, bool* result) { | |||
int dummy; | int dummy = 0; | |||
*result = (&dummy < ptr); | *result = std::less<const void*>()(&dummy, ptr); | |||
} | } | |||
// Make sure AddressSanitizer does not tamper with the stack here. | // Make sure AddressSanitizer does not tamper with the stack here. | |||
GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ | GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ | |||
GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ | GTEST_ATTRIBUTE_NO_SANITIZE_HWADDRESS_ | |||
static bool StackGrowsDown() { | static bool StackGrowsDown() { | |||
int dummy; | int dummy = 0; | |||
bool result; | bool result; | |||
StackLowerThanAddress(&dummy, &result); | StackLowerThanAddress(&dummy, &result); | |||
return result; | return result; | |||
} | } | |||
# endif // GTEST_HAS_CLONE | # endif // GTEST_HAS_CLONE | |||
// Spawns a child process with the same executable as the current process in | // Spawns a child process with the same executable as the current process in | |||
// a thread-safe manner and instructs it to run the death test. The | // a thread-safe manner and instructs it to run the death test. The | |||
// implementation uses fork(2) + exec. On systems where clone(2) is | // implementation uses fork(2) + exec. On systems where clone(2) is | |||
// available, it is used instead, being slightly more thread-safe. On QNX, | // available, it is used instead, being slightly more thread-safe. On QNX, | |||
skipping to change at line 1342 | skipping to change at line 1334 | |||
return EXIT_FAILURE; | return EXIT_FAILURE; | |||
} | } | |||
int fd_flags; | int fd_flags; | |||
// Set close_fd to be closed after spawn. | // Set close_fd to be closed after spawn. | |||
GTEST_DEATH_TEST_CHECK_SYSCALL_(fd_flags = fcntl(close_fd, F_GETFD)); | GTEST_DEATH_TEST_CHECK_SYSCALL_(fd_flags = fcntl(close_fd, F_GETFD)); | |||
GTEST_DEATH_TEST_CHECK_SYSCALL_(fcntl(close_fd, F_SETFD, | GTEST_DEATH_TEST_CHECK_SYSCALL_(fcntl(close_fd, F_SETFD, | |||
fd_flags | FD_CLOEXEC)); | fd_flags | FD_CLOEXEC)); | |||
struct inheritance inherit = {0}; | struct inheritance inherit = {0}; | |||
// spawn is a system call. | // spawn is a system call. | |||
child_pid = | child_pid = spawn(args.argv[0], 0, nullptr, &inherit, args.argv, environ); | |||
spawn(args.argv[0], 0, nullptr, &inherit, args.argv, GetEnviron()); | ||||
// Restores the current working directory. | // Restores the current working directory. | |||
GTEST_DEATH_TEST_CHECK_(fchdir(cwd_fd) != -1); | GTEST_DEATH_TEST_CHECK_(fchdir(cwd_fd) != -1); | |||
GTEST_DEATH_TEST_CHECK_SYSCALL_(close(cwd_fd)); | GTEST_DEATH_TEST_CHECK_SYSCALL_(close(cwd_fd)); | |||
# else // GTEST_OS_QNX | # else // GTEST_OS_QNX | |||
# if GTEST_OS_LINUX | # if GTEST_OS_LINUX | |||
// When a SIGPROF signal is received while fork() or clone() are executing, | // When a SIGPROF signal is received while fork() or clone() are executing, | |||
// the process may hang. To avoid this, we ignore SIGPROF here and re-enable | // the process may hang. To avoid this, we ignore SIGPROF here and re-enable | |||
// it after the call to fork()/clone() is complete. | // it after the call to fork()/clone() is complete. | |||
struct sigaction saved_sigprof_action; | struct sigaction saved_sigprof_action; | |||
skipping to change at line 1367 | skipping to change at line 1358 | |||
ignore_sigprof_action.sa_handler = SIG_IGN; | ignore_sigprof_action.sa_handler = SIG_IGN; | |||
GTEST_DEATH_TEST_CHECK_SYSCALL_(sigaction( | GTEST_DEATH_TEST_CHECK_SYSCALL_(sigaction( | |||
SIGPROF, &ignore_sigprof_action, &saved_sigprof_action)); | SIGPROF, &ignore_sigprof_action, &saved_sigprof_action)); | |||
# endif // GTEST_OS_LINUX | # endif // GTEST_OS_LINUX | |||
# if GTEST_HAS_CLONE | # if GTEST_HAS_CLONE | |||
const bool use_fork = GTEST_FLAG(death_test_use_fork); | const bool use_fork = GTEST_FLAG(death_test_use_fork); | |||
if (!use_fork) { | if (!use_fork) { | |||
static const bool stack_grows_down = StackGrowsDown(); | static const bool stack_grows_down = StackGrowsDown(); | |||
const auto stack_size = static_cast<size_t>(getpagesize()); | const auto stack_size = static_cast<size_t>(getpagesize() * 2); | |||
// MMAP_ANONYMOUS is not defined on Mac, so we use MAP_ANON instead. | // MMAP_ANONYMOUS is not defined on Mac, so we use MAP_ANON instead. | |||
void* const stack = mmap(nullptr, stack_size, PROT_READ | PROT_WRITE, | void* const stack = mmap(nullptr, stack_size, PROT_READ | PROT_WRITE, | |||
MAP_ANON | MAP_PRIVATE, -1, 0); | MAP_ANON | MAP_PRIVATE, -1, 0); | |||
GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED); | GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED); | |||
// Maximum stack alignment in bytes: For a downward-growing stack, this | // Maximum stack alignment in bytes: For a downward-growing stack, this | |||
// amount is subtracted from size of the stack space to get an address | // amount is subtracted from size of the stack space to get an address | |||
// that is within the stack space and is aligned on all systems we care | // that is within the stack space and is aligned on all systems we care | |||
// about. As far as I know there is no ABI with stack alignment greater | // about. As far as I know there is no ABI with stack alignment greater | |||
// than 64. We assume stack and stack_size already have alignment of | // than 64. We assume stack and stack_size already have alignment of | |||
End of changes. 21 change blocks. | ||||
37 lines changed or deleted | 28 lines changed or added |