Add a few leak check tests.

These tests are meant to replace the leak check tests from libbacktrace.

Bug: 120606663

Test: Ran tests on host and target.
Change-Id: I928b199304afc36b4bac78e9a2cd688b6f2910b9
diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp
index d1b8271..c90f5b2 100644
--- a/libunwindstack/Android.bp
+++ b/libunwindstack/Android.bp
@@ -212,6 +212,7 @@
         "tests/RegsStepIfSignalHandlerTest.cpp",
         "tests/RegsTest.cpp",
         "tests/SymbolsTest.cpp",
+        "tests/TestUtils.cpp",
         "tests/UnwindOfflineTest.cpp",
         "tests/UnwindTest.cpp",
         "tests/UnwinderTest.cpp",
diff --git a/libunwindstack/tests/TestUtils.cpp b/libunwindstack/tests/TestUtils.cpp
new file mode 100644
index 0000000..e76f5f8
--- /dev/null
+++ b/libunwindstack/tests/TestUtils.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <malloc.h>
+#include <stdint.h>
+
+#include <gtest/gtest.h>
+
+namespace unwindstack {
+
+void TestCheckForLeaks(void (*unwind_func)(void*), void* data) {
+  static constexpr size_t kNumLeakLoops = 200;
+  static constexpr size_t kMaxAllowedLeakBytes = 32 * 1024;
+
+  size_t first_allocated_bytes = 0;
+  size_t last_allocated_bytes = 0;
+  for (size_t i = 0; i < kNumLeakLoops; i++) {
+    unwind_func(data);
+
+    size_t allocated_bytes = mallinfo().uordblks;
+    if (first_allocated_bytes == 0) {
+      first_allocated_bytes = allocated_bytes;
+    } else if (last_allocated_bytes > first_allocated_bytes) {
+      // Check that the memory did not increase too much over the first loop.
+      ASSERT_LE(last_allocated_bytes - first_allocated_bytes, kMaxAllowedLeakBytes);
+    }
+    last_allocated_bytes = allocated_bytes;
+  }
+}
+
+}  // namespace unwindstack
diff --git a/libunwindstack/tests/TestUtils.h b/libunwindstack/tests/TestUtils.h
index 8c31aa6..a4d7b9b 100644
--- a/libunwindstack/tests/TestUtils.h
+++ b/libunwindstack/tests/TestUtils.h
@@ -50,6 +50,8 @@
   return ready;
 }
 
+void TestCheckForLeaks(void (*unwind_func)(void*), void* data);
+
 }  // namespace unwindstack
 
 #endif  // _LIBUNWINDSTACK_TESTS_TEST_UTILS_H
diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp
index 0588a84..b5feb38 100644
--- a/libunwindstack/tests/UnwindOfflineTest.cpp
+++ b/libunwindstack/tests/UnwindOfflineTest.cpp
@@ -43,6 +43,7 @@
 #include <unwindstack/Unwinder.h>
 
 #include "ElfTestUtils.h"
+#include "TestUtils.h"
 
 namespace unwindstack {
 
@@ -901,6 +902,43 @@
   EXPECT_EQ(0xff85f0c0U, unwinder.frames()[75].sp);
 }
 
+struct LeakType {
+  LeakType(Maps* maps, Regs* regs, std::shared_ptr<Memory>& process_memory)
+      : maps(maps), regs(regs), process_memory(process_memory) {}
+
+  Maps* maps;
+  Regs* regs;
+  std::shared_ptr<Memory>& process_memory;
+};
+
+static void OfflineUnwind(void* data) {
+  LeakType* leak_data = reinterpret_cast<LeakType*>(data);
+
+  std::unique_ptr<Regs> regs_copy(leak_data->regs->Clone());
+  JitDebug jit_debug(leak_data->process_memory);
+  Unwinder unwinder(128, leak_data->maps, regs_copy.get(), leak_data->process_memory);
+  unwinder.SetJitDebug(&jit_debug, regs_copy->Arch());
+  unwinder.Unwind();
+  ASSERT_EQ(76U, unwinder.NumFrames());
+}
+
+TEST_F(UnwindOfflineTest, unwind_offline_check_for_leaks) {
+  ASSERT_NO_FATAL_FAILURE(Init("jit_debug_arm/", ARCH_ARM));
+
+  MemoryOfflineParts* memory = new MemoryOfflineParts;
+  AddMemory(dir_ + "descriptor.data", memory);
+  AddMemory(dir_ + "descriptor1.data", memory);
+  AddMemory(dir_ + "stack.data", memory);
+  for (size_t i = 0; i < 7; i++) {
+    AddMemory(dir_ + "entry" + std::to_string(i) + ".data", memory);
+    AddMemory(dir_ + "jit" + std::to_string(i) + ".data", memory);
+  }
+  process_memory_.reset(memory);
+
+  LeakType data(maps_.get(), regs_.get(), process_memory_);
+  TestCheckForLeaks(OfflineUnwind, &data);
+}
+
 // The eh_frame_hdr data is present but set to zero fdes. This should
 // fallback to iterating over the cies/fdes and ignore the eh_frame_hdr.
 // No .gnu_debugdata section in the elf file, so no symbols.
