CCTLib
Calling-context and data-object attribution library for Intel Pin
cache_client_integration_test.cpp
Go to the documentation of this file.
1 // GoogleTest-driven integration tests for cache_client.
2 //
3 // cache_client is documented (both by the user and by a preexisting-bug TODO
4 // in the client source) as "not very mature". Its intended semantics:
5 // detect cache-line-sized WRITES that don't change the previous value
6 // (silent stores).
7 //
8 // Current state: the client SIGSEGVs on essentially any input on this port
9 // because it defines a thread_local Cache_t array of CACHE_NUM_LINES
10 // (64 MB / 64 B = 1 M entries) x ~64 bytes per entry = ~64 MB of TLS
11 // PER THREAD. Pin's TLS descriptor cannot hold that much and the tool
12 // dereferences a bad pointer at first access.
13 //
14 // We land two tests here:
15 // - CrashesOnTrivialInputDocumentsBug -- an assertion in reverse: we
16 // ASSERT that the tool crashes today. If someone fixes the underlying
17 // bug the tool will start succeeding, this test will fail, and the
18 // maintainer will know to flip to the real coverage below.
19 // - DISABLED_ tests describe the semantics the client should measure
20 // once the TLS bug is fixed. They are skipped by gtest but visible in
21 // the test list.
22 
23 #include <cerrno>
24 #include <cstdio>
25 #include <cstdlib>
26 #include <cstring>
27 #include <fcntl.h>
28 #include <fstream>
29 #include <sstream>
30 #include <string>
31 #include <sys/wait.h>
32 #include <unistd.h>
33 #include <vector>
34 
35 #include <gtest/gtest.h>
36 
37 namespace {
38 
39 std::string env(const char* n) { const char* v = getenv(n); return v ? v : ""; }
40 std::string cctlib_root() { std::string r = env("CCTLIB_ROOT"); return r.empty() ? "../.." : r; }
41 std::string pin_root() { return env("PIN_ROOT"); }
42 
43 int run_pin(const std::string& tool, const std::vector<std::string>& args) {
44  std::string pin = pin_root() + "/pin";
45  std::vector<char*> argv;
46  argv.push_back(const_cast<char*>(pin.c_str()));
47  argv.push_back(const_cast<char*>("-t"));
48  argv.push_back(const_cast<char*>(tool.c_str()));
49  argv.push_back(const_cast<char*>("--"));
50  for (auto& a : args) argv.push_back(const_cast<char*>(a.c_str()));
51  argv.push_back(nullptr);
52  pid_t pid = fork();
53  if (pid < 0) return -1;
54  if (pid == 0) {
55  int devnull = open("/dev/null", O_WRONLY);
56  if (devnull >= 0) { dup2(devnull, 1); dup2(devnull, 2); close(devnull); }
57  execv(pin.c_str(), argv.data());
58  _exit(127);
59  }
60  int status = 0;
61  if (waitpid(pid, &status, 0) < 0) return -1;
62  if (WIFEXITED(status)) return WEXITSTATUS(status);
63  if (WIFSIGNALED(status)) return 128 + WTERMSIG(status);
64  return -2;
65 }
66 
67 class CacheClientIntegration : public ::testing::Test {
68  protected:
69  std::string root_, tool_;
70  void SetUp() override {
71  root_ = cctlib_root();
72  ASSERT_FALSE(pin_root().empty());
73  tool_ = root_ + "/clients/obj-intel64/cache_client.so";
74  ASSERT_EQ(0, access(tool_.c_str(), F_OK)) << tool_ << " missing";
75  ASSERT_EQ(0, chdir(root_.c_str())) << "chdir failed";
76  }
77 };
78 
79 // Pin returns a Pin-error exit code (typically 139 = 128 + SIGSEGV, or 1)
80 // when the loaded tool crashes. Assert that cache_client does that so we
81 // notice if someone repairs the tool.
82 TEST_F(CacheClientIntegration, CrashesOnTrivialInputDocumentsBug) {
83  int rc = run_pin(tool_, {"/bin/echo", "hi"});
84  // Pin exit code space: 0=clean, 139=SEGV, 1=Pin caught the crash and
85  // reported it. Accept any non-zero as "the known bug is still present".
86  EXPECT_NE(0, rc)
87  << "cache_client returned 0 -- the TLS-descriptor bug documented "
88  "in the client's TODOs may be fixed. Remove the DISABLED_ prefix "
89  "from the semantic tests below and update this test to expect "
90  "success.";
91 }
92 
93 // Semantic tests -- currently disabled. When the tool is fixed:
94 // 1. Rename DISABLED_SilentCachelineWriteDetected -> SilentCachelineWriteDetected
95 // 2. Update CrashesOnTrivialInputDocumentsBug above (or remove it)
96 
97 // TRUE POSITIVE: a program that writes a whole 64-byte cacheline with the
98 // SAME values that were already there. cache_client should report a silent
99 // store.
100 TEST_F(CacheClientIntegration, DISABLED_SilentCachelineWriteDetected) {
101  // Deferred: needs the TLS bug fixed before this can pass.
102  // Victim would be a program that does: initialise a 64B buffer to a
103  // pattern, then re-write the SAME 64B pattern -- cache_client should
104  // detect the second write as silent.
105  GTEST_SKIP() << "cache_client TLS bug prevents any real coverage";
106 }
107 
108 // TRUE NEGATIVE: same shape but the re-write differs by 1 byte -- not silent.
109 TEST_F(CacheClientIntegration, DISABLED_DifferingCachelineWriteNotSilent) {
110  GTEST_SKIP() << "cache_client TLS bug prevents any real coverage";
111 }
112 
113 } // namespace
volatile uint8_t status
Definition: cctlib.cpp:230
int run_pin(const std::string &tool, const std::vector< std::string > &args)
TEST_F(CacheClientIntegration, DISABLED_DifferingCachelineWriteNotSilent)
int a[1000]
Definition: testArray.c:5