diff options
| author | Christopher Ferris <cferris@google.com> | 2019-01-26 06:45:39 +0000 |
|---|---|---|
| committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2019-01-26 06:45:39 +0000 |
| commit | ed7ca8bb1499bfa6ae2ed00fa5f19239d2b998f1 (patch) | |
| tree | 9eceffa3fda081e29739ba2c02235ab6329ef0d8 /libunwindstack/tests | |
| parent | ce17f19bc8bdf4a852b776382e39284b80f08715 (diff) | |
| parent | e1f7a63a4d94575ac154229f686e5fc215ff0c17 (diff) | |
| download | system_core-ed7ca8bb1499bfa6ae2ed00fa5f19239d2b998f1.tar.gz system_core-ed7ca8bb1499bfa6ae2ed00fa5f19239d2b998f1.tar.bz2 system_core-ed7ca8bb1499bfa6ae2ed00fa5f19239d2b998f1.zip | |
Merge "Add a few leak check tests."
Diffstat (limited to 'libunwindstack/tests')
| -rw-r--r-- | libunwindstack/tests/TestUtils.cpp | 44 | ||||
| -rw-r--r-- | libunwindstack/tests/TestUtils.h | 2 | ||||
| -rw-r--r-- | libunwindstack/tests/UnwindOfflineTest.cpp | 38 | ||||
| -rw-r--r-- | libunwindstack/tests/UnwindTest.cpp | 66 |
4 files changed, 150 insertions, 0 deletions
diff --git a/libunwindstack/tests/TestUtils.cpp b/libunwindstack/tests/TestUtils.cpp new file mode 100644 index 000000000..e76f5f8de --- /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 8c31aa6e5..a4d7b9b33 100644 --- a/libunwindstack/tests/TestUtils.h +++ b/libunwindstack/tests/TestUtils.h @@ -50,6 +50,8 @@ inline bool TestQuiescePid(pid_t pid) { 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 0588a8444..b5feb3845 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 @@ TEST_F(UnwindOfflineTest, jit_debug_arm) { 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 c747eabc6..4e3801511 100644 --- a/libunwindstack/tests/UnwindTest.cpp +++ b/libunwindstack/tests/UnwindTest.cpp @@ -198,6 +198,21 @@ TEST_F(UnwindTest, local_use_from_pid) { 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 @@ TEST_F(UnwindTest, unwind_from_pid_remote) { << "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([&]() { |
