1 /*
2 * Copyright (C) 2019 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 <sys/types.h>
18
19 #include <memory>
20 #include <string>
21 #include <string_view>
22
23 #include <android-base/file.h>
24 #include <dex/dex_file.h>
25 #include <gtest/gtest.h>
26
27 #include "art_api/dex_file_support.h"
28
29 namespace art_api {
30 namespace dex {
31
32 static constexpr uint32_t kDexData[] = {
33 0x0a786564, 0x00383330, 0xc98b3ab8, 0xf3749d94, 0xaecca4d8, 0xffc7b09a, 0xdca9ca7f, 0x5be5deab,
34 0x00000220, 0x00000070, 0x12345678, 0x00000000, 0x00000000, 0x0000018c, 0x00000008, 0x00000070,
35 0x00000004, 0x00000090, 0x00000002, 0x000000a0, 0x00000000, 0x00000000, 0x00000003, 0x000000b8,
36 0x00000001, 0x000000d0, 0x00000130, 0x000000f0, 0x00000122, 0x0000012a, 0x00000132, 0x00000146,
37 0x00000151, 0x00000154, 0x00000158, 0x0000016d, 0x00000001, 0x00000002, 0x00000004, 0x00000006,
38 0x00000004, 0x00000002, 0x00000000, 0x00000005, 0x00000002, 0x0000011c, 0x00000000, 0x00000000,
39 0x00010000, 0x00000007, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000,
40 0x00000003, 0x00000000, 0x0000017e, 0x00000000, 0x00010001, 0x00000001, 0x00000173, 0x00000004,
41 0x00021070, 0x000e0000, 0x00010001, 0x00000000, 0x00000178, 0x00000001, 0x0000000e, 0x00000001,
42 0x3c060003, 0x74696e69, 0x4c06003e, 0x6e69614d, 0x4c12003b, 0x6176616a, 0x6e616c2f, 0x624f2f67,
43 0x7463656a, 0x4d09003b, 0x2e6e6961, 0x6176616a, 0x00560100, 0x004c5602, 0x6a4c5b13, 0x2f617661,
44 0x676e616c, 0x7274532f, 0x3b676e69, 0x616d0400, 0x01006e69, 0x000e0700, 0x07000103, 0x0000000e,
45 0x81000002, 0x01f00480, 0x02880901, 0x0000000c, 0x00000000, 0x00000001, 0x00000000, 0x00000001,
46 0x00000008, 0x00000070, 0x00000002, 0x00000004, 0x00000090, 0x00000003, 0x00000002, 0x000000a0,
47 0x00000005, 0x00000003, 0x000000b8, 0x00000006, 0x00000001, 0x000000d0, 0x00002001, 0x00000002,
48 0x000000f0, 0x00001001, 0x00000001, 0x0000011c, 0x00002002, 0x00000008, 0x00000122, 0x00002003,
49 0x00000002, 0x00000173, 0x00002000, 0x00000001, 0x0000017e, 0x00001000, 0x00000001, 0x0000018c,
50 };
51
TEST(DexStringTest,alloc_string)52 TEST(DexStringTest, alloc_string) {
53 auto s = DexString("123");
54 EXPECT_EQ(std::string_view(s), "123");
55 }
56
TEST(DexStringTest,alloc_empty_string)57 TEST(DexStringTest, alloc_empty_string) {
58 auto s = DexString("");
59 EXPECT_TRUE(std::string_view(s).empty());
60 }
61
TEST(DexStringTest,move_construct)62 TEST(DexStringTest, move_construct) {
63 auto s1 = DexString("foo");
64 auto s2 = DexString(std::move(s1));
65 EXPECT_TRUE(std::string_view(s1).empty()); // NOLINT bugprone-use-after-move
66 EXPECT_EQ(std::string_view(s2), "foo");
67 }
68
TEST(DexStringTest,move_assign)69 TEST(DexStringTest, move_assign) {
70 auto s1 = DexString("foo");
71 DexString s2;
72 EXPECT_TRUE(std::string_view(s2).empty());
73 s2 = std::move(s1);
74 EXPECT_TRUE(std::string_view(s1).empty()); // NOLINT bugprone-use-after-move
75 EXPECT_EQ(std::string_view(s2), "foo");
76 }
77
TEST(DexStringTest,reassign)78 TEST(DexStringTest, reassign) {
79 auto s = DexString("foo");
80 s = DexString("bar");
81 EXPECT_EQ(std::string_view(s), "bar");
82 }
83
TEST(DexStringTest,data_access)84 TEST(DexStringTest, data_access) {
85 auto s = DexString("foo");
86 EXPECT_STREQ(s.data(), "foo");
87 EXPECT_STREQ(s.c_str(), "foo");
88 }
89
TEST(DexStringTest,size_access)90 TEST(DexStringTest, size_access) {
91 auto s = DexString("foo");
92 EXPECT_EQ(s.size(), size_t{3});
93 EXPECT_EQ(s.length(), size_t{3});
94 }
95
TEST(DexStringTest,equality)96 TEST(DexStringTest, equality) {
97 auto s = DexString("foo");
98 EXPECT_EQ(s, DexString("foo"));
99 EXPECT_FALSE(s == DexString("bar"));
100 }
101
TEST(DexStringTest,equality_with_nul)102 TEST(DexStringTest, equality_with_nul) {
103 auto s = DexString(std::string("foo\0bar", 7));
104 EXPECT_EQ(s.size(), size_t{7});
105 EXPECT_EQ(s, DexString(std::string("foo\0bar", 7)));
106 EXPECT_FALSE(s == DexString(std::string("foo\0baz", 7)));
107 }
108
TEST(DexFileTest,from_memory_header_too_small)109 TEST(DexFileTest, from_memory_header_too_small) {
110 size_t size = sizeof(art::DexFile::Header) - 1;
111 std::string error_msg;
112 EXPECT_EQ(DexFile::OpenFromMemory(kDexData, &size, "", &error_msg), nullptr);
113 EXPECT_EQ(size, sizeof(art::DexFile::Header));
114 EXPECT_TRUE(error_msg.empty());
115 }
116
TEST(DexFileTest,from_memory_file_too_small)117 TEST(DexFileTest, from_memory_file_too_small) {
118 size_t size = sizeof(art::DexFile::Header);
119 std::string error_msg;
120 EXPECT_EQ(DexFile::OpenFromMemory(kDexData, &size, "", &error_msg), nullptr);
121 EXPECT_EQ(size, sizeof(kDexData));
122 EXPECT_TRUE(error_msg.empty());
123 }
124
GetTestDexData()125 static std::unique_ptr<DexFile> GetTestDexData() {
126 size_t size = sizeof(kDexData);
127 std::string error_msg;
128 std::unique_ptr<DexFile> dex_file = DexFile::OpenFromMemory(kDexData, &size, "", &error_msg);
129 EXPECT_TRUE(error_msg.empty());
130 return dex_file;
131 }
132
TEST(DexFileTest,from_memory)133 TEST(DexFileTest, from_memory) {
134 EXPECT_NE(GetTestDexData(), nullptr);
135 }
136
TEST(DexFileTest,from_fd_header_too_small)137 TEST(DexFileTest, from_fd_header_too_small) {
138 TemporaryFile tf;
139 ASSERT_NE(tf.fd, -1);
140 ASSERT_EQ(sizeof(art::DexFile::Header) - 1,
141 static_cast<size_t>(
142 TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(art::DexFile::Header) - 1))));
143
144 std::string error_msg;
145 EXPECT_EQ(DexFile::OpenFromFd(tf.fd, 0, tf.path, &error_msg), nullptr);
146 EXPECT_FALSE(error_msg.empty());
147 }
148
TEST(DexFileTest,from_fd_file_too_small)149 TEST(DexFileTest, from_fd_file_too_small) {
150 TemporaryFile tf;
151 ASSERT_NE(tf.fd, -1);
152 ASSERT_EQ(sizeof(art::DexFile::Header),
153 static_cast<size_t>(
154 TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(art::DexFile::Header)))));
155
156 std::string error_msg;
157 EXPECT_EQ(DexFile::OpenFromFd(tf.fd, 0, tf.path, &error_msg), nullptr);
158 EXPECT_FALSE(error_msg.empty());
159 }
160
TEST(DexFileTest,from_fd)161 TEST(DexFileTest, from_fd) {
162 TemporaryFile tf;
163 ASSERT_NE(tf.fd, -1);
164 ASSERT_EQ(sizeof(kDexData),
165 static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
166
167 std::string error_msg;
168 EXPECT_NE(DexFile::OpenFromFd(tf.fd, 0, tf.path, &error_msg), nullptr);
169 EXPECT_TRUE(error_msg.empty());
170 }
171
TEST(DexFileTest,from_fd_non_zero_offset)172 TEST(DexFileTest, from_fd_non_zero_offset) {
173 TemporaryFile tf;
174 ASSERT_NE(tf.fd, -1);
175 ASSERT_EQ(0x100, lseek(tf.fd, 0x100, SEEK_SET));
176 ASSERT_EQ(sizeof(kDexData),
177 static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
178
179 std::string error_msg;
180 EXPECT_NE(DexFile::OpenFromFd(tf.fd, 0x100, tf.path, &error_msg), nullptr);
181 EXPECT_TRUE(error_msg.empty());
182 }
183
TEST(DexFileTest,get_method_info_for_offset_without_signature)184 TEST(DexFileTest, get_method_info_for_offset_without_signature) {
185 std::unique_ptr<DexFile> dex_file = GetTestDexData();
186 ASSERT_NE(dex_file, nullptr);
187
188 MethodInfo info = dex_file->GetMethodInfoForOffset(0x102, false);
189 EXPECT_EQ(info.offset, int32_t{0x100});
190 EXPECT_EQ(info.len, int32_t{8});
191 EXPECT_STREQ(info.name.data(), "Main.<init>");
192
193 info = dex_file->GetMethodInfoForOffset(0x118, false);
194 EXPECT_EQ(info.offset, int32_t{0x118});
195 EXPECT_EQ(info.len, int32_t{2});
196 EXPECT_STREQ(info.name.data(), "Main.main");
197
198 // Retrieve a cached result.
199 info = dex_file->GetMethodInfoForOffset(0x104, false);
200 EXPECT_EQ(info.offset, int32_t{0x100});
201 EXPECT_EQ(info.len, int32_t{8});
202 EXPECT_STREQ(info.name.data(), "Main.<init>");
203 }
204
TEST(DexFileTest,get_method_info_for_offset_with_signature)205 TEST(DexFileTest, get_method_info_for_offset_with_signature) {
206 std::unique_ptr<DexFile> dex_file = GetTestDexData();
207 ASSERT_NE(dex_file, nullptr);
208
209 MethodInfo info = dex_file->GetMethodInfoForOffset(0x102, true);
210 EXPECT_EQ(info.offset, int32_t{0x100});
211 EXPECT_EQ(info.len, int32_t{8});
212 EXPECT_STREQ(info.name.data(), "void Main.<init>()");
213
214 info = dex_file->GetMethodInfoForOffset(0x118, true);
215 EXPECT_EQ(info.offset, int32_t{0x118});
216 EXPECT_EQ(info.len, int32_t{2});
217 EXPECT_STREQ(info.name.data(), "void Main.main(java.lang.String[])");
218
219 // Retrieve a cached result.
220 info = dex_file->GetMethodInfoForOffset(0x104, true);
221 EXPECT_EQ(info.offset, int32_t{0x100});
222 EXPECT_EQ(info.len, int32_t{8});
223 EXPECT_STREQ(info.name.data(), "void Main.<init>()");
224
225 // with_signature doesn't affect the cache.
226 info = dex_file->GetMethodInfoForOffset(0x104, false);
227 EXPECT_EQ(info.offset, int32_t{0x100});
228 EXPECT_EQ(info.len, int32_t{8});
229 EXPECT_STREQ(info.name.data(), "Main.<init>");
230 }
231
TEST(DexFileTest,get_method_info_for_offset_boundaries)232 TEST(DexFileTest, get_method_info_for_offset_boundaries) {
233 std::unique_ptr<DexFile> dex_file = GetTestDexData();
234 ASSERT_NE(dex_file, nullptr);
235
236 MethodInfo info = dex_file->GetMethodInfoForOffset(0x100000, false);
237 EXPECT_EQ(info.offset, int32_t{0});
238
239 info = dex_file->GetMethodInfoForOffset(0x99, false);
240 EXPECT_EQ(info.offset, int32_t{0});
241 info = dex_file->GetMethodInfoForOffset(0x100, false);
242 EXPECT_EQ(info.offset, int32_t{0x100});
243 info = dex_file->GetMethodInfoForOffset(0x107, false);
244 EXPECT_EQ(info.offset, int32_t{0x100});
245 info = dex_file->GetMethodInfoForOffset(0x108, false);
246 EXPECT_EQ(info.offset, int32_t{0});
247
248 // Make sure that once the whole dex file has been cached, no problems occur.
249 info = dex_file->GetMethodInfoForOffset(0x98, false);
250 EXPECT_EQ(info.offset, int32_t{0});
251
252 // Choose a value that is in the cached map, but not in a valid method.
253 info = dex_file->GetMethodInfoForOffset(0x110, false);
254 EXPECT_EQ(info.offset, int32_t{0});
255 }
256
TEST(DexFileTest,get_all_method_infos_without_signature)257 TEST(DexFileTest, get_all_method_infos_without_signature) {
258 std::unique_ptr<DexFile> dex_file = GetTestDexData();
259 ASSERT_NE(dex_file, nullptr);
260
261 std::vector<MethodInfo> infos;
262 infos.emplace_back(MethodInfo{0x100, 8, DexString("Main.<init>")});
263 infos.emplace_back(MethodInfo{0x118, 2, DexString("Main.main")});
264 ASSERT_EQ(dex_file->GetAllMethodInfos(false), infos);
265 }
266
TEST(DexFileTest,get_all_method_infos_with_signature)267 TEST(DexFileTest, get_all_method_infos_with_signature) {
268 std::unique_ptr<DexFile> dex_file = GetTestDexData();
269 ASSERT_NE(dex_file, nullptr);
270
271 std::vector<MethodInfo> infos;
272 infos.emplace_back(MethodInfo{0x100, 8, DexString("void Main.<init>()")});
273 infos.emplace_back(MethodInfo{0x118, 2, DexString("void Main.main(java.lang.String[])")});
274 ASSERT_EQ(dex_file->GetAllMethodInfos(true), infos);
275 }
276
TEST(DexFileTest,move_construct)277 TEST(DexFileTest, move_construct) {
278 std::unique_ptr<DexFile> dex_file = GetTestDexData();
279 ASSERT_NE(dex_file, nullptr);
280
281 auto df1 = DexFile(std::move(*dex_file));
282 auto df2 = DexFile(std::move(df1));
283
284 MethodInfo info = df2.GetMethodInfoForOffset(0x100, false);
285 EXPECT_EQ(info.offset, int32_t{0x100});
286 }
287
TEST(DexFileTest,pointer_construct)288 TEST(DexFileTest, pointer_construct) {
289 std::unique_ptr<DexFile> dex_file = GetTestDexData();
290 ASSERT_NE(dex_file, nullptr);
291
292 auto new_dex = DexFile(dex_file);
293 ASSERT_TRUE(dex_file.get() == nullptr);
294
295 MethodInfo info = new_dex.GetMethodInfoForOffset(0x100, false);
296 EXPECT_EQ(info.offset, int32_t{0x100});
297 }
298
299 } // namespace dex
300 } // namespace art_api
301