1 /*
2  * Copyright (C) 2011 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 "dex_file.h"
18 
19 #include <memory>
20 
21 #include "base/stl_util.h"
22 #include "base/unix_file/fd_file.h"
23 #include "common_runtime_test.h"
24 #include "dex_file-inl.h"
25 #include "os.h"
26 #include "scoped_thread_state_change.h"
27 #include "thread-inl.h"
28 
29 namespace art {
30 
31 class DexFileTest : public CommonRuntimeTest {};
32 
TEST_F(DexFileTest,Open)33 TEST_F(DexFileTest, Open) {
34   ScopedObjectAccess soa(Thread::Current());
35   std::unique_ptr<const DexFile> dex(OpenTestDexFile("Nested"));
36   ASSERT_TRUE(dex.get() != nullptr);
37 }
38 
39 static const uint8_t kBase64Map[256] = {
40   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
41   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
42   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
43   255, 255, 255, 255, 255, 255, 255,  62, 255, 255, 255,  63,
44   52,  53,  54,  55,  56,  57,  58,  59,  60,  61, 255, 255,
45   255, 254, 255, 255, 255,   0,   1,   2,   3,   4,   5,   6,
46     7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18,  // NOLINT
47    19,  20,  21,  22,  23,  24,  25, 255, 255, 255, 255, 255,  // NOLINT
48   255,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,
49    37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,  // NOLINT
50    49,  50,  51, 255, 255, 255, 255, 255, 255, 255, 255, 255,  // NOLINT
51   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
52   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
53   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
54   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
55   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
56   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
57   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
58   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
59   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
60   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
61   255, 255, 255, 255
62 };
63 
DecodeBase64(const char * src,size_t * dst_size)64 static inline uint8_t* DecodeBase64(const char* src, size_t* dst_size) {
65   std::vector<uint8_t> tmp;
66   uint32_t t = 0, y = 0;
67   int g = 3;
68   for (size_t i = 0; src[i] != '\0'; ++i) {
69     uint8_t c = kBase64Map[src[i] & 0xFF];
70     if (c == 255) continue;
71     // the final = symbols are read and used to trim the remaining bytes
72     if (c == 254) {
73       c = 0;
74       // prevent g < 0 which would potentially allow an overflow later
75       if (--g < 0) {
76         *dst_size = 0;
77         return nullptr;
78       }
79     } else if (g != 3) {
80       // we only allow = to be at the end
81       *dst_size = 0;
82       return nullptr;
83     }
84     t = (t << 6) | c;
85     if (++y == 4) {
86       tmp.push_back((t >> 16) & 255);
87       if (g > 1) {
88         tmp.push_back((t >> 8) & 255);
89       }
90       if (g > 2) {
91         tmp.push_back(t & 255);
92       }
93       y = t = 0;
94     }
95   }
96   if (y != 0) {
97     *dst_size = 0;
98     return nullptr;
99   }
100   std::unique_ptr<uint8_t[]> dst(new uint8_t[tmp.size()]);
101   if (dst_size != nullptr) {
102     *dst_size = tmp.size();
103   } else {
104     *dst_size = 0;
105   }
106   std::copy(tmp.begin(), tmp.end(), dst.get());
107   return dst.release();
108 }
109 
110 // Although this is the same content logically as the Nested test dex,
111 // the DexFileHeader test is sensitive to subtle changes in the
112 // contents due to the checksum etc, so we embed the exact input here.
113 //
114 // class Nested {
115 //     class Inner {
116 //     }
117 // }
118 static const char kRawDex[] =
119   "ZGV4CjAzNQAQedgAe7gM1B/WHsWJ6L7lGAISGC7yjD2IAwAAcAAAAHhWNBIAAAAAAAAAAMQCAAAP"
120   "AAAAcAAAAAcAAACsAAAAAgAAAMgAAAABAAAA4AAAAAMAAADoAAAAAgAAAAABAABIAgAAQAEAAK4B"
121   "AAC2AQAAvQEAAM0BAADXAQAA+wEAABsCAAA+AgAAUgIAAF8CAABiAgAAZgIAAHMCAAB5AgAAgQIA"
122   "AAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAkAAAAJAAAABgAAAAAAAAAKAAAABgAAAKgBAAAAAAEA"
123   "DQAAAAAAAQAAAAAAAQAAAAAAAAAFAAAAAAAAAAAAAAAAAAAABQAAAAAAAAAIAAAAiAEAAKsCAAAA"
124   "AAAAAQAAAAAAAAAFAAAAAAAAAAgAAACYAQAAuAIAAAAAAAACAAAAlAIAAJoCAAABAAAAowIAAAIA"
125   "AgABAAAAiAIAAAYAAABbAQAAcBACAAAADgABAAEAAQAAAI4CAAAEAAAAcBACAAAADgBAAQAAAAAA"
126   "AAAAAAAAAAAATAEAAAAAAAAAAAAAAAAAAAEAAAABAAY8aW5pdD4ABUlubmVyAA5MTmVzdGVkJElu"
127   "bmVyOwAITE5lc3RlZDsAIkxkYWx2aWsvYW5ub3RhdGlvbi9FbmNsb3NpbmdDbGFzczsAHkxkYWx2"
128   "aWsvYW5ub3RhdGlvbi9Jbm5lckNsYXNzOwAhTGRhbHZpay9hbm5vdGF0aW9uL01lbWJlckNsYXNz"
129   "ZXM7ABJMamF2YS9sYW5nL09iamVjdDsAC05lc3RlZC5qYXZhAAFWAAJWTAALYWNjZXNzRmxhZ3MA"
130   "BG5hbWUABnRoaXMkMAAFdmFsdWUAAgEABw4AAQAHDjwAAgIBDhgBAgMCCwQADBcBAgQBDhwBGAAA"
131   "AQEAAJAgAICABNQCAAABAAGAgATwAgAAEAAAAAAAAAABAAAAAAAAAAEAAAAPAAAAcAAAAAIAAAAH"
132   "AAAArAAAAAMAAAACAAAAyAAAAAQAAAABAAAA4AAAAAUAAAADAAAA6AAAAAYAAAACAAAAAAEAAAMQ"
133   "AAACAAAAQAEAAAEgAAACAAAAVAEAAAYgAAACAAAAiAEAAAEQAAABAAAAqAEAAAIgAAAPAAAArgEA"
134   "AAMgAAACAAAAiAIAAAQgAAADAAAAlAIAAAAgAAACAAAAqwIAAAAQAAABAAAAxAIAAA==";
135 
OpenDexFileBase64(const char * base64,const char * location)136 static std::unique_ptr<const DexFile> OpenDexFileBase64(const char* base64,
137                                                         const char* location) {
138   // decode base64
139   CHECK(base64 != nullptr);
140   size_t length;
141   std::unique_ptr<uint8_t[]> dex_bytes(DecodeBase64(base64, &length));
142   CHECK(dex_bytes.get() != nullptr);
143 
144   // write to provided file
145   std::unique_ptr<File> file(OS::CreateEmptyFile(location));
146   CHECK(file.get() != nullptr);
147   if (!file->WriteFully(dex_bytes.get(), length)) {
148     PLOG(FATAL) << "Failed to write base64 as dex file";
149   }
150   if (file->FlushCloseOrErase() != 0) {
151     PLOG(FATAL) << "Could not flush and close test file.";
152   }
153   file.reset();
154 
155   // read dex file
156   ScopedObjectAccess soa(Thread::Current());
157   std::string error_msg;
158   std::vector<std::unique_ptr<const DexFile>> tmp;
159   bool success = DexFile::Open(location, location, &error_msg, &tmp);
160   CHECK(success) << error_msg;
161   EXPECT_EQ(1U, tmp.size());
162   std::unique_ptr<const DexFile> dex_file = std::move(tmp[0]);
163   EXPECT_EQ(PROT_READ, dex_file->GetPermissions());
164   EXPECT_TRUE(dex_file->IsReadOnly());
165   return dex_file;
166 }
167 
TEST_F(DexFileTest,Header)168 TEST_F(DexFileTest, Header) {
169   ScratchFile tmp;
170   std::unique_ptr<const DexFile> raw(OpenDexFileBase64(kRawDex, tmp.GetFilename().c_str()));
171   ASSERT_TRUE(raw.get() != nullptr);
172 
173   const DexFile::Header& header = raw->GetHeader();
174   // TODO: header.magic_
175   EXPECT_EQ(0x00d87910U, header.checksum_);
176   // TODO: header.signature_
177   EXPECT_EQ(904U, header.file_size_);
178   EXPECT_EQ(112U, header.header_size_);
179   EXPECT_EQ(0U, header.link_size_);
180   EXPECT_EQ(0U, header.link_off_);
181   EXPECT_EQ(15U, header.string_ids_size_);
182   EXPECT_EQ(112U, header.string_ids_off_);
183   EXPECT_EQ(7U, header.type_ids_size_);
184   EXPECT_EQ(172U, header.type_ids_off_);
185   EXPECT_EQ(2U, header.proto_ids_size_);
186   EXPECT_EQ(200U, header.proto_ids_off_);
187   EXPECT_EQ(1U, header.field_ids_size_);
188   EXPECT_EQ(224U, header.field_ids_off_);
189   EXPECT_EQ(3U, header.method_ids_size_);
190   EXPECT_EQ(232U, header.method_ids_off_);
191   EXPECT_EQ(2U, header.class_defs_size_);
192   EXPECT_EQ(256U, header.class_defs_off_);
193   EXPECT_EQ(584U, header.data_size_);
194   EXPECT_EQ(320U, header.data_off_);
195 
196   EXPECT_EQ(header.checksum_, raw->GetLocationChecksum());
197 }
198 
TEST_F(DexFileTest,GetLocationChecksum)199 TEST_F(DexFileTest, GetLocationChecksum) {
200   ScopedObjectAccess soa(Thread::Current());
201   std::unique_ptr<const DexFile> raw(OpenTestDexFile("Main"));
202   EXPECT_NE(raw->GetHeader().checksum_, raw->GetLocationChecksum());
203 }
204 
TEST_F(DexFileTest,GetChecksum)205 TEST_F(DexFileTest, GetChecksum) {
206   uint32_t checksum;
207   ScopedObjectAccess soa(Thread::Current());
208   std::string error_msg;
209   EXPECT_TRUE(DexFile::GetChecksum(GetLibCoreDexFileName().c_str(), &checksum, &error_msg))
210       << error_msg;
211   EXPECT_EQ(java_lang_dex_file_->GetLocationChecksum(), checksum);
212 }
213 
TEST_F(DexFileTest,ClassDefs)214 TEST_F(DexFileTest, ClassDefs) {
215   ScopedObjectAccess soa(Thread::Current());
216   std::unique_ptr<const DexFile> raw(OpenTestDexFile("Nested"));
217   ASSERT_TRUE(raw.get() != nullptr);
218   EXPECT_EQ(2U, raw->NumClassDefs());
219 
220   const DexFile::ClassDef& c0 = raw->GetClassDef(0);
221   EXPECT_STREQ("LNested$Inner;", raw->GetClassDescriptor(c0));
222 
223   const DexFile::ClassDef& c1 = raw->GetClassDef(1);
224   EXPECT_STREQ("LNested;", raw->GetClassDescriptor(c1));
225 }
226 
TEST_F(DexFileTest,GetMethodSignature)227 TEST_F(DexFileTest, GetMethodSignature) {
228   ScopedObjectAccess soa(Thread::Current());
229   std::unique_ptr<const DexFile> raw(OpenTestDexFile("GetMethodSignature"));
230   ASSERT_TRUE(raw.get() != nullptr);
231   EXPECT_EQ(1U, raw->NumClassDefs());
232 
233   const DexFile::ClassDef& class_def = raw->GetClassDef(0);
234   ASSERT_STREQ("LGetMethodSignature;", raw->GetClassDescriptor(class_def));
235 
236   const uint8_t* class_data = raw->GetClassData(class_def);
237   ASSERT_TRUE(class_data != nullptr);
238   ClassDataItemIterator it(*raw, class_data);
239 
240   EXPECT_EQ(1u, it.NumDirectMethods());
241 
242   // Check the signature for the static initializer.
243   {
244     ASSERT_EQ(1U, it.NumDirectMethods());
245     const DexFile::MethodId& method_id = raw->GetMethodId(it.GetMemberIndex());
246     const char* name = raw->StringDataByIdx(method_id.name_idx_);
247     ASSERT_STREQ("<init>", name);
248     std::string signature(raw->GetMethodSignature(method_id).ToString());
249     ASSERT_EQ("()V", signature);
250   }
251 
252   // Check both virtual methods.
253   ASSERT_EQ(2U, it.NumVirtualMethods());
254   {
255     it.Next();
256     const DexFile::MethodId& method_id = raw->GetMethodId(it.GetMemberIndex());
257 
258     const char* name = raw->StringDataByIdx(method_id.name_idx_);
259     ASSERT_STREQ("m1", name);
260 
261     std::string signature(raw->GetMethodSignature(method_id).ToString());
262     ASSERT_EQ("(IDJLjava/lang/Object;)Ljava/lang/Float;", signature);
263   }
264 
265   {
266     it.Next();
267     const DexFile::MethodId& method_id = raw->GetMethodId(it.GetMemberIndex());
268 
269     const char* name = raw->StringDataByIdx(method_id.name_idx_);
270     ASSERT_STREQ("m2", name);
271 
272     std::string signature(raw->GetMethodSignature(method_id).ToString());
273     ASSERT_EQ("(ZSC)LGetMethodSignature;", signature);
274   }
275 }
276 
TEST_F(DexFileTest,FindStringId)277 TEST_F(DexFileTest, FindStringId) {
278   ScopedObjectAccess soa(Thread::Current());
279   std::unique_ptr<const DexFile> raw(OpenTestDexFile("GetMethodSignature"));
280   ASSERT_TRUE(raw.get() != nullptr);
281   EXPECT_EQ(1U, raw->NumClassDefs());
282 
283   const char* strings[] = { "LGetMethodSignature;", "Ljava/lang/Float;", "Ljava/lang/Object;",
284       "D", "I", "J", nullptr };
285   for (size_t i = 0; strings[i] != nullptr; i++) {
286     const char* str = strings[i];
287     const DexFile::StringId* str_id = raw->FindStringId(str);
288     const char* dex_str = raw->GetStringData(*str_id);
289     EXPECT_STREQ(dex_str, str);
290   }
291 }
292 
TEST_F(DexFileTest,FindTypeId)293 TEST_F(DexFileTest, FindTypeId) {
294   for (size_t i = 0; i < java_lang_dex_file_->NumTypeIds(); i++) {
295     const char* type_str = java_lang_dex_file_->StringByTypeIdx(i);
296     const DexFile::StringId* type_str_id = java_lang_dex_file_->FindStringId(type_str);
297     ASSERT_TRUE(type_str_id != nullptr);
298     uint32_t type_str_idx = java_lang_dex_file_->GetIndexForStringId(*type_str_id);
299     const DexFile::TypeId* type_id = java_lang_dex_file_->FindTypeId(type_str_idx);
300     ASSERT_TRUE(type_id != nullptr);
301     EXPECT_EQ(java_lang_dex_file_->GetIndexForTypeId(*type_id), i);
302   }
303 }
304 
TEST_F(DexFileTest,FindProtoId)305 TEST_F(DexFileTest, FindProtoId) {
306   for (size_t i = 0; i < java_lang_dex_file_->NumProtoIds(); i++) {
307     const DexFile::ProtoId& to_find = java_lang_dex_file_->GetProtoId(i);
308     const DexFile::TypeList* to_find_tl = java_lang_dex_file_->GetProtoParameters(to_find);
309     std::vector<uint16_t> to_find_types;
310     if (to_find_tl != nullptr) {
311       for (size_t j = 0; j < to_find_tl->Size(); j++) {
312         to_find_types.push_back(to_find_tl->GetTypeItem(j).type_idx_);
313       }
314     }
315     const DexFile::ProtoId* found =
316         java_lang_dex_file_->FindProtoId(to_find.return_type_idx_, to_find_types);
317     ASSERT_TRUE(found != nullptr);
318     EXPECT_EQ(java_lang_dex_file_->GetIndexForProtoId(*found), i);
319   }
320 }
321 
TEST_F(DexFileTest,FindMethodId)322 TEST_F(DexFileTest, FindMethodId) {
323   for (size_t i = 0; i < java_lang_dex_file_->NumMethodIds(); i++) {
324     const DexFile::MethodId& to_find = java_lang_dex_file_->GetMethodId(i);
325     const DexFile::TypeId& klass = java_lang_dex_file_->GetTypeId(to_find.class_idx_);
326     const DexFile::StringId& name = java_lang_dex_file_->GetStringId(to_find.name_idx_);
327     const DexFile::ProtoId& signature = java_lang_dex_file_->GetProtoId(to_find.proto_idx_);
328     const DexFile::MethodId* found = java_lang_dex_file_->FindMethodId(klass, name, signature);
329     ASSERT_TRUE(found != nullptr) << "Didn't find method " << i << ": "
330         << java_lang_dex_file_->StringByTypeIdx(to_find.class_idx_) << "."
331         << java_lang_dex_file_->GetStringData(name)
332         << java_lang_dex_file_->GetMethodSignature(to_find);
333     EXPECT_EQ(java_lang_dex_file_->GetIndexForMethodId(*found), i);
334   }
335 }
336 
TEST_F(DexFileTest,FindFieldId)337 TEST_F(DexFileTest, FindFieldId) {
338   for (size_t i = 0; i < java_lang_dex_file_->NumFieldIds(); i++) {
339     const DexFile::FieldId& to_find = java_lang_dex_file_->GetFieldId(i);
340     const DexFile::TypeId& klass = java_lang_dex_file_->GetTypeId(to_find.class_idx_);
341     const DexFile::StringId& name = java_lang_dex_file_->GetStringId(to_find.name_idx_);
342     const DexFile::TypeId& type = java_lang_dex_file_->GetTypeId(to_find.type_idx_);
343     const DexFile::FieldId* found = java_lang_dex_file_->FindFieldId(klass, name, type);
344     ASSERT_TRUE(found != nullptr) << "Didn't find field " << i << ": "
345         << java_lang_dex_file_->StringByTypeIdx(to_find.type_idx_) << " "
346         << java_lang_dex_file_->StringByTypeIdx(to_find.class_idx_) << "."
347         << java_lang_dex_file_->GetStringData(name);
348     EXPECT_EQ(java_lang_dex_file_->GetIndexForFieldId(*found), i);
349   }
350 }
351 
TEST_F(DexFileTest,GetMultiDexClassesDexName)352 TEST_F(DexFileTest, GetMultiDexClassesDexName) {
353   ASSERT_EQ("classes.dex", DexFile::GetMultiDexClassesDexName(0));
354   ASSERT_EQ("classes2.dex", DexFile::GetMultiDexClassesDexName(1));
355   ASSERT_EQ("classes3.dex", DexFile::GetMultiDexClassesDexName(2));
356   ASSERT_EQ("classes100.dex", DexFile::GetMultiDexClassesDexName(99));
357 }
358 
TEST_F(DexFileTest,GetMultiDexLocation)359 TEST_F(DexFileTest, GetMultiDexLocation) {
360   std::string dex_location_str = "/system/app/framework.jar";
361   const char* dex_location = dex_location_str.c_str();
362   ASSERT_EQ("/system/app/framework.jar", DexFile::GetMultiDexLocation(0, dex_location));
363   ASSERT_EQ("/system/app/framework.jar:classes2.dex",
364             DexFile::GetMultiDexLocation(1, dex_location));
365   ASSERT_EQ("/system/app/framework.jar:classes101.dex",
366             DexFile::GetMultiDexLocation(100, dex_location));
367 }
368 
TEST_F(DexFileTest,GetDexCanonicalLocation)369 TEST_F(DexFileTest, GetDexCanonicalLocation) {
370   ScratchFile file;
371   UniqueCPtr<const char[]> dex_location_real(realpath(file.GetFilename().c_str(), nullptr));
372   std::string dex_location(dex_location_real.get());
373 
374   ASSERT_EQ(dex_location, DexFile::GetDexCanonicalLocation(dex_location.c_str()));
375   std::string multidex_location = DexFile::GetMultiDexLocation(1, dex_location.c_str());
376   ASSERT_EQ(multidex_location, DexFile::GetDexCanonicalLocation(multidex_location.c_str()));
377 
378   std::string dex_location_sym = dex_location + "symlink";
379   ASSERT_EQ(0, symlink(dex_location.c_str(), dex_location_sym.c_str()));
380 
381   ASSERT_EQ(dex_location, DexFile::GetDexCanonicalLocation(dex_location_sym.c_str()));
382 
383   std::string multidex_location_sym = DexFile::GetMultiDexLocation(1, dex_location_sym.c_str());
384   ASSERT_EQ(multidex_location, DexFile::GetDexCanonicalLocation(multidex_location_sym.c_str()));
385 
386   ASSERT_EQ(0, unlink(dex_location_sym.c_str()));
387 }
388 
TEST(DexFileUtilsTest,GetBaseLocationAndMultiDexSuffix)389 TEST(DexFileUtilsTest, GetBaseLocationAndMultiDexSuffix) {
390   EXPECT_EQ("/foo/bar/baz.jar", DexFile::GetBaseLocation("/foo/bar/baz.jar"));
391   EXPECT_EQ("/foo/bar/baz.jar", DexFile::GetBaseLocation("/foo/bar/baz.jar:classes2.dex"));
392   EXPECT_EQ("/foo/bar/baz.jar", DexFile::GetBaseLocation("/foo/bar/baz.jar:classes8.dex"));
393   EXPECT_EQ("", DexFile::GetMultiDexSuffix("/foo/bar/baz.jar"));
394   EXPECT_EQ(":classes2.dex", DexFile::GetMultiDexSuffix("/foo/bar/baz.jar:classes2.dex"));
395   EXPECT_EQ(":classes8.dex", DexFile::GetMultiDexSuffix("/foo/bar/baz.jar:classes8.dex"));
396 }
397 
398 }  // namespace art
399