Created
October 20, 2013 12:39
-
-
Save TheBurnDoc/7069048 to your computer and use it in GitHub Desktop.
A method of using Posix fork to 'catch' and report seg faults in Google Test. To take advantage of it, use the ForkedTest class as your base test case class and remember to call its SetUp and TearDown in the derived classes' SetUp and TearDown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <gtest/gtest.h> | |
#include <fcntl.h> | |
#include <string.h> | |
#include <errno.h> | |
#include <resource.h> | |
#include "ForkedTest.h" | |
using namespace ::std; | |
using namespace ::testing; | |
ForkedTest::ForkedTest() | |
: m_pid(0) | |
, m_read_fd(m_pipe_fd[0]) | |
, m_write_fd(m_pipe_fd[1]) | |
{ | |
if (pipe2(m_pipe_fd, O_NONBLOCK) == -1) | |
{ | |
cout << "ForkedTest::ForkedTest(): pipe2() failed with error: " << strerror(errno) << std::endl; | |
exit(EXIT_FAILURE); | |
} | |
} | |
ForkedTest::~ForkedTest() | |
{ | |
close(m_read_fd); | |
close(m_write_fd); | |
} | |
void ForkedTest::SetUp() | |
{ | |
m_pid = fork(); | |
if (m_pid == -1) | |
{ | |
cout << "ForkedTest::SetUp(): fork() failed with error: " << strerror(errno) << endl; | |
_exit(EXIT_FAILURE); | |
} | |
// Child only code | |
else if (m_pid == 0) | |
{ | |
// Disable core dumps on new process | |
struct rlimit rl; | |
rl.rlim_cur = rl.rlim_max = 0; | |
if (setrlimit(RLIMIT_CORE, &rl) == -1) | |
cout << "ForkedTest::SetUp(): setrlimit() failed with error: " << strerror(errno) << endl; | |
} | |
// Parent only code | |
else if (m_pid > 0) | |
{ | |
pid_t wpid; | |
int exit_status; | |
bool do_suicide = false; | |
ssize_t read_size; | |
do | |
{ | |
wpid = waitpid(m_pid, &exit_status, WNOHANG); | |
if (wpid == -1) | |
{ | |
cout << "ForkedTest::SetUp(): waitpid() failed with error: " << strerror(errno) << endl; | |
_exit(EXIT_FAILURE); | |
} | |
else if (wpid && WIFSIGNALED(exit_status)) | |
{ | |
bool seg_fault_detected = static_cast<bool>(WTERMSIG(exit_status) == SIGSEGV); | |
ASSERT_FALSE(seg_fault_detected); | |
} | |
else | |
{ | |
// Child's TearDown() has told us to die | |
read_size = read(m_read_fd, static_cast<void*>(&do_suicide), sizeof(bool)); | |
if (read_size != -1 && read_size == sizeof(bool)) | |
if (do_suicide) _exit(EXIT_SUCCESS); | |
} | |
} | |
while (wpid == 0); | |
} | |
} | |
void ForkedTest::TearDown() | |
{ | |
// Child only code | |
if (m_pid == 0) | |
{ | |
bool parent_die = true; | |
ssize_t write_size = write(m_write_fd, static_cast<void*>(&parent_die), sizeof(bool)); | |
if (write_size == -1) | |
{ | |
cout << "ForkedTest::TearDown(): write() failed with error: " << strerror(errno) << endl; | |
_exit(EXIT_FAILURE); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef CORESAFETEST_H_ | |
#define CORESAFETEST_H_ | |
#include <gtest/gtest.h> | |
#include <fcntl.h> | |
class ForkedTest : public ::testing::Test | |
{ | |
protected: | |
ForkedTest(); | |
virtual ~ForkedTest(); | |
virtual void SetUp(); | |
virtual void TearDown(); | |
private: | |
pid_t m_pid; | |
int m_pipe_fd[2]; | |
const int& m_read_fd; | |
const int& m_write_fd; | |
}; | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment