1 /*
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "file-inl.h"
17 #include "file_items.h"
18 #include "file_item_container.h"
19 #include "utils/string_helpers.h"
20 #include "zip_archive.h"
21 #include "file.h"
22
23 #include "assembly-emitter.h"
24 #include "assembly-parser.h"
25
26 #include <cstdint>
27 #ifdef PANDA_TARGET_MOBILE
28 #include <unistd.h>
29 #endif
30
31 #include <vector>
32
33 #include <gtest/gtest.h>
34
35 namespace panda::panda_file::test {
36
37 static constexpr const char *ABC_FILE = "test_file.abc";
38
GetPandaFile(std::vector<uint8_t> * data)39 static std::unique_ptr<const File> GetPandaFile(std::vector<uint8_t> *data)
40 {
41 os::mem::ConstBytePtr ptr(reinterpret_cast<std::byte *>(data->data()), data->size(),
42 [](std::byte *, size_t) noexcept {});
43 return File::OpenFromMemory(std::move(ptr));
44 }
45
GetEmptyPandaFileBytes()46 static std::vector<uint8_t> GetEmptyPandaFileBytes()
47 {
48 pandasm::Parser p;
49
50 auto source = R"()";
51
52 std::string src_filename = "src.pa";
53 auto res = p.Parse(source, src_filename);
54 ASSERT(p.ShowError().err == pandasm::Error::ErrorType::ERR_NONE);
55
56 auto pf = pandasm::AsmEmitter::Emit(res.Value());
57 ASSERT(pf != nullptr);
58
59 std::vector<uint8_t> data {};
60 const auto header_ptr = reinterpret_cast<const uint8_t *>(pf->GetHeader());
61 data.assign(header_ptr, header_ptr + sizeof(File::Header));
62
63 ASSERT(data.size() == sizeof(File::Header));
64
65 return data;
66 }
67
CreateOrAddZipPandaFile(std::vector<uint8_t> * data,const char * zip_archive_name,const char * filename,int append,int level)68 int CreateOrAddZipPandaFile(std::vector<uint8_t> *data, const char *zip_archive_name, const char *filename, int append,
69 int level)
70 {
71 return CreateOrAddFileIntoZip(zip_archive_name, filename, (*data).data(), (*data).size(), append, level);
72 }
73
CheckAnonMemoryName(const char * zip_archive_name)74 bool CheckAnonMemoryName([[maybe_unused]] const char *zip_archive_name)
75 {
76 // check if [annon:panda-classes.abc extracted in memory from /xx/__OpenPandaFileFromZip__.zip]
77 #ifdef PANDA_TARGET_MOBILE
78 bool result = false;
79 const char *prefix = "[anon:panda-";
80 int pid = getpid();
81 std::stringstream ss;
82 ss << "/proc/" << pid << "/maps";
83 std::ifstream f;
84 f.open(ss.str(), std::ios::in);
85 EXPECT_TRUE(f.is_open());
86 for (std::string line; std::getline(f, line);) {
87 if (line.find(prefix) != std::string::npos && line.find(zip_archive_name) != std::string::npos) {
88 result = true;
89 }
90 }
91 f.close();
92 return result;
93 #else
94 return true;
95 #endif
96 }
97
98 HWTEST(File, GetClassByName, testing::ext::TestSize.Level0)
99 {
100 ItemContainer container;
101
102 std::vector<std::string> names = {"C", "B", "A"};
103 std::vector<ClassItem *> classes;
104
105 for (auto &name : names) {
106 classes.push_back(container.GetOrCreateClassItem(name));
107 }
108
109 MemoryWriter mem_writer;
110
111 ASSERT_TRUE(container.Write(&mem_writer));
112
113 // Read panda file from memory
114
115 auto data = mem_writer.GetData();
116 auto panda_file = GetPandaFile(&data);
117 ASSERT_NE(panda_file, nullptr);
118
119 for (size_t i = 0; i < names.size(); i++) {
120 EXPECT_EQ(panda_file->GetClassId(reinterpret_cast<const uint8_t *>(names[i].c_str())).GetOffset(),
121 classes[i]->GetOffset());
122 }
123 }
124
125 HWTEST(File, OpenPandaFile, testing::ext::TestSize.Level0)
126 {
127 // Create ZIP
128 auto data = GetEmptyPandaFileBytes();
129 int ret;
130 const char *zip_filename = "__OpenPandaFile__.zip";
131 const char *filename1 = ARCHIVE_FILENAME;
132 const char *filename2 = "classses2.abc"; // just for testing.
133 ret = CreateOrAddZipPandaFile(&data, zip_filename, filename1, APPEND_STATUS_CREATE, Z_BEST_COMPRESSION);
134 ASSERT_EQ(ret, 0);
135 ret = CreateOrAddZipPandaFile(&data, zip_filename, filename2, APPEND_STATUS_ADDINZIP, Z_BEST_COMPRESSION);
136 ASSERT_EQ(ret, 0);
137
138 // Open from ZIP
139 auto pf = OpenPandaFile(zip_filename);
140 EXPECT_NE(pf, nullptr);
141 EXPECT_STREQ((pf->GetFilename()).c_str(), zip_filename);
142
143 // Open from ZIP with archive_filename
144 const char *filename3 = "classses3.abc"; // just for testing.
145 pf = OpenPandaFile(zip_filename, filename3);
146 EXPECT_NE(pf, nullptr);
147
148 remove(zip_filename);
149
150 ret = CreateOrAddZipPandaFile(&data, zip_filename, filename2, APPEND_STATUS_CREATE, Z_BEST_COMPRESSION);
151 ASSERT_EQ(ret, 0);
152
153 // Open from ZIP without default archive_filename
154 pf = OpenPandaFile(zip_filename);
155 EXPECT_EQ(pf, nullptr);
156
157 remove(zip_filename);
158 }
159
160 HWTEST(File, OpenPandaFileFromMemory, testing::ext::TestSize.Level0)
161 {
162 auto pf = OpenPandaFileFromMemory(nullptr, -1);
163 EXPECT_EQ(pf, nullptr);
164
165 pf = OpenPandaFileFromMemory(nullptr, 1U);
166 EXPECT_EQ(pf, nullptr);
167
168 std::string tag = "ArkTS Code";
169 pf = OpenPandaFileFromMemory(nullptr, -1, tag);
170 EXPECT_EQ(pf, nullptr);
171
172 tag = "";
173 pf = OpenPandaFileFromMemory(nullptr, 1U, tag);
174 EXPECT_EQ(pf, nullptr);
175 }
176
177 HWTEST(File, OpenPandaFileFromSecureMemory, testing::ext::TestSize.Level0)
178 {
179 auto pf = OpenPandaFileFromSecureMemory(nullptr, -1);
180 EXPECT_EQ(pf, nullptr);
181
182 pf = OpenPandaFileFromSecureMemory(nullptr, 1U);
183 EXPECT_EQ(pf, nullptr);
184 }
185
186 HWTEST(File, OpenPandaFileFromZipNameAnonMem, testing::ext::TestSize.Level0)
187 {
188 // Create ZIP
189 auto data = GetEmptyPandaFileBytes();
190 int ret;
191 const char *zip_filename = "__OpenPandaFileFromZipNameAnonMem__.zip";
192 const char *filename1 = ARCHIVE_FILENAME;
193 ret = CreateOrAddZipPandaFile(&data, zip_filename, filename1, APPEND_STATUS_CREATE, Z_BEST_COMPRESSION);
194 ASSERT_EQ(ret, 0);
195
196 // Open from ZIP
197 auto pf = OpenPandaFile(zip_filename);
198 EXPECT_NE(pf, nullptr);
199 EXPECT_STREQ((pf->GetFilename()).c_str(), zip_filename);
200 ASSERT_TRUE(CheckAnonMemoryName(zip_filename));
201
202 remove(zip_filename);
203 }
204
205 HWTEST(File, OpenPandaFileOrZip, testing::ext::TestSize.Level0)
206 {
207 // Create ZIP
208 auto data = GetEmptyPandaFileBytes();
209 int ret;
210 const char *zip_filename = "__OpenPandaFileOrZip__.zip";
211 const char *filename1 = ARCHIVE_FILENAME;
212 const char *filename2 = "classes2.abc"; // just for testing.
213 ret = CreateOrAddZipPandaFile(&data, zip_filename, filename1, APPEND_STATUS_CREATE, Z_BEST_COMPRESSION);
214 ASSERT_EQ(ret, 0);
215 ret = CreateOrAddZipPandaFile(&data, zip_filename, filename2, APPEND_STATUS_ADDINZIP, Z_BEST_COMPRESSION);
216 ASSERT_EQ(ret, 0);
217
218 // Open from ZIP
219 auto pf = OpenPandaFileOrZip(zip_filename);
220 EXPECT_NE(pf, nullptr);
221 EXPECT_STREQ((pf->GetFilename()).c_str(), zip_filename);
222
223 const char *zip_filename_with_entry = "__OpenPandaFileOrZip__.zip!/classes.abc";
224 auto pf_new = OpenPandaFileOrZip(zip_filename_with_entry);
225 EXPECT_NE(pf_new, nullptr);
226
227 remove(zip_filename);
228 }
229
230 HWTEST(File, OpenPandaFileFromZipErrorHandler, testing::ext::TestSize.Level0)
231 {
232 const char *file_name = "test_file_empty.panda";
233 {
234 auto writer = FileWriter(file_name);
235 ASSERT_TRUE(writer);
236 }
237 auto pf = OpenPandaFile(file_name);
238 EXPECT_EQ(pf, nullptr);
239
240 const char *file_name_zip = "test_file_empty.zip";
241 {
242 auto writer = FileWriter(file_name);
243 ASSERT_TRUE(writer);
244 const std::vector<uint8_t> magic = {'P', 'K'};
245 ASSERT_TRUE(writer.WriteBytes(magic));
246 }
247 pf = OpenPandaFile(file_name_zip);
248 EXPECT_EQ(pf, nullptr);
249
250 // Create ZIP
251 const char *file_name_zip_with_entry = "test_file_with_entry.zip";
252 std::vector<uint8_t> data = {};
253 int ret = CreateOrAddZipPandaFile(&data, file_name_zip_with_entry, ARCHIVE_FILENAME,
254 APPEND_STATUS_CREATE, Z_BEST_COMPRESSION);
255 ASSERT_EQ(ret, 0);
256 pf = OpenPandaFile(file_name_zip_with_entry);
257 EXPECT_EQ(pf, nullptr);
258
259 auto fp = fopen(file_name_zip_with_entry, "a");
260 EXPECT_NE(fp, nullptr);
261 const char append_str[] = "error";
262 EXPECT_EQ(fwrite(append_str, sizeof(append_str), 1U, fp), 1U);
263 fclose(fp);
264 pf = OpenPandaFile(file_name_zip_with_entry);
265 EXPECT_EQ(pf, nullptr);
266
267 remove(file_name);
268 remove(file_name_zip);
269 remove(file_name_zip_with_entry);
270 }
271
272 HWTEST(File, HandleArchive, testing::ext::TestSize.Level0)
273 {
274 {
275 ItemContainer container;
276 auto writer = FileWriter(ARCHIVE_FILENAME);
277 ASSERT_TRUE(container.Write(&writer));
278 ASSERT_TRUE(writer.Align(4U)); // to 4 bytes align
279 }
280
281 std::vector<uint8_t> data;
282 {
283 std::ifstream in(ARCHIVE_FILENAME, std::ios::binary);
284 data.insert(data.end(), (std::istreambuf_iterator<char>(in)), std::istreambuf_iterator<char>());
285 ASSERT_TRUE(data.size() > 0U && data.size() % 4U == 0U);
286 }
287
288 // Create ZIP
289 const char *zip_filename = "__HandleArchive__.zip";
290 int ret = CreateOrAddZipPandaFile(&data, zip_filename, ARCHIVE_FILENAME, APPEND_STATUS_CREATE, Z_NO_COMPRESSION);
291 ASSERT_EQ(ret, 0);
292 auto pf = OpenPandaFile(zip_filename);
293 EXPECT_NE(pf, nullptr);
294
295 remove(ARCHIVE_FILENAME);
296 remove(zip_filename);
297 }
298
299 HWTEST(File, CheckHeader, testing::ext::TestSize.Level0)
300 {
301 // Write panda file to disk
302 ItemContainer container;
303
304 auto writer = FileWriter(ABC_FILE);
305 ASSERT_TRUE(container.Write(&writer));
306
307 // Read panda file from disk
308 auto fp = fopen(ABC_FILE, "rb");
309 EXPECT_NE(fp, nullptr);
310
311 os::mem::ConstBytePtr ptr = os::mem::MapFile(os::file::File(fileno(fp)), os::mem::MMAP_PROT_READ,
312 os::mem::MMAP_FLAG_PRIVATE, writer.GetOffset()).ToConst();
313 EXPECT_NE(ptr.Get(), nullptr);
314 EXPECT_TRUE(CheckHeader(ptr, ABC_FILE));
315 fclose(fp);
316
317 remove(ABC_FILE);
318 }
319
320 HWTEST(File, GetMode, testing::ext::TestSize.Level0)
321 {
322 // Write panda file to disk
323 ItemContainer container;
324
325 auto writer = FileWriter(ABC_FILE);
326 ASSERT_TRUE(container.Write(&writer));
327
328 // Read panda file from disk
329 EXPECT_NE(File::Open(ABC_FILE), nullptr);
330 EXPECT_EQ(File::Open(ABC_FILE, File::OpenMode::WRITE_ONLY), nullptr);
331
332 remove(ABC_FILE);
333 }
334
335 HWTEST(File, Open, testing::ext::TestSize.Level0)
336 {
337 EXPECT_EQ(File::Open(ABC_FILE), nullptr);
338
339 auto fp = fopen(ABC_FILE, "w");
340 EXPECT_NE(fp, nullptr);
341 const char write_str[] = "error";
342 EXPECT_EQ(fwrite(write_str, sizeof(write_str), 1U, fp), 1U);
343 fclose(fp);
344 EXPECT_EQ(File::Open(ABC_FILE), nullptr);
345 EXPECT_EQ(File::Open(ABC_FILE, File::OpenMode::WRITE_ONLY), nullptr);
346
347 remove(ABC_FILE);
348 }
349
350 HWTEST(File, OpenUncompressedArchive, testing::ext::TestSize.Level0)
351 {
352 // Invalid FD
353 EXPECT_EQ(File::OpenUncompressedArchive(-1, ABC_FILE, 0U, 0U), nullptr);
354
355 // Invalid Size
356 EXPECT_EQ(File::OpenUncompressedArchive(1, ABC_FILE, 0U, 0U), nullptr);
357
358 // Invalid Max Size
359 EXPECT_EQ(File::OpenUncompressedArchive(1, ABC_FILE, -1, 0U), nullptr);
360
361 // Invalid ABC File
362 auto data = GetEmptyPandaFileBytes();
363 auto fp = fopen(ARCHIVE_FILENAME, "w+");
364 EXPECT_NE(fp, nullptr);
365 data[0] = 0U;
366 EXPECT_EQ(fwrite(data.data(), sizeof(uint8_t), data.size(), fp), data.size());
367 (void)fseek(fp, 0, SEEK_SET);
368 EXPECT_EQ(File::OpenUncompressedArchive(fileno(fp), ARCHIVE_FILENAME, sizeof(File::Header), 0U), nullptr);
369 fclose(fp);
370
371 remove(ABC_FILE);
372 }
373
374 HWTEST(File, CheckSecureMem, testing::ext::TestSize.Level0)
375 {
376 uint8_t *data1 = nullptr;
377 uintptr_t value1 = reinterpret_cast<uintptr_t>(data1);
378 bool res1 = CheckSecureMem(value1, 0); // 0: size
379 EXPECT_TRUE(res1);
380
381 int data2 = 256;
382 uintptr_t value2 = reinterpret_cast<uintptr_t>(&data2);
383 bool res2 = CheckSecureMem(value2, 1000);
384 EXPECT_TRUE(res2);
385
386 int data3 = 41235235;
387 uintptr_t value3 = reinterpret_cast<uintptr_t>(&data3);
388 bool res3 = CheckSecureMem(value3, static_cast<size_t>(243423423523));
389 EXPECT_TRUE(res3);
390 }
391
392 HWTEST(File, CheckLiteralArray, testing::ext::TestSize.Level0)
393 {
394 // Write panda file to disk
395 ItemContainer container;
396
397 auto writer = FileWriter(ABC_FILE);
398 ASSERT_TRUE(container.Write(&writer));
399
400 // Read panda file from disk
401 auto fp = fopen(ABC_FILE, "rb");
402 EXPECT_NE(fp, nullptr);
403
404 os::mem::ConstBytePtr ptr =
405 os::mem::MapFile(os::file::File(fileno(fp)), os::mem::MMAP_PROT_READ | os::mem::MMAP_PROT_WRITE,
406 os::mem::MMAP_FLAG_PRIVATE, writer.GetOffset())
407 .ToConst();
408 EXPECT_NE(ptr.Get(), nullptr);
409 EXPECT_TRUE(CheckHeader(ptr, ABC_FILE));
410
411 auto header = reinterpret_cast<File::Header *>(reinterpret_cast<uintptr_t>(ptr.Get()));
412 auto num_literalarrays = header->num_literalarrays;
413 uint32_t i = 10;
414 header->num_literalarrays = i;
415 EXPECT_FALSE(CheckHeader(ptr, ABC_FILE));
416 header->num_literalarrays = num_literalarrays;
417 header->literalarray_idx_off = i;
418 EXPECT_FALSE(CheckHeader(ptr, ABC_FILE));
419 fclose(fp);
420
421 remove(ABC_FILE);
422 }
423
424 } // namespace panda::panda_file::test
425