diff options
author | jln@chromium.org <jln@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-06 20:59:51 +0000 |
---|---|---|
committer | jln@chromium.org <jln@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-06 20:59:51 +0000 |
commit | 263e0a20bacae798fb39fea69b9778a2f433e759 (patch) | |
tree | 88ac26bfb7f55719eef059421c1dffa884d5d5cf /sandbox/linux | |
parent | aeb894d899d7548a5f4e0f35e5689ef4ca171ef2 (diff) | |
download | chromium_src-263e0a20bacae798fb39fea69b9778a2f433e759.zip chromium_src-263e0a20bacae798fb39fea69b9778a2f433e759.tar.gz chromium_src-263e0a20bacae798fb39fea69b9778a2f433e759.tar.bz2 |
Linux sandbox: cleanup test framework further
Remove more void* in favor of strong typing. Create a new global
SandboxTestRunner interface that can be implemented by specific test runners.
Implement BPF_TEST via a SandboxBPFTestRunner class which takes a delegate
to implement allocating the BPF policy and actually running the function.
This allows us to confine templating to this new BPFTesterSimpleDelegate class.
BUG=368970
R=jorgelo@chromium.org, mdempsky@chromium.org
Review URL: https://codereview.chromium.org/265283003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@268608 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'sandbox/linux')
-rw-r--r-- | sandbox/linux/sandbox_linux.gypi | 5 | ||||
-rw-r--r-- | sandbox/linux/seccomp-bpf/bpf_tests.cc | 4 | ||||
-rw-r--r-- | sandbox/linux/seccomp-bpf/bpf_tests.h | 116 | ||||
-rw-r--r-- | sandbox/linux/seccomp-bpf/bpf_tests_unittest.cc | 21 | ||||
-rw-r--r-- | sandbox/linux/seccomp-bpf/sandbox_bpf_test_runner.cc | 70 | ||||
-rw-r--r-- | sandbox/linux/seccomp-bpf/sandbox_bpf_test_runner.h | 57 | ||||
-rw-r--r-- | sandbox/linux/tests/sandbox_test_runner.h | 25 | ||||
-rw-r--r-- | sandbox/linux/tests/sandbox_test_runner_function_pointer.cc | 25 | ||||
-rw-r--r-- | sandbox/linux/tests/sandbox_test_runner_function_pointer.h | 26 | ||||
-rw-r--r-- | sandbox/linux/tests/unit_tests.cc | 6 | ||||
-rw-r--r-- | sandbox/linux/tests/unit_tests.h | 25 |
11 files changed, 289 insertions, 91 deletions
diff --git a/sandbox/linux/sandbox_linux.gypi b/sandbox/linux/sandbox_linux.gypi index cf9922e..9c56f8d 100644 --- a/sandbox/linux/sandbox_linux.gypi +++ b/sandbox/linux/sandbox_linux.gypi @@ -66,6 +66,9 @@ '../..', ], 'sources': [ + 'tests/sandbox_test_runner.h', + 'tests/sandbox_test_runner_function_pointer.cc', + 'tests/sandbox_test_runner_function_pointer.h', 'tests/test_utils.cc', 'tests/test_utils.h', 'tests/unit_tests.cc', @@ -76,6 +79,8 @@ 'sources': [ 'seccomp-bpf/bpf_tests.cc', 'seccomp-bpf/bpf_tests.h', + 'seccomp-bpf/sandbox_bpf_test_runner.cc', + 'seccomp-bpf/sandbox_bpf_test_runner.h', ], 'dependencies': [ 'seccomp_bpf', diff --git a/sandbox/linux/seccomp-bpf/bpf_tests.cc b/sandbox/linux/seccomp-bpf/bpf_tests.cc index dea0ab1..b1ab719 100644 --- a/sandbox/linux/seccomp-bpf/bpf_tests.cc +++ b/sandbox/linux/seccomp-bpf/bpf_tests.cc @@ -8,13 +8,13 @@ namespace sandbox { // static template <> -void* BPFTests<void>::NewAux() { +void* BPFTesterSimpleDelegate<void>::NewAux() { return NULL; } // static template <> -void BPFTests<void>::DeleteAux(void* aux) { +void BPFTesterSimpleDelegate<void>::DeleteAux(void* aux) { CHECK(!aux); } diff --git a/sandbox/linux/seccomp-bpf/bpf_tests.h b/sandbox/linux/seccomp-bpf/bpf_tests.h index 47a00b9..ccfc651 100644 --- a/sandbox/linux/seccomp-bpf/bpf_tests.h +++ b/sandbox/linux/seccomp-bpf/bpf_tests.h @@ -14,6 +14,8 @@ #include "build/build_config.h" #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" #include "sandbox/linux/seccomp-bpf/sandbox_bpf_compatibility_policy.h" +#include "sandbox/linux/seccomp-bpf/sandbox_bpf_test_runner.h" +#include "sandbox/linux/tests/sandbox_test_runner.h" #include "sandbox/linux/tests/unit_tests.h" namespace sandbox { @@ -24,13 +26,16 @@ namespace sandbox { // A BPF_DEATH_TEST is always disabled under ThreadSanitizer, see // crbug.com/243968. #define BPF_DEATH_TEST(test_case_name, test_name, death, policy, aux...) \ - void BPF_TEST_##test_name(sandbox::BPFTests<aux>::AuxType* BPF_AUX); \ + void BPF_TEST_##test_name( \ + sandbox::BPFTesterSimpleDelegate<aux>::AuxType* BPF_AUX); \ TEST(test_case_name, DISABLE_ON_TSAN(test_name)) { \ - sandbox::BPFTests<aux>::TestArgs arg(BPF_TEST_##test_name, policy); \ - sandbox::BPFTests<aux>::RunTestInProcess( \ - sandbox::BPFTests<aux>::TestWrapper, &arg, death); \ + sandbox::SandboxBPFTestRunner bpf_test_runner( \ + new sandbox::BPFTesterSimpleDelegate<aux>(BPF_TEST_##test_name, \ + policy)); \ + sandbox::UnitTests::RunTestInProcess(&bpf_test_runner, death); \ } \ - void BPF_TEST_##test_name(sandbox::BPFTests<aux>::AuxType* BPF_AUX) + void BPF_TEST_##test_name( \ + sandbox::BPFTesterSimpleDelegate<aux>::AuxType* BPF_AUX) // BPF_TEST() is a special version of SANDBOX_TEST(). It turns into a no-op, // if the host does not have kernel support for running BPF filters. @@ -59,80 +64,36 @@ namespace sandbox { #define BPF_ASSERT_LE(x, y) BPF_ASSERT((x) <= (y)) #define BPF_ASSERT_GE(x, y) BPF_ASSERT((x) >= (y)) -// The "Aux" type is optional. void is used by default and all pointers -// provided to the tests will be NULL. template <class Aux = void> -class BPFTests : public UnitTests { +class BPFTesterSimpleDelegate : public BPFTesterDelegate { public: typedef Aux AuxType; + BPFTesterSimpleDelegate( + void (*test_function)(AuxType*), + typename CompatibilityPolicy<AuxType>::SyscallEvaluator policy_function) + : aux_pointer_for_policy_(NULL), + test_function_(test_function), + policy_function_(policy_function) { + // This will be NULL iff AuxType is void. + aux_pointer_for_policy_ = NewAux(); + } - class TestArgs { - public: - TestArgs(void (*t)(AuxType*), - typename CompatibilityPolicy<AuxType>::SyscallEvaluator p) - : test_(t), policy_function_(p) {} - - void (*test() const)(AuxType*) { return test_; } - - private: - friend class BPFTests; - - void (*test_)(AuxType*); - typename CompatibilityPolicy<AuxType>::SyscallEvaluator policy_function_; - }; + virtual ~BPFTesterSimpleDelegate() { DeleteAux(aux_pointer_for_policy_); } - static void TestWrapper(void* void_arg) { - TestArgs* arg = reinterpret_cast<TestArgs*>(void_arg); - sandbox::Die::EnableSimpleExit(); + virtual scoped_ptr<SandboxBPFPolicy> GetSandboxBPFPolicy() OVERRIDE { + // The current method is guaranteed to only run in the child process + // running the test. In this process, the current object is guaranteed + // to live forever. So it's ok to pass aux_pointer_for_policy_ to + // the policy, which could in turn pass it to the kernel via Trap(). + return scoped_ptr<SandboxBPFPolicy>(new CompatibilityPolicy<AuxType>( + policy_function_, aux_pointer_for_policy_)); + } - // This will be NULL iff AuxType is void. - AuxType* aux_pointer_for_policy = NewAux(); - - scoped_ptr<CompatibilityPolicy<AuxType> > policy( - new CompatibilityPolicy<AuxType>(arg->policy_function_, - aux_pointer_for_policy)); - - if (sandbox::SandboxBPF::SupportsSeccompSandbox(-1) == - sandbox::SandboxBPF::STATUS_AVAILABLE) { - // Ensure the the sandbox is actually available at this time - int proc_fd; - BPF_ASSERT((proc_fd = open("/proc", O_RDONLY | O_DIRECTORY)) >= 0); - BPF_ASSERT(sandbox::SandboxBPF::SupportsSeccompSandbox(proc_fd) == - sandbox::SandboxBPF::STATUS_AVAILABLE); - - // Initialize and then start the sandbox with our custom policy - sandbox::SandboxBPF sandbox; - sandbox.set_proc_fd(proc_fd); - sandbox.SetSandboxPolicy(policy.release()); - BPF_ASSERT( - sandbox.StartSandbox(sandbox::SandboxBPF::PROCESS_SINGLE_THREADED)); - - // Run the actual test. - arg->test()(aux_pointer_for_policy); - - // Once a BPF policy is engaged, there is no going back. A SIGSYS handler - // can make use of aux, this can happen even in _exit(). This object's - // ownership has been passed to the kernel by engaging the sandbox and it - // will be destroyed with the process. - ANNOTATE_LEAKING_OBJECT_PTR(aux_pointer_for_policy); - } else { - printf("This BPF test is not fully running in this configuration!\n"); - // Android and Valgrind are the only configurations where we accept not - // having kernel BPF support. - if (!IsAndroid() && !IsRunningOnValgrind()) { - const bool seccomp_bpf_is_supported = false; - BPF_ASSERT(seccomp_bpf_is_supported); - } - // Call the compiler and verify the policy. That's the least we can do, - // if we don't have kernel support. - sandbox::SandboxBPF sandbox; - sandbox.SetSandboxPolicy(policy.release()); - sandbox::SandboxBPF::Program* program = - sandbox.AssembleFilter(true /* force_verification */); - delete program; - DeleteAux(aux_pointer_for_policy); - sandbox::UnitTests::IgnoreThisTest(); - } + virtual void RunTestFunction() OVERRIDE { + // Run the actual test. + // The current object is guaranteed to live forever in the child process + // where this will run. + test_function_(aux_pointer_for_policy_); } private: @@ -141,14 +102,17 @@ class BPFTests : public UnitTests { static Aux* NewAux() { return new Aux(); } static void DeleteAux(Aux* aux) { delete aux; } - DISALLOW_IMPLICIT_CONSTRUCTORS(BPFTests); + AuxType* aux_pointer_for_policy_; + void (*test_function_)(AuxType*); + typename CompatibilityPolicy<AuxType>::SyscallEvaluator policy_function_; + DISALLOW_COPY_AND_ASSIGN(BPFTesterSimpleDelegate); }; // Specialization of NewAux that returns NULL; template <> -void* BPFTests<void>::NewAux(); +void* BPFTesterSimpleDelegate<void>::NewAux(); template <> -void BPFTests<void>::DeleteAux(void* aux); +void BPFTesterSimpleDelegate<void>::DeleteAux(void* aux); } // namespace sandbox diff --git a/sandbox/linux/seccomp-bpf/bpf_tests_unittest.cc b/sandbox/linux/seccomp-bpf/bpf_tests_unittest.cc index b91966f..41c3dd3 100644 --- a/sandbox/linux/seccomp-bpf/bpf_tests_unittest.cc +++ b/sandbox/linux/seccomp-bpf/bpf_tests_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -7,6 +7,7 @@ #include <errno.h> #include "base/logging.h" +#include "base/memory/scoped_ptr.h" #include "build/build_config.h" #include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" #include "sandbox/linux/services/linux_syscalls.h" @@ -67,6 +68,24 @@ BPF_TEST(BPFTest, BPF_ASSERT(FourtyTwo::kMagicValue == BPF_AUX->value()); } +void DummyTestFunction(FourtyTwo *fourty_two) { +} + +TEST(BPFTest, BPFTesterSimpleDelegateLeakTest) { + // Don't do anything, simply gives dynamic tools an opportunity to detect + // leaks. + { + BPFTesterSimpleDelegate<FourtyTwo> simple_delegate(DummyTestFunction, + EmptyPolicyTakesClass); + } + { + // Test polymorphism. + scoped_ptr<BPFTesterDelegate> simple_delegate( + new BPFTesterSimpleDelegate<FourtyTwo>(DummyTestFunction, + EmptyPolicyTakesClass)); + } +} + } // namespace } // namespace sandbox diff --git a/sandbox/linux/seccomp-bpf/sandbox_bpf_test_runner.cc b/sandbox/linux/seccomp-bpf/sandbox_bpf_test_runner.cc new file mode 100644 index 0000000..ade1d49 --- /dev/null +++ b/sandbox/linux/seccomp-bpf/sandbox_bpf_test_runner.cc @@ -0,0 +1,70 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "sandbox/linux/seccomp-bpf/sandbox_bpf_test_runner.h" + +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/types.h> + +#include "base/basictypes.h" +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "sandbox/linux/seccomp-bpf/sandbox_bpf.h" +#include "sandbox/linux/tests/unit_tests.h" + +namespace sandbox { + +SandboxBPFTestRunner::SandboxBPFTestRunner( + BPFTesterDelegate* bpf_tester_delegate) + : bpf_tester_delegate_(bpf_tester_delegate) { +} + +SandboxBPFTestRunner::~SandboxBPFTestRunner() { +} + +void SandboxBPFTestRunner::Run() { + DCHECK(bpf_tester_delegate_); + sandbox::Die::EnableSimpleExit(); + + scoped_ptr<SandboxBPFPolicy> policy = + bpf_tester_delegate_->GetSandboxBPFPolicy(); + + if (sandbox::SandboxBPF::SupportsSeccompSandbox(-1) == + sandbox::SandboxBPF::STATUS_AVAILABLE) { + // Ensure the the sandbox is actually available at this time + int proc_fd; + SANDBOX_ASSERT((proc_fd = open("/proc", O_RDONLY | O_DIRECTORY)) >= 0); + SANDBOX_ASSERT(sandbox::SandboxBPF::SupportsSeccompSandbox(proc_fd) == + sandbox::SandboxBPF::STATUS_AVAILABLE); + + // Initialize and then start the sandbox with our custom policy + sandbox::SandboxBPF sandbox; + sandbox.set_proc_fd(proc_fd); + sandbox.SetSandboxPolicy(policy.release()); + SANDBOX_ASSERT( + sandbox.StartSandbox(sandbox::SandboxBPF::PROCESS_SINGLE_THREADED)); + + // Run the actual test. + bpf_tester_delegate_->RunTestFunction(); + } else { + printf("This BPF test is not fully running in this configuration!\n"); + // Android and Valgrind are the only configurations where we accept not + // having kernel BPF support. + if (!IsAndroid() && !IsRunningOnValgrind()) { + const bool seccomp_bpf_is_supported = false; + SANDBOX_ASSERT(seccomp_bpf_is_supported); + } + // Call the compiler and verify the policy. That's the least we can do, + // if we don't have kernel support. + sandbox::SandboxBPF sandbox; + sandbox.SetSandboxPolicy(policy.release()); + sandbox::SandboxBPF::Program* program = + sandbox.AssembleFilter(true /* force_verification */); + delete program; + sandbox::UnitTests::IgnoreThisTest(); + } +} + +} // namespace sandbox diff --git a/sandbox/linux/seccomp-bpf/sandbox_bpf_test_runner.h b/sandbox/linux/seccomp-bpf/sandbox_bpf_test_runner.h new file mode 100644 index 0000000..c1beba2 --- /dev/null +++ b/sandbox/linux/seccomp-bpf/sandbox_bpf_test_runner.h @@ -0,0 +1,57 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_TEST_RUNNER_H_ +#define SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_TEST_RUNNER_H_ + +#include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" +#include "sandbox/linux/seccomp-bpf/sandbox_bpf_policy.h" +#include "sandbox/linux/tests/sandbox_test_runner.h" + +namespace sandbox { + +// To create a SandboxBPFTestRunner object, one needs to implement this +// interface and pass an instance to the SandboxBPFTestRunner constructor. +// In the child process running the test, the BPFTesterDelegate object is +// guaranteed to not be destroyed until the child process terminates. +class BPFTesterDelegate { + public: + BPFTesterDelegate() {} + virtual ~BPFTesterDelegate() {} + + // This will instanciate a policy suitable for the test we want to run. It is + // guaranteed to only be called from the child process that will run the + // test. + virtual scoped_ptr<SandboxBPFPolicy> GetSandboxBPFPolicy() = 0; + // This will be called from a child process with the BPF sandbox turned on. + virtual void RunTestFunction() = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(BPFTesterDelegate); +}; + +// This class implements the SandboxTestRunner interface and Run() will +// initialize a seccomp-bpf sandbox (specified by |bpf_tester_delegate|) and +// run a test function (via |bpf_tester_delegate|) if the current kernel +// configuration allows it. If it can not run the test under seccomp-bpf, +// Run() will still compile the policy which should allow to get some coverage +// under tools such as Valgrind. +class SandboxBPFTestRunner : public SandboxTestRunner { + public: + // This constructor takes ownership of the |bpf_tester_delegate| object. + // (It doesn't take a scoped_ptr since they make polymorphism verbose). + explicit SandboxBPFTestRunner(BPFTesterDelegate* bpf_tester_delegate); + virtual ~SandboxBPFTestRunner(); + + virtual void Run() OVERRIDE; + + private: + scoped_ptr<BPFTesterDelegate> bpf_tester_delegate_; + DISALLOW_COPY_AND_ASSIGN(SandboxBPFTestRunner); +}; + +} // namespace sandbox + +#endif // SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_TEST_RUNNER_H_ diff --git a/sandbox/linux/tests/sandbox_test_runner.h b/sandbox/linux/tests/sandbox_test_runner.h new file mode 100644 index 0000000..4cb7102 --- /dev/null +++ b/sandbox/linux/tests/sandbox_test_runner.h @@ -0,0 +1,25 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef SANDBOX_LINUX_TESTS_SANDBOX_TEST_RUNNER_H_ +#define SANDBOX_LINUX_TESTS_SANDBOX_TEST_RUNNER_H_ + +#include "base/basictypes.h" + +namespace sandbox { + +// A simple "runner" class to implement tests. +class SandboxTestRunner { + public: + SandboxTestRunner() {} + virtual ~SandboxTestRunner() {} + virtual void Run() = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(SandboxTestRunner); +}; + +} // namespace sandbox + +#endif // SANDBOX_LINUX_TESTS_SANDBOX_TEST_RUNNER_H_ diff --git a/sandbox/linux/tests/sandbox_test_runner_function_pointer.cc b/sandbox/linux/tests/sandbox_test_runner_function_pointer.cc new file mode 100644 index 0000000..69e05ac --- /dev/null +++ b/sandbox/linux/tests/sandbox_test_runner_function_pointer.cc @@ -0,0 +1,25 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "sandbox/linux/tests/sandbox_test_runner_function_pointer.h" + +#include "base/logging.h" +#include "build/build_config.h" + +namespace sandbox { + +SandboxTestRunnerFunctionPointer::SandboxTestRunnerFunctionPointer( + void (*function_to_run)(void)) + : function_to_run_(function_to_run) { +} + +SandboxTestRunnerFunctionPointer::~SandboxTestRunnerFunctionPointer() { +} + +void SandboxTestRunnerFunctionPointer::Run() { + DCHECK(function_to_run_); + function_to_run_(); +} + +} // namespace sandbox diff --git a/sandbox/linux/tests/sandbox_test_runner_function_pointer.h b/sandbox/linux/tests/sandbox_test_runner_function_pointer.h new file mode 100644 index 0000000..1cb709f --- /dev/null +++ b/sandbox/linux/tests/sandbox_test_runner_function_pointer.h @@ -0,0 +1,26 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef SANDBOX_LINUX_TESTS_SANDBOX_TEST_RUNNER_FUNCTION_POINTER_H_ +#define SANDBOX_LINUX_TESTS_SANDBOX_TEST_RUNNER_FUNCTION_POINTER_H_ + +#include "base/basictypes.h" +#include "sandbox/linux/tests/sandbox_test_runner.h" + +namespace sandbox { + +class SandboxTestRunnerFunctionPointer : public SandboxTestRunner { + public: + SandboxTestRunnerFunctionPointer(void (*function_to_run)(void)); + virtual ~SandboxTestRunnerFunctionPointer() OVERRIDE; + virtual void Run() OVERRIDE; + + private: + void (*function_to_run_)(void); + DISALLOW_COPY_AND_ASSIGN(SandboxTestRunnerFunctionPointer); +}; + +} // namespace sandbox + +#endif // SANDBOX_LINUX_TESTS_SANDBOX_TEST_RUNNER__FUNCTION_POINTER_H_ diff --git a/sandbox/linux/tests/unit_tests.cc b/sandbox/linux/tests/unit_tests.cc index 42b85a8..282c718 100644 --- a/sandbox/linux/tests/unit_tests.cc +++ b/sandbox/linux/tests/unit_tests.cc @@ -105,10 +105,10 @@ static void SetProcessTimeout(int time_in_seconds) { // in the BPF sandbox, as it potentially makes global state changes and as // it also tends to raise fatal errors, if the code has been used in an // insecure manner. -void UnitTests::RunTestInProcess(UnitTests::Test test, - void* arg, +void UnitTests::RunTestInProcess(SandboxTestRunner* test_runner, DeathCheck death, const void* death_aux) { + CHECK(test_runner); // We need to fork(), so we can't be multi-threaded, as threads could hold // locks. int num_threads = CountThreads(); @@ -174,7 +174,7 @@ void UnitTests::RunTestInProcess(UnitTests::Test test, struct rlimit no_core = {0}; setrlimit(RLIMIT_CORE, &no_core); - test(arg); + test_runner->Run(); _exit(kExpectedValue); } diff --git a/sandbox/linux/tests/unit_tests.h b/sandbox/linux/tests/unit_tests.h index bc1939c..9531595 100644 --- a/sandbox/linux/tests/unit_tests.h +++ b/sandbox/linux/tests/unit_tests.h @@ -7,6 +7,7 @@ #include "base/basictypes.h" #include "build/build_config.h" +#include "sandbox/linux/tests/sandbox_test_runner_function_pointer.h" #include "testing/gtest/include/gtest/gtest.h" namespace sandbox { @@ -62,12 +63,13 @@ bool IsRunningOnValgrind(); // that the test actually dies. The death test only passes if the death occurs // in the expected fashion, as specified by "death" and "death_aux". These two // parameters are typically set to one of the DEATH_XXX() macros. -#define SANDBOX_DEATH_TEST(test_case_name, test_name, death) \ - void TEST_##test_name(void*); \ - TEST(test_case_name, test_name) { \ - sandbox::UnitTests::RunTestInProcess(TEST_##test_name, NULL, death); \ - } \ - void TEST_##test_name(void*) +#define SANDBOX_DEATH_TEST(test_case_name, test_name, death) \ + void TEST_##test_name(void); \ + TEST(test_case_name, test_name) { \ + SandboxTestRunnerFunctionPointer sandbox_test_runner(TEST_##test_name); \ + sandbox::UnitTests::RunTestInProcess(&sandbox_test_runner, death); \ + } \ + void TEST_##test_name(void) // Define a new test case that runs inside of a GTest death test. This is // necessary, as most of our tests by definition make global and irreversible @@ -88,9 +90,10 @@ bool IsRunningOnValgrind(); ((expr) ? static_cast<void>(0) : sandbox::UnitTests::AssertionFailure( \ SANDBOX_STR(expr), __FILE__, __LINE__)) +// This class allows to run unittests in their own process. The main method is +// RunTestInProcess(). class UnitTests { public: - typedef void (*Test)(void*); typedef void (*DeathCheck)(int status, const std::string& msg, const void* aux); @@ -99,8 +102,12 @@ class UnitTests { // directly. It is automatically invoked by SANDBOX_TEST(). Most sandboxing // functions make global irreversible changes to the execution environment // and must therefore execute in their own isolated process. - static void RunTestInProcess(Test test, - void* arg, + // |test_runner| must implement the SandboxTestRunner interface and will run + // in a subprocess. + // Note: since the child process (created with fork()) will never return from + // RunTestInProcess(), |test_runner| is guaranteed to exist for the lifetime + // of the child process. + static void RunTestInProcess(SandboxTestRunner* test_runner, DeathCheck death, const void* death_aux); |