"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "googletest/src/gtest-death-test.cc" between
googletest-release-1.10.0.tar.gz and googletest-release-1.11.0.tar.gz

About: GoogleTest is Google's (unit) testing and mocking framework for C++ tests.

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

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)