summaryrefslogtreecommitdiffstats
path: root/sandbox/linux/tests/unit_tests.cc
blob: 105c45bc58926f9a36a81a4bd527745aff573b99 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
// Copyright (c) 2012 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 <stdio.h>
#include <sys/resource.h>
#include <sys/time.h>

#include "base/file_util.h"
#include "sandbox/linux/tests/unit_tests.h"

namespace sandbox {

static const int kExpectedValue = 42;

void UnitTests::RunTestInProcess(UnitTests::Test test, void *arg) {
  // 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(0, pipe(fds));

  pid_t pid;
  ASSERT_LE(0, (pid = fork()));
  if (!pid) {
    // In child process
    // Redirect stderr to our pipe. This way, we can capture all error
    // messages, if we decide we want to do so in our tests.
    SANDBOX_ASSERT(dup2(fds[1], 2) == 2);
    SANDBOX_ASSERT(!close(fds[0]));
    SANDBOX_ASSERT(!close(fds[1]));

    // Disable core files. They are not very useful for our individual test
    // cases.
    struct rlimit no_core = { 0 };
    setrlimit(RLIMIT_CORE, &no_core);

    test(arg);
    _exit(kExpectedValue);
  }

  (void)HANDLE_EINTR(close(fds[1]));
  std::vector<char> msg;
  ssize_t rc;
  do {
    const unsigned 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);
  std::string details;
  if (!msg.empty()) {
    details = "Actual test failure: " + std::string(msg.begin(), msg.end());
  }
  (void)HANDLE_EINTR(close(fds[0]));

  int status = 0;
  int waitpid_returned = HANDLE_EINTR(waitpid(pid, &status, 0));
  ASSERT_EQ(pid, waitpid_returned) << details;
  bool subprocess_terminated_normally = WIFEXITED(status);
  ASSERT_TRUE(subprocess_terminated_normally) << details;
  int subprocess_exit_status = WEXITSTATUS(status);
  ASSERT_EQ(kExpectedValue, subprocess_exit_status) << details;
  bool subprocess_exited_but_printed_messages = !msg.empty();
  EXPECT_FALSE(subprocess_exited_but_printed_messages) << details;
}

void UnitTests::AssertionFailure(const char *expr, const char *file,
                                 int line) {
  fprintf(stderr, "%s:%d:%s", file, line, expr);
  fflush(stderr);
  _exit(1);
}

}  // namespace