| /* | |
| * Copyright (C) 2022 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 "src/trace_processor/util/zip_reader.h" | |
| #include <cstdint> | |
| #include <cstring> | |
| #include <ctime> | |
| #include <string> | |
| #include <vector> | |
| #include "perfetto/base/build_config.h" | |
| #include "perfetto/base/status.h" | |
| #include "perfetto/ext/base/string_view.h" | |
| #include "perfetto/trace_processor/trace_blob.h" | |
| #include "perfetto/trace_processor/trace_blob_view.h" | |
| #include "src/base/test/status_matchers.h" | |
| #include "test/gtest_and_gmock.h" | |
| namespace perfetto::trace_processor::util { | |
| namespace { | |
| using base::gtest_matchers::IsError; | |
| // This zip file contains the following: | |
| // Zip file size: 386 bytes, number of entries: 2 | |
| // -rw-r--r-- 3.0 unx 4 tx stor 22-Jul-25 16:43 stored_file | |
| // -rw-r--r-- 3.0 unx 89 tx defN 22-Jul-25 18:34 dir/deflated_file | |
| // 2 files, 92 bytes uncompressed, 52 bytes compressed: 43.5% | |
| // | |
| // /stored_file content: "foo" | |
| // dir/deflated_file content: 2x "The quick brown fox jumps over the lazy dog\n" | |
| const uint8_t kTestZip[] = { | |
| 0x50, 0x4b, 0x03, 0x04, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6a, 0x85, | |
| 0xf9, 0x54, 0xa8, 0x65, 0x32, 0x7e, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, | |
| 0x00, 0x00, 0x0b, 0x00, 0x1c, 0x00, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x64, | |
| 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x55, 0x54, 0x09, 0x00, 0x03, 0x17, 0xba, | |
| 0xde, 0x62, 0x44, 0xba, 0xde, 0x62, 0x75, 0x78, 0x0b, 0x00, 0x01, 0x04, | |
| 0xce, 0x69, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x66, 0x6f, 0x6f, | |
| 0x0a, 0x50, 0x4b, 0x03, 0x04, 0x14, 0x00, 0x00, 0x00, 0x08, 0x00, 0x47, | |
| 0x94, 0xf9, 0x54, 0xf2, 0x03, 0x92, 0x3c, 0x34, 0x00, 0x00, 0x00, 0x59, | |
| 0x00, 0x00, 0x00, 0x11, 0x00, 0x1c, 0x00, 0x64, 0x69, 0x72, 0x2f, 0x64, | |
| 0x65, 0x66, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x65, | |
| 0x55, 0x54, 0x09, 0x00, 0x03, 0x15, 0xd4, 0xde, 0x62, 0xf4, 0xba, 0xde, | |
| 0x62, 0x75, 0x78, 0x0b, 0x00, 0x01, 0x04, 0xce, 0x69, 0x02, 0x00, 0x04, | |
| 0x00, 0x00, 0x00, 0x00, 0x0b, 0xc9, 0x48, 0x55, 0x28, 0x2c, 0xcd, 0x4c, | |
| 0xce, 0x56, 0x48, 0x2a, 0xca, 0x2f, 0xcf, 0x53, 0x48, 0xcb, 0xaf, 0x50, | |
| 0xc8, 0x2a, 0xcd, 0x2d, 0x28, 0x56, 0xc8, 0x2f, 0x4b, 0x2d, 0x52, 0x28, | |
| 0x01, 0x4a, 0xe7, 0x24, 0x56, 0x55, 0x2a, 0xa4, 0xe4, 0xa7, 0x73, 0x85, | |
| 0x10, 0xa9, 0x36, 0xad, 0x08, 0xa8, 0x18, 0x00, 0x50, 0x4b, 0x01, 0x02, | |
| 0x1e, 0x03, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6a, 0x85, 0xf9, 0x54, | |
| 0xa8, 0x65, 0x32, 0x7e, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | |
| 0x0b, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, | |
| 0xa4, 0x81, 0x00, 0x00, 0x00, 0x00, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x64, | |
| 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x55, 0x54, 0x05, 0x00, 0x03, 0x17, 0xba, | |
| 0xde, 0x62, 0x75, 0x78, 0x0b, 0x00, 0x01, 0x04, 0xce, 0x69, 0x02, 0x00, | |
| 0x04, 0x00, 0x00, 0x00, 0x00, 0x50, 0x4b, 0x01, 0x02, 0x1e, 0x03, 0x14, | |
| 0x00, 0x00, 0x00, 0x08, 0x00, 0x47, 0x94, 0xf9, 0x54, 0xf2, 0x03, 0x92, | |
| 0x3c, 0x34, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x11, 0x00, 0x18, | |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa4, 0x81, 0x49, | |
| 0x00, 0x00, 0x00, 0x64, 0x69, 0x72, 0x2f, 0x64, 0x65, 0x66, 0x6c, 0x61, | |
| 0x74, 0x65, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x55, 0x54, 0x05, 0x00, | |
| 0x03, 0x15, 0xd4, 0xde, 0x62, 0x75, 0x78, 0x0b, 0x00, 0x01, 0x04, 0xce, | |
| 0x69, 0x02, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x50, 0x4b, 0x05, 0x06, | |
| 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0xa8, 0x00, 0x00, 0x00, | |
| 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00}; | |
| // Same logical contents as kTestZip, but written as a zip64 archive: the local | |
| // file headers use version 4.5 (45), set the 32-bit size fields to the | |
| // 0xFFFFFFFF sentinel and carry the real sizes in a Zip64 Extended Information | |
| // extra field (header id 0x0001). | |
| // stored_file content: "foo\n" | |
| // dir/deflated_file content: 2x "The quick brown fox jumps over the lazy dog\n" | |
| const uint8_t kTestZip64[] = { | |
| 0x50, 0x4b, 0x03, 0x04, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6a, 0x85, | |
| 0xf9, 0x54, 0xa8, 0x65, 0x32, 0x7e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | |
| 0xff, 0xff, 0x0b, 0x00, 0x14, 0x00, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x64, | |
| 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x01, 0x00, 0x10, 0x00, 0x04, 0x00, 0x00, | |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 0x00, 0x66, 0x6f, 0x6f, 0x0a, 0x50, 0x4b, 0x03, 0x04, 0x2d, 0x00, 0x00, | |
| 0x00, 0x08, 0x00, 0x47, 0x94, 0xf9, 0x54, 0xf2, 0x03, 0x92, 0x3c, 0xff, | |
| 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x11, 0x00, 0x14, 0x00, 0x64, | |
| 0x69, 0x72, 0x2f, 0x64, 0x65, 0x66, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x5f, | |
| 0x66, 0x69, 0x6c, 0x65, 0x01, 0x00, 0x10, 0x00, 0x59, 0x00, 0x00, 0x00, | |
| 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 0x0b, 0xc9, 0x48, 0x55, 0x28, 0x2c, 0xcd, 0x4c, 0xce, 0x56, 0x48, 0x2a, | |
| 0xca, 0x2f, 0xcf, 0x53, 0x48, 0xcb, 0xaf, 0x50, 0xc8, 0x2a, 0xcd, 0x2d, | |
| 0x28, 0x56, 0xc8, 0x2f, 0x4b, 0x2d, 0x52, 0x28, 0xc9, 0x48, 0x55, 0xc8, | |
| 0x49, 0xac, 0xaa, 0x54, 0x48, 0xc9, 0x4f, 0xe7, 0x0a, 0x21, 0x52, 0x6d, | |
| 0x5a, 0x51, 0x7e, 0x3a, 0x17, 0x00, 0x50, 0x4b, 0x01, 0x02, 0x2d, 0x03, | |
| 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6a, 0x85, 0xf9, 0x54, 0xa8, 0x65, | |
| 0x32, 0x7e, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x0b, 0x00, | |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, | |
| 0x00, 0x00, 0x00, 0x00, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x64, 0x5f, 0x66, | |
| 0x69, 0x6c, 0x65, 0x50, 0x4b, 0x01, 0x02, 0x2d, 0x03, 0x2d, 0x00, 0x00, | |
| 0x00, 0x08, 0x00, 0x47, 0x94, 0xf9, 0x54, 0xf2, 0x03, 0x92, 0x3c, 0x36, | |
| 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, | |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x41, 0x00, 0x00, | |
| 0x00, 0x64, 0x69, 0x72, 0x2f, 0x64, 0x65, 0x66, 0x6c, 0x61, 0x74, 0x65, | |
| 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x00, | |
| 0x00, 0x00, 0x02, 0x00, 0x02, 0x00, 0x78, 0x00, 0x00, 0x00, 0xba, 0x00, | |
| 0x00, 0x00, 0x00, 0x00, | |
| }; | |
| // A zip64 archive written to a non-seekable stream: the single deflated entry | |
| // uses general-purpose flag bit 3 (data descriptor), so the local header sizes | |
| // are placeholders and the real 8-byte compressed/uncompressed sizes live in a | |
| // trailing zip64 data descriptor. | |
| // dir/deflated_file content: 2x "The quick brown fox jumps over the lazy dog\n" | |
| const uint8_t kTestZip64DataDescriptor[] = { | |
| 0x50, 0x4b, 0x03, 0x04, 0x2d, 0x00, 0x08, 0x00, 0x08, 0x00, 0x47, 0x94, | |
| 0xf9, 0x54, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, | |
| 0xff, 0xff, 0x11, 0x00, 0x14, 0x00, 0x64, 0x69, 0x72, 0x2f, 0x64, 0x65, | |
| 0x66, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x01, | |
| 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0xc9, 0x48, 0x55, 0x28, | |
| 0x2c, 0xcd, 0x4c, 0xce, 0x56, 0x48, 0x2a, 0xca, 0x2f, 0xcf, 0x53, 0x48, | |
| 0xcb, 0xaf, 0x50, 0xc8, 0x2a, 0xcd, 0x2d, 0x28, 0x56, 0xc8, 0x2f, 0x4b, | |
| 0x2d, 0x52, 0x28, 0xc9, 0x48, 0x55, 0xc8, 0x49, 0xac, 0xaa, 0x54, 0x48, | |
| 0xc9, 0x4f, 0xe7, 0x0a, 0x21, 0x52, 0x6d, 0x5a, 0x51, 0x7e, 0x3a, 0x17, | |
| 0x00, 0x50, 0x4b, 0x07, 0x08, 0xf2, 0x03, 0x92, 0x3c, 0x36, 0x00, 0x00, | |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 0x00, 0x50, 0x4b, 0x01, 0x02, 0x2d, 0x03, 0x2d, 0x00, 0x08, 0x00, 0x08, | |
| 0x00, 0x47, 0x94, 0xf9, 0x54, 0xf2, 0x03, 0x92, 0x3c, 0x36, 0x00, 0x00, | |
| 0x00, 0x59, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |
| 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x64, | |
| 0x69, 0x72, 0x2f, 0x64, 0x65, 0x66, 0x6c, 0x61, 0x74, 0x65, 0x64, 0x5f, | |
| 0x66, 0x69, 0x6c, 0x65, 0x50, 0x4b, 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, | |
| 0x01, 0x00, 0x01, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, | |
| 0x00, 0x00, | |
| }; | |
| // A single local file header whose 32-bit sizes are the 0xFFFFFFFF sentinel, | |
| // but whose Zip64 extra field (id 0x0001) declares a length of 4 bytes: too | |
| // short to carry the 8-byte size it promises. A conforming reader must reject | |
| // this rather than leave the sentinel in place as a real size. | |
| const uint8_t kTestZip64TruncatedExtraField[] = { | |
| 0x50, 0x4b, 0x03, 0x04, // signature | |
| 0x2d, 0x00, // version needed 4.5 | |
| 0x00, 0x00, // flags | |
| 0x00, 0x00, // compression: store | |
| 0x6a, 0x85, 0xf9, 0x54, // mod time + date | |
| 0xa8, 0x65, 0x32, 0x7e, // crc32 | |
| 0xff, 0xff, 0xff, 0xff, // compressed size sentinel | |
| 0xff, 0xff, 0xff, 0xff, // uncompressed size sentinel | |
| 0x0b, 0x00, // fname_len = 11 | |
| 0x08, 0x00, // extra_field_len = 8 | |
| 0x73, 0x74, 0x6f, 0x72, 0x65, 0x64, 0x5f, 0x66, // "stored_f" | |
| 0x69, 0x6c, 0x65, // "ile" | |
| 0x01, 0x00, // extra id 0x0001 | |
| 0x04, 0x00, // extra size = 4 (< 8) | |
| 0x00, 0x00, 0x00, 0x00, // 4 bytes of payload | |
| }; | |
| std::string vec2str(const std::vector<uint8_t>& vec) { | |
| return {reinterpret_cast<const char*>(vec.data()), vec.size()}; | |
| } | |
| void ValidateTestZip(ZipReader& zr) { | |
| ASSERT_EQ(zr.files().size(), 2u); | |
| std::vector<uint8_t> dec; | |
| ASSERT_EQ(zr.files()[0].name(), "stored_file"); | |
| ASSERT_EQ(zr.files()[0].GetDatetimeStr(), "2022-07-25 16:43:20"); | |
| ASSERT_EQ(zr.files()[1].name(), "dir/deflated_file"); | |
| ASSERT_EQ(zr.files()[1].GetDatetimeStr(), "2022-07-25 18:34:14"); | |
| // This file is STORE-d and doesn't require any decompression. | |
| auto res = zr.files()[0].Decompress(&dec); | |
| ASSERT_TRUE(res.ok()) << res.message(); | |
| ASSERT_EQ(dec.size(), 4u); | |
| ASSERT_EQ(vec2str(dec), "foo\n"); | |
| // This file is DEFLATE-d and requires zlib. | |
| #if PERFETTO_BUILDFLAG(PERFETTO_ZLIB) | |
| res = zr.files()[1].Decompress(&dec); | |
| ASSERT_TRUE(res.ok()) << res.message(); | |
| ASSERT_EQ(dec.size(), 89u); | |
| ASSERT_EQ(vec2str(dec), | |
| "The quick brown fox jumps over the lazy dog\n" | |
| "The quick brown fox jumps over the lazy frog\n"); | |
| #endif | |
| } | |
| TEST(ZipReaderTest, ValidZip_OneShotParse) { | |
| ZipReader zr; | |
| ASSERT_OK( | |
| zr.Parse(TraceBlobView(TraceBlob::CopyFrom(kTestZip, sizeof(kTestZip))))); | |
| ValidateTestZip(zr); | |
| } | |
| TEST(ZipReaderTest, ValidZip64_OneShotParse) { | |
| ZipReader zr; | |
| ASSERT_OK(zr.Parse( | |
| TraceBlobView(TraceBlob::CopyFrom(kTestZip64, sizeof(kTestZip64))))); | |
| ValidateTestZip(zr); | |
| } | |
| TEST(ZipReaderTest, ValidZip64_OneByteChunks) { | |
| ZipReader zr; | |
| for (auto i : kTestZip64) { | |
| ASSERT_OK(zr.Parse(TraceBlobView(TraceBlob::CopyFrom(&i, 1)))); | |
| } | |
| ValidateTestZip(zr); | |
| } | |
| TEST(ZipReaderTest, ValidZip_OneByteChunks) { | |
| ZipReader zr; | |
| for (auto i : kTestZip) { | |
| ASSERT_OK(zr.Parse(TraceBlobView(TraceBlob::CopyFrom(&i, 1)))); | |
| } | |
| ValidateTestZip(zr); | |
| } | |
| TEST(ZipReaderTest, MalformedZip_InvalidSignature) { | |
| ZipReader zr; | |
| uint8_t content[sizeof(kTestZip)]; | |
| memcpy(content, kTestZip, sizeof(kTestZip)); | |
| content[0] = 0xff; // Invalid signature | |
| ASSERT_THAT( | |
| zr.Parse(TraceBlobView(TraceBlob::CopyFrom(content, sizeof(kTestZip)))), | |
| IsError()); | |
| ASSERT_EQ(zr.files().size(), 0u); | |
| } | |
| TEST(ZipReaderTest, MalformedZip_VersionTooHigh) { | |
| ZipReader zr; | |
| uint8_t content[sizeof(kTestZip)]; | |
| memcpy(content, kTestZip, sizeof(kTestZip)); | |
| content[5] = 9; // Version: 9.0 | |
| ASSERT_THAT( | |
| zr.Parse(TraceBlobView(TraceBlob::CopyFrom(content, sizeof(kTestZip)))), | |
| IsError()); | |
| ASSERT_EQ(zr.files().size(), 0u); | |
| } | |
| TEST(ZipReaderTest, TruncatedZip) { | |
| ZipReader zr; | |
| ASSERT_OK(zr.Parse(TraceBlobView(TraceBlob::CopyFrom(kTestZip, 40)))); | |
| ASSERT_EQ(zr.files().size(), 0u); | |
| } | |
| TEST(ZipReaderTest, MalformedZip64_TruncatedExtraField) { | |
| ZipReader zr; | |
| ASSERT_THAT(zr.Parse(TraceBlobView( | |
| TraceBlob::CopyFrom(kTestZip64TruncatedExtraField, | |
| sizeof(kTestZip64TruncatedExtraField)))), | |
| IsError()); | |
| } | |
| TEST(ZipReaderTest, Find) { | |
| ZipReader zr; | |
| ASSERT_OK( | |
| zr.Parse(TraceBlobView(TraceBlob::CopyFrom(kTestZip, sizeof(kTestZip))))); | |
| ASSERT_EQ(zr.Find("stored_file")->name(), "stored_file"); | |
| ASSERT_EQ(zr.Find("dir/deflated_file")->name(), "dir/deflated_file"); | |
| ASSERT_EQ(nullptr, zr.Find("stored_f")); | |
| ASSERT_EQ(nullptr, zr.Find("_file*")); | |
| ASSERT_EQ(nullptr, zr.Find("dirz/deflated_file")); | |
| } | |
| // All the tests below require zlib. | |
| #if PERFETTO_BUILDFLAG(PERFETTO_ZLIB) | |
| TEST(ZipReaderTest, ValidZip_DecompressLines) { | |
| ZipReader zr; | |
| ASSERT_OK( | |
| zr.Parse(TraceBlobView(TraceBlob::CopyFrom(kTestZip, sizeof(kTestZip))))); | |
| ValidateTestZip(zr); | |
| int num_callbacks = 0; | |
| zr.files()[1].DecompressLines( | |
| [&](const std::vector<base::StringView>& lines) { | |
| ASSERT_EQ(num_callbacks++, 0); | |
| ASSERT_TRUE(lines.size() == 2); | |
| ASSERT_EQ(lines[0].ToStdString(), | |
| "The quick brown fox jumps over the lazy dog"); | |
| ASSERT_EQ(lines[1].ToStdString(), | |
| "The quick brown fox jumps over the lazy frog"); | |
| }); | |
| ASSERT_EQ(num_callbacks, 1); | |
| } | |
| TEST(ZipReaderTest, ValidZip64DataDescriptor) { | |
| ZipReader zr; | |
| ASSERT_OK(zr.Parse(TraceBlobView(TraceBlob::CopyFrom( | |
| kTestZip64DataDescriptor, sizeof(kTestZip64DataDescriptor))))); | |
| ASSERT_EQ(zr.files().size(), 1u); | |
| ASSERT_EQ(zr.files()[0].name(), "dir/deflated_file"); | |
| std::vector<uint8_t> dec; | |
| auto res = zr.files()[0].Decompress(&dec); | |
| ASSERT_TRUE(res.ok()) << res.message(); | |
| ASSERT_EQ(dec.size(), 89u); | |
| ASSERT_EQ(vec2str(dec), | |
| "The quick brown fox jumps over the lazy dog\n" | |
| "The quick brown fox jumps over the lazy frog\n"); | |
| } | |
| TEST(ZipReaderTest, ValidZip64DataDescriptor_OneByteChunks) { | |
| ZipReader zr; | |
| for (auto i : kTestZip64DataDescriptor) { | |
| ASSERT_OK(zr.Parse(TraceBlobView(TraceBlob::CopyFrom(&i, 1)))); | |
| } | |
| ASSERT_EQ(zr.files().size(), 1u); | |
| std::vector<uint8_t> dec; | |
| ASSERT_OK(zr.files()[0].Decompress(&dec)); | |
| ASSERT_EQ(dec.size(), 89u); | |
| } | |
| TEST(ZipReaderTest, MalformedZip_DecomprError) { | |
| ZipReader zr; | |
| uint8_t content[sizeof(kTestZip)]; | |
| memcpy(content, kTestZip, sizeof(kTestZip)); | |
| // The 2nd file header starts at 103, the payload at 30 (header) + 17 (fname) | |
| // bytes later. We start clobbering at offset=150, so the header is intanct | |
| // but decompression fails. | |
| memset(&content[150], 0, 40); | |
| ASSERT_OK( | |
| zr.Parse(TraceBlobView(TraceBlob::CopyFrom(content, sizeof(kTestZip))))); | |
| ASSERT_EQ(zr.files().size(), 2u); | |
| std::vector<uint8_t> ignored; | |
| ASSERT_OK(zr.files()[0].Decompress(&ignored)); | |
| ASSERT_THAT(zr.files()[1].Decompress(&ignored), IsError()); | |
| } | |
| #endif // PERFETTO_BUILDFLAG(PERFETTO_ZLIB) | |
| } // namespace | |
| } // namespace perfetto::trace_processor::util |