diff --git a/libunwindstack/tests/UnwindTest.cpp b/libunwindstack/tests/UnwindTest.cpp
index c747eab..4e38015 100644
--- a/libunwindstack/tests/UnwindTest.cpp
+++ b/libunwindstack/tests/UnwindTest.cpp
@@ -198,6 +198,21 @@
   OuterFunction(TEST_TYPE_LOCAL_UNWINDER_FROM_PID);
 }
 
+static void LocalUnwind(void* data) {
+  TestTypeEnum* test_type = reinterpret_cast<TestTypeEnum*>(data);
+  OuterFunction(*test_type);
+}
+
+TEST_F(UnwindTest, local_check_for_leak) {
+  TestTypeEnum test_type = TEST_TYPE_LOCAL_UNWINDER;
+  TestCheckForLeaks(LocalUnwind, &test_type);
+}
+
+TEST_F(UnwindTest, local_use_from_pid_check_for_leak) {
+  TestTypeEnum test_type = TEST_TYPE_LOCAL_UNWINDER_FROM_PID;
+  TestCheckForLeaks(LocalUnwind, &test_type);
+}
+
 void WaitForRemote(pid_t pid, uint64_t addr, bool leave_attached, bool* completed) {
   *completed = false;
   // Need to sleep before attempting first ptrace. Without this, on the
@@ -279,6 +294,57 @@
       << "ptrace detach failed with unexpected error: " << strerror(errno);
 }
 
+static void RemoteCheckForLeaks(void (*unwind_func)(void*)) {
+  pid_t pid;
+  if ((pid = fork()) == 0) {
+    OuterFunction(TEST_TYPE_REMOTE);
+    exit(0);
+  }
+  ASSERT_NE(-1, pid);
+  TestScopedPidReaper reap(pid);
+
+  bool completed;
+  WaitForRemote(pid, reinterpret_cast<uint64_t>(&g_ready_for_remote), true, &completed);
+  ASSERT_TRUE(completed) << "Timed out waiting for remote process to be ready.";
+
+  TestCheckForLeaks(unwind_func, &pid);
+
+  ASSERT_EQ(0, ptrace(PTRACE_DETACH, pid, 0, 0))
+      << "ptrace detach failed with unexpected error: " << strerror(errno);
+}
+
+static void RemoteUnwind(void* data) {
+  pid_t* pid = reinterpret_cast<pid_t*>(data);
+
+  RemoteMaps maps(*pid);
+  ASSERT_TRUE(maps.Parse());
+  std::unique_ptr<Regs> regs(Regs::RemoteGet(*pid));
+  ASSERT_TRUE(regs.get() != nullptr);
+
+  VerifyUnwind(*pid, &maps, regs.get(), kFunctionOrder);
+}
+
+TEST_F(UnwindTest, remote_check_for_leaks) {
+  RemoteCheckForLeaks(RemoteUnwind);
+}
+
+static void RemoteUnwindFromPid(void* data) {
+  pid_t* pid = reinterpret_cast<pid_t*>(data);
+
+  std::unique_ptr<Regs> regs(Regs::RemoteGet(*pid));
+  ASSERT_TRUE(regs.get() != nullptr);
+
+  UnwinderFromPid unwinder(512, *pid);
+  ASSERT_TRUE(unwinder.Init(regs->Arch()));
+  unwinder.SetRegs(regs.get());
+
+  VerifyUnwind(&unwinder, kFunctionOrder);
+}
+
+TEST_F(UnwindTest, remote_unwind_for_pid_check_for_leaks) {
+  RemoteCheckForLeaks(RemoteUnwindFromPid);
+}
+
 TEST_F(UnwindTest, from_context) {
   std::atomic_int tid(0);
   std::thread thread([&]() {