Chromium Code Reviews| Index: sandbox/linux/tests/unit_tests.cc |
| diff --git a/sandbox/linux/tests/unit_tests.cc b/sandbox/linux/tests/unit_tests.cc |
| index 2e24d8c07c8ffa27386099f439bbda83b1894e2c..748aae15a66e35341b3dd40b69b883083a98bed4 100644 |
| --- a/sandbox/linux/tests/unit_tests.cc |
| +++ b/sandbox/linux/tests/unit_tests.cc |
| @@ -2,7 +2,91 @@ |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| -#include "testing/gtest/include/gtest/gtest.h" |
| +#include <stdio.h> |
| +#include <sys/resource.h> |
| +#include <sys/time.h> |
| + |
| +#include "base/file_util.h" |
| +#include "sandbox/linux/seccomp-bpf/die.h" |
| +#include "sandbox/linux/tests/unit_tests.h" |
| + |
| +// Allow us to intercept fatal errors in the seccomp BPF sandbox and write |
| +// unittests that check whether they were raised as expected. This code is |
| +// harmless when used with any of the other sandboxes. But of course, |
| +// SANDBOX_ASSERT_DEATH() is only useable for seccomp BPF. |
| +using playground2::Die; |
| + |
| +void UnitTests::RunTestInProcess(UnitTests::Test test) { |
| + // Runs a test in a sub-process. This is necessary for most of the code |
| + // 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. |
| + int fds[2]; |
| + ASSERT_EQ(pipe(fds), 0); |
| + |
| + pid_t pid; |
| + ASSERT_GE((pid = fork()), 0); |
| + if (!pid) { |
| + // In child process |
| + // Set up the error handler that is used by the BPF sandbox so that it |
| + // logs messages to our pipe. It should include file names and line numbers |
| + // but no stack traces. |
| + // Die::LogToStderr() does what we want to do. |
| + SANDBOX_ASSERT(dup2(fds[1], 2) == 2); |
| + SANDBOX_ASSERT(!close(fds[0])); |
| + SANDBOX_ASSERT(!close(fds[1])); |
| + Die custom_handler(Die::LogToStderr); |
| + |
| + // Disable core files. They are not very useful for our individual test |
| + // cases. |
| + struct rlimit no_core = { 0 }; |
| + setrlimit(RLIMIT_CORE, &no_core); |
| + |
| + SANDBOX_ASSERT(test()); |
| + _exit(1); |
| + } |
| + |
| + HANDLE_EINTR(close(fds[1])); |
| + std::vector<char> msg; |
| + ssize_t rc; |
| + do { |
| + const int kCapacity = 256; |
| + size_t len = msg.size(); |
| + msg.resize(len + kCapacity); |
| + rc = HANDLE_EINTR(read(fds[0], &msg[len], kCapacity)); |
| + msg.resize(len + std::max(rc, static_cast<ssize_t>(0))); |
| + } while (rc > 0); |
| + HANDLE_EINTR(close(fds[0])); |
| + EXPECT_EQ(msg.size(), 0u) << std::string(msg.begin(), msg.end()); |
| + |
| + int status; |
| + HANDLE_EINTR(waitpid(pid, &status, 0)); |
| +} |
| + |
| +void UnitTests::CaptureError(const char *msg, const char *file, int line) { |
| + if (msg) { |
| + last_error_ = msg; |
| + } else { |
| + last_error_.clear(); |
| + } |
| + |
| + // The use of longjmp() can cause us to not destroy objects that have |
| + // gone out of scope. This is OK. We only ever use this code in cases |
| + // were we want to test that a fatal error has been raised. And the |
| + // code that raises these errors isn't prepared to deal with clean up |
| + // after the error anyway. |
| + // Leaking of resources is fine in this case, because we only ever do |
| + // so from within sub-processes; and the sub-processes either die themselves |
| + // upon test failure, or they call _exit() (note the underscore). |
| + longjmp(jmp_env_, 1); |
| +} |
| + |
| +void UnitTests::AssertionFailure(const char *expr, const char *file, int line){ |
|
jln (very slow on Chromium)
2012/08/14 01:48:13
Style Missing space before "{"
|
| + fprintf(stderr, "%s:%d:%s\n", file, line, expr); |
| + fflush(stderr); |
| + _exit(1); |
| +} |
| + |
| int main(int argc, char *argv[]) { |
|
jln (very slow on Chromium)
2012/08/14 01:48:13
Please split this out to main.cc
|
| testing::InitGoogleTest(&argc, argv); |
| // Always go through re-execution for death tests. |
| @@ -12,3 +96,6 @@ int main(int argc, char *argv[]) { |
| ::testing::FLAGS_gtest_death_test_style = "threadsafe"; |
| return RUN_ALL_TESTS(); |
| } |
| + |
| +std::string UnitTests::last_error_; |
| +jmp_buf UnitTests::jmp_env_; |