Fix memory leak of Test objects.
am: ee59d49576

Change-Id: Ibad8c7f45dc51200a4efe847ca02539fa03ff7b1
diff --git a/Isolate.cpp b/Isolate.cpp
index 3eb63ac..e2e2f33 100644
--- a/Isolate.cpp
+++ b/Isolate.cpp
@@ -203,11 +203,11 @@
       exit(ChildProcessFn(tests_[cur_test_index_]));
     }
 
-    size_t run_index = running_indices_.top();
-    running_indices_.pop();
+    size_t run_index = running_indices_.back();
+    running_indices_.pop_back();
     Test* test = new Test(tests_[cur_test_index_], cur_test_index_, run_index, read_fd.release());
+    running_by_pid_.emplace(pid, test);
     running_[run_index] = test;
-    running_by_pid_[pid] = test;
     running_by_test_index_[cur_test_index_] = test;
 
     pollfd* pollfd = &running_pollfds_[run_index];
@@ -247,7 +247,8 @@
       LOG(FATAL) << "Pid " << pid << " was not spawned by the isolation framework.";
     }
 
-    Test* test = entry->second;
+    std::unique_ptr<Test>& test_ptr = entry->second;
+    Test* test = test_ptr.get();
     test->Stop();
 
     // Read any leftover data.
@@ -312,8 +313,8 @@
     }
     finished_tests++;
     size_t test_index = test->test_index();
-    finished_.emplace(test_index, test);
-    running_indices_.push(test->run_index());
+    finished_.emplace(test_index, test_ptr.release());
+    running_indices_.push_back(test->run_index());
 
     // Remove it from all of the running indices.
     size_t run_index = test->run_index();
@@ -337,7 +338,7 @@
 
 void Isolate::CheckTestsTimeout() {
   for (auto& entry : running_by_pid_) {
-    Test* test = entry.second;
+    Test* test = entry.second.get();
     if (test->result() == TEST_TIMEOUT) {
       continue;
     }
@@ -388,8 +389,9 @@
   running_.resize(job_count);
   running_pollfds_.resize(job_count);
   memset(running_pollfds_.data(), 0, running_pollfds_.size() * sizeof(pollfd));
+  running_indices_.clear();
   for (size_t i = 0; i < job_count; i++) {
-    running_indices_.push(i);
+    running_indices_.push_back(i);
   }
 
   finished_.clear();
@@ -417,7 +419,7 @@
   ColoredPrintf(color, prefix);
   printf(" %s, listed below:\n", PluralizeString(total, " test").c_str());
   for (const auto& entry : finished_) {
-    const Test* test = entry.second;
+    const Test* test = entry.second.get();
     if (match_func(*test)) {
       ColoredPrintf(color, prefix);
       printf(" %s", test->name().c_str());
@@ -585,7 +587,7 @@
   std::vector<CaseInfo> cases;
   CaseInfo* info = nullptr;
   for (const auto& entry : finished_) {
-    const Test* test = entry.second;
+    const Test* test = entry.second.get();
     const std::string& case_name = test->case_name();
     if (test->result() == TEST_XFAIL) {
       // Skip XFAIL tests.
diff --git a/Isolate.h b/Isolate.h
index 7025afb..a0d7891 100644
--- a/Isolate.h
+++ b/Isolate.h
@@ -21,6 +21,7 @@
 #include <sys/types.h>
 
 #include <map>
+#include <memory>
 #include <stack>
 #include <string>
 #include <tuple>
@@ -91,11 +92,11 @@
 
   std::vector<Test*> running_;
   std::vector<pollfd> running_pollfds_;
-  std::stack<size_t> running_indices_;
-  std::unordered_map<pid_t, Test*> running_by_pid_;
+  std::vector<size_t> running_indices_;
+  std::unordered_map<pid_t, std::unique_ptr<Test>> running_by_pid_;
   std::map<size_t, Test*> running_by_test_index_;
 
-  std::map<size_t, Test*> finished_;
+  std::map<size_t, std::unique_ptr<Test>> finished_;
 
   static constexpr useconds_t MIN_USECONDS_WAIT = 1000;
 };
diff --git a/tests/SystemTests.cpp b/tests/SystemTests.cpp
index 61b0f13..194731c 100644
--- a/tests/SystemTests.cpp
+++ b/tests/SystemTests.cpp
@@ -15,6 +15,7 @@
  */
 
 #include <fcntl.h>
+#include <malloc.h>
 #include <signal.h>
 #include <stdio.h>
 #include <sys/types.h>
@@ -27,6 +28,7 @@
 #include <vector>
 
 #include <android-base/file.h>
+#include <android-base/strings.h>
 #include <android-base/test_utils.h>
 #include <gtest/gtest.h>
 
@@ -978,6 +980,52 @@
   ASSERT_EQ(0, WEXITSTATUS(status));
 }
 
+TEST_F(SystemTests, verify_memory) {
+  // This test verifies that memory isn't leaking when running repeatedly.
+  std::vector<const char*> args{"--gtest_filter=*.DISABLED_memory",
+                                "--gtest_also_run_disabled_tests", "--gtest_repeat=400"};
+  ExecAndCapture(args);
+  ASSERT_EQ(0, exitcode_) << "Test output:\n" << raw_output_;
+  std::vector<std::string> lines(android::base::Split(raw_output_, "\n"));
+
+  constexpr static size_t kMaxLeakBytes = 32 * 1024;
+  size_t memory_iteration = 0;
+  size_t memory_start = 0;
+  size_t memory_last = 0;
+  for (auto& line : lines) {
+    size_t memory;
+    if (android::base::StartsWith(line, "Allocated ") &&
+        sscanf(line.c_str(), "Allocated %zu", &memory) == 1) {
+      if (memory_iteration == 0) {
+        memory_start = memory;
+      } else {
+        // Check the increase from the last loop.
+        if (memory > memory_last) {
+          ASSERT_GT(kMaxLeakBytes, memory - memory_last)
+              << "On iteration " << memory_iteration << " memory increased beyond expected value."
+              << std::endl
+              << "Last memory bytes " << memory_last << std::endl
+              << "Current memory bytes " << memory;
+        }
+        // Check the increase from the first loop.
+        if (memory > memory_start) {
+          ASSERT_GT(kMaxLeakBytes, memory - memory_start)
+              << "On iteration " << memory_iteration
+              << " total memory increased beyond expected value." << std::endl
+              << "Starting memory bytes " << memory_start << std::endl
+              << "Current memory bytes " << memory;
+        }
+      }
+      memory_last = memory;
+      memory_iteration++;
+    }
+  }
+  ASSERT_EQ(400, memory_iteration)
+      << "Did not find the expected 400 lines of memory data." << std::endl
+      << "Raw output:" << std::endl
+      << raw_output_;
+}
+
 // These tests are used by the verify_disabled tests.
 TEST_F(SystemTests, always_pass) {}
 
@@ -1156,5 +1204,14 @@
   ASSERT_EQ(1, 0);
 }
 
+TEST(SystemTestsMemory, DISABLED_memory) {
+  struct mallinfo info = mallinfo();
+#if defined(__ANDROID__)
+  printf("Allocated %zu\n", info.uordblks);
+#else
+  printf("Allocated %d\n", info.uordblks);
+#endif
+}
+
 }  // namespace gtest_extras
 }  // namespace android