xref: /aosp_15_r20/system/unwinding/libunwindstack/tests/DexFileTest.cpp (revision eb293b8f56ee8303637c5595cfcdeef8039e85c6)
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <malloc.h>
18 #include <stdint.h>
19 #include <sys/types.h>
20 #include <unistd.h>
21 
22 #include <memory>
23 #include <unordered_map>
24 
25 #include <MemoryLocal.h>
26 #include <android-base/file.h>
27 #include <gtest/gtest.h>
28 #include <unwindstack/MapInfo.h>
29 #include <unwindstack/Memory.h>
30 
31 #include "DexFile.h"
32 #include "DexFileData.h"
33 #include "utils/MemoryFake.h"
34 
35 namespace unwindstack {
36 
37 static constexpr size_t kNumLeakLoops = 5000;
38 static constexpr size_t kMaxAllowedLeakBytes = 4 * 1024;
39 
CheckForLeak(size_t loop,size_t * first_allocated_bytes,size_t * last_allocated_bytes)40 static void CheckForLeak(size_t loop, size_t* first_allocated_bytes, size_t* last_allocated_bytes) {
41   size_t allocated_bytes = mallinfo().uordblks;
42   if (*first_allocated_bytes == 0) {
43     *first_allocated_bytes = allocated_bytes;
44   } else if (*last_allocated_bytes > *first_allocated_bytes) {
45     // Check that the total memory did not increase too much over the first loop.
46     ASSERT_LE(*last_allocated_bytes - *first_allocated_bytes, kMaxAllowedLeakBytes)
47         << "Failed in loop " << loop << " first_allocated_bytes " << *first_allocated_bytes
48         << " last_allocated_bytes " << *last_allocated_bytes;
49   }
50   *last_allocated_bytes = allocated_bytes;
51 }
52 
TEST(DexFileTest,from_file_no_leak)53 TEST(DexFileTest, from_file_no_leak) {
54 #if !defined(__BIONIC__)
55   GTEST_SKIP() << "Leak checking depends on bionic.";
56 #endif
57 
58   TemporaryFile tf;
59   ASSERT_TRUE(tf.fd != -1);
60 
61   ASSERT_EQ(sizeof(kDexData),
62             static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
63 
64   size_t first_allocated_bytes = 0;
65   size_t last_allocated_bytes = 0;
66   for (size_t i = 0; i < kNumLeakLoops; i++) {
67     MemoryFake memory;
68     auto info = MapInfo::Create(0, 0x10000, 0, 0x5, tf.path);
69     EXPECT_TRUE(DexFile::Create(0, sizeof(kDexData), &memory, info.get()) != nullptr);
70     ASSERT_NO_FATAL_FAILURE(CheckForLeak(i, &first_allocated_bytes, &last_allocated_bytes));
71   }
72 }
73 
TEST(DexFileTest,from_memory_no_leak)74 TEST(DexFileTest, from_memory_no_leak) {
75 #if !defined(__BIONIC__)
76   GTEST_SKIP() << "Leak checking depends on bionic.";
77 #endif
78 
79   MemoryFake memory;
80 
81   memory.SetMemory(0x1000, kDexData, sizeof(kDexData));
82 
83   size_t first_allocated_bytes = 0;
84   size_t last_allocated_bytes = 0;
85   for (size_t i = 0; i < kNumLeakLoops; i++) {
86     EXPECT_TRUE(DexFile::Create(0x1000, sizeof(kDexData), &memory, nullptr) != nullptr);
87     ASSERT_NO_FATAL_FAILURE(CheckForLeak(i, &first_allocated_bytes, &last_allocated_bytes));
88   }
89 }
90 
TEST(DexFileTest,create_using_file)91 TEST(DexFileTest, create_using_file) {
92   TemporaryFile tf;
93   ASSERT_TRUE(tf.fd != -1);
94 
95   ASSERT_EQ(0x500, lseek(tf.fd, 0x500, SEEK_SET));
96   ASSERT_EQ(sizeof(kDexData),
97             static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
98 
99   MemoryFake memory;
100   auto info = MapInfo::Create(0, 0x10000, 0, 0x5, tf.path);
101   EXPECT_TRUE(DexFile::Create(0x500, sizeof(kDexData), &memory, info.get()) != nullptr);
102 }
103 
TEST(DexFileTest,create_using_file_non_zero_start)104 TEST(DexFileTest, create_using_file_non_zero_start) {
105   TemporaryFile tf;
106   ASSERT_TRUE(tf.fd != -1);
107 
108   ASSERT_EQ(0x500, lseek(tf.fd, 0x500, SEEK_SET));
109   ASSERT_EQ(sizeof(kDexData),
110             static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
111 
112   MemoryFake memory;
113   auto info = MapInfo::Create(0x100, 0x10000, 0, 0x5, tf.path);
114   EXPECT_TRUE(DexFile::Create(0x600, sizeof(kDexData), &memory, info.get()) != nullptr);
115 }
116 
TEST(DexFileTest,create_using_file_non_zero_offset)117 TEST(DexFileTest, create_using_file_non_zero_offset) {
118   TemporaryFile tf;
119   ASSERT_TRUE(tf.fd != -1);
120 
121   ASSERT_EQ(0x500, lseek(tf.fd, 0x500, SEEK_SET));
122   ASSERT_EQ(sizeof(kDexData),
123             static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
124 
125   MemoryFake memory;
126   auto info = MapInfo::Create(0x100, 0x10000, 0x200, 0x5, tf.path);
127   EXPECT_TRUE(DexFile::Create(0x400, sizeof(kDexData), &memory, info.get()) != nullptr);
128 }
129 
TEST(DexFileTest,create_using_memory_empty_file)130 TEST(DexFileTest, create_using_memory_empty_file) {
131   MemoryFake memory;
132   memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
133   auto info = MapInfo::Create(0x100, 0x10000, 0x200, 0x5, "");
134   EXPECT_TRUE(DexFile::Create(0x4000, sizeof(kDexData), &memory, info.get()) != nullptr);
135 }
136 
TEST(DexFileTest,create_using_memory_file_does_not_exist)137 TEST(DexFileTest, create_using_memory_file_does_not_exist) {
138   MemoryFake memory;
139   memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
140   auto info = MapInfo::Create(0x100, 0x10000, 0x200, 0x5, "/does/not/exist");
141   EXPECT_TRUE(DexFile::Create(0x4000, sizeof(kDexData), &memory, info.get()) != nullptr);
142 }
143 
TEST(DexFileTest,create_using_memory_file_is_malformed)144 TEST(DexFileTest, create_using_memory_file_is_malformed) {
145   TemporaryFile tf;
146   ASSERT_TRUE(tf.fd != -1);
147 
148   ASSERT_EQ(sizeof(kDexData) - 10,
149             static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData) - 10))));
150 
151   MemoryFake memory;
152   memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
153   auto info = MapInfo::Create(0x4000, 0x10000, 0x200, 0x5, "/does/not/exist");
154   std::shared_ptr<DexFile> dex_file =
155       DexFile::Create(0x4000, sizeof(kDexData), &memory, info.get());
156   ASSERT_TRUE(dex_file != nullptr);
157 
158   // Check it came from memory by clearing memory and verifying it fails.
159   memory.Clear();
160   dex_file = DexFile::Create(0x4000, sizeof(kDexData), &memory, info.get());
161   EXPECT_TRUE(dex_file == nullptr);
162 }
163 
TEST(DexFileTest,create_using_memory_header_too_small)164 TEST(DexFileTest, create_using_memory_header_too_small) {
165   MemoryFake memory;
166   size_t size = 10;
167   memory.SetMemory(0x4000, kDexData, size);
168   EXPECT_TRUE(DexFile::Create(0x4000, size, &memory, nullptr) == nullptr);
169 }
170 
TEST(DexFileTest,create_using_memory_size_too_small)171 TEST(DexFileTest, create_using_memory_size_too_small) {
172   MemoryFake memory;
173   size_t size = sizeof(kDexData) - 1;
174   memory.SetMemory(0x4000, kDexData, size);
175   EXPECT_TRUE(DexFile::Create(0x4000, size, &memory, nullptr) == nullptr);
176 }
177 
TEST(DexFileTest,get_method)178 TEST(DexFileTest, get_method) {
179   MemoryFake memory;
180   memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
181   auto info = MapInfo::Create(0x100, 0x10000, 0x200, 0x5, "");
182   std::shared_ptr<DexFile> dex_file(DexFile::Create(0x4000, sizeof(kDexData), &memory, info.get()));
183   ASSERT_TRUE(dex_file != nullptr);
184 
185   SharedString method;
186   uint64_t method_offset;
187   ASSERT_TRUE(dex_file->GetFunctionName(0x4102, &method, &method_offset));
188   EXPECT_EQ("Main.<init>", method);
189   EXPECT_EQ(2U, method_offset);
190 
191   ASSERT_TRUE(dex_file->GetFunctionName(0x4118, &method, &method_offset));
192   EXPECT_EQ("Main.main", method);
193   EXPECT_EQ(0U, method_offset);
194 }
195 
TEST(DexFileTest,get_method_empty)196 TEST(DexFileTest, get_method_empty) {
197   MemoryFake memory;
198   memory.SetMemory(0x4000, kDexData, sizeof(kDexData));
199   auto info = MapInfo::Create(0x100, 0x10000, 0x200, 0x5, "");
200   std::shared_ptr<DexFile> dex_file(DexFile::Create(0x4000, sizeof(kDexData), &memory, info.get()));
201   ASSERT_TRUE(dex_file != nullptr);
202 
203   SharedString method;
204   uint64_t method_offset;
205   EXPECT_FALSE(dex_file->GetFunctionName(0x100000, &method, &method_offset));
206 
207   EXPECT_FALSE(dex_file->GetFunctionName(0x98, &method, &method_offset));
208 }
209 
TEST(DexFileTest,get_method_from_cache)210 TEST(DexFileTest, get_method_from_cache) {
211   TemporaryFile tf;
212   ASSERT_TRUE(tf.fd != -1);
213   ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET));
214   ASSERT_EQ(sizeof(kDexData),
215             static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
216 
217   MemoryFake memory;
218   auto info = MapInfo::Create(0x4000, 0x10000, 0, 0x5, tf.path);
219   std::shared_ptr<DexFile> dex_file =
220       DexFile::Create(0x4000, sizeof(kDexData), &memory, info.get());
221   EXPECT_TRUE(dex_file != nullptr);
222 
223   SharedString method;
224   uint64_t method_offset;
225   ASSERT_TRUE(dex_file->GetFunctionName(0x4118, &method, &method_offset));
226   EXPECT_EQ("Main.main", method);
227   EXPECT_EQ(0U, method_offset);
228 
229   // Corrupt the dex file: change the name of the class.
230   int main = std::string(reinterpret_cast<const char*>(kDexData), sizeof(kDexData)).find("Main");
231   ASSERT_EQ(main, lseek(tf.fd, main, SEEK_SET));
232   ASSERT_EQ(4u, static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, "MAIN", 4))));
233 
234   // Check that we see the *old* cached value.
235   ASSERT_TRUE(dex_file->GetFunctionName(0x4118, &method, &method_offset));
236   EXPECT_EQ("Main.main", method);
237   EXPECT_EQ(0U, method_offset);
238 
239   // Check that for other methods we see the *new* updated value.
240   ASSERT_TRUE(dex_file->GetFunctionName(0x4102, &method, &method_offset));
241   EXPECT_EQ("MAIN.<init>", method);
242   EXPECT_EQ(2U, method_offset);
243 }
244 
245 }  // namespace unwindstack
246