/src/libjxl/tools/icc_codec_fuzzer.cc
Line | Count | Source |
1 | | // Copyright (c) the JPEG XL Project Authors. All rights reserved. |
2 | | // |
3 | | // Use of this source code is governed by a BSD-style |
4 | | // license that can be found in the LICENSE file. |
5 | | |
6 | | #include <cstddef> |
7 | | #include <cstdint> |
8 | | #include <cstdio> |
9 | | #include <cstring> |
10 | | #include <vector> |
11 | | |
12 | | #include "lib/jxl/base/compiler_specific.h" |
13 | | #include "lib/jxl/enc_icc_codec.h" |
14 | | #include "tools/tracking_memory_manager.h" |
15 | | |
16 | | #ifdef JXL_ICC_FUZZER_SLOW_TEST |
17 | | #include "lib/jxl/base/span.h" |
18 | | #include "lib/jxl/dec_bit_reader.h" |
19 | | #endif |
20 | | |
21 | | #include "lib/jxl/base/status.h" |
22 | | #include "lib/jxl/fuzztest.h" |
23 | | #include "lib/jxl/padded_bytes.h" |
24 | | |
25 | | namespace jxl { |
26 | | Status PredictICC(const uint8_t* icc, size_t size, PaddedBytes* result); |
27 | | Status UnpredictICC(const uint8_t* enc, size_t size, PaddedBytes* result); |
28 | | } // namespace jxl |
29 | | |
30 | | namespace { |
31 | | |
32 | | using ::jpegxl::tools::kGiB; |
33 | | using ::jpegxl::tools::TrackingMemoryManager; |
34 | | using ::jxl::PaddedBytes; |
35 | | |
36 | | #ifdef JXL_ICC_FUZZER_SLOW_TEST |
37 | | using ::jxl::BitReader; |
38 | | using ::jxl::Span; |
39 | | #endif |
40 | | |
41 | 18.4k | void CheckImpl(bool ok, const char* condition, const char* file, int line) { |
42 | 18.4k | if (!ok) { |
43 | 0 | fprintf(stderr, "Check(%s) failed at %s:%d\n", condition, file, line); |
44 | 0 | JXL_CRASH(); |
45 | 0 | } |
46 | 18.4k | } |
47 | 18.4k | #define Check(OK) CheckImpl((OK), #OK, __FILE__, __LINE__) |
48 | | |
49 | 4.81k | int DoTestOneInput(const uint8_t* data, size_t size) { |
50 | | #if defined(JXL_ICC_FUZZER_ONLY_WRITE) |
51 | | bool read = false; |
52 | | #elif defined(JXL_ICC_FUZZER_ONLY_READ) |
53 | | bool read = true; |
54 | | #else |
55 | | // Decide whether to test the reader or the writer (both use parsing) |
56 | 4.81k | if (!size) return 0; |
57 | 4.81k | bool read = data[0] == 0; |
58 | 4.81k | data++; |
59 | 4.81k | size--; |
60 | 4.81k | #endif |
61 | 4.81k | TrackingMemoryManager memory_manager{/* cap */ 1 * kGiB, |
62 | 4.81k | /* total_cap */ 5 * kGiB}; |
63 | | |
64 | | #ifdef JXL_ICC_FUZZER_SLOW_TEST |
65 | | // Including JPEG XL LZ77 and ANS compression. These are already fuzzed |
66 | | // separately, so it is better to disable JXL_ICC_FUZZER_SLOW_TEST to focus on |
67 | | // the ICC parsing. |
68 | | if (read) { |
69 | | // Reading parses the compressed format. |
70 | | BitReader br(Bytes(data, size)); |
71 | | std::vector<uint8_t> result; |
72 | | (void)jxl::test::ReadICC(&br, &result); |
73 | | (void)br.Close(); |
74 | | } else { |
75 | | // Writing parses the original ICC profile. |
76 | | PaddedBytes icc{memory_manager.get()}; |
77 | | icc.assign(data, data + size); |
78 | | BitWriter writer{memory_manager.get()}; |
79 | | // Writing should support any random bytestream so must succeed, make |
80 | | // fuzzer fail if not. |
81 | | Check(jxl::WriteICC(icc, &writer, jxl::LayerType::Header, nullptr)); |
82 | | } |
83 | | #else // JXL_ICC_FUZZER_SLOW_TEST |
84 | 4.81k | if (read) { |
85 | | // Reading (unpredicting) parses the compressed format. |
86 | 1.41k | PaddedBytes result{memory_manager.get()}; |
87 | 1.41k | (void)jxl::UnpredictICC(data, size, &result); |
88 | 3.40k | } else { |
89 | | // Writing (predicting) parses the original ICC profile. |
90 | 3.40k | PaddedBytes result{memory_manager.get()}; |
91 | | // Writing should support any random bytestream so must succeed, make |
92 | | // fuzzer fail if not. |
93 | 3.40k | Check(jxl::PredictICC(data, size, &result)); |
94 | 3.40k | PaddedBytes reconstructed{memory_manager.get()}; |
95 | 3.40k | Check(jxl::UnpredictICC(result.data(), result.size(), &reconstructed)); |
96 | 3.40k | Check(reconstructed.size() == size); |
97 | 3.40k | Check(memcmp(data, reconstructed.data(), size) == 0); |
98 | 3.40k | } |
99 | 4.81k | #endif // JXL_ICC_FUZZER_SLOW_TEST |
100 | | |
101 | 4.81k | Check(memory_manager.Reset()); |
102 | 4.81k | return 0; |
103 | 4.81k | } |
104 | | |
105 | | } // namespace |
106 | | |
107 | 53.8k | extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { |
108 | 53.8k | return DoTestOneInput(data, size); |
109 | 53.8k | } |
110 | | |
111 | 0 | void TestOneInput(const std::vector<uint8_t>& data) { |
112 | 0 | DoTestOneInput(data.data(), data.size()); |
113 | 0 | } |
114 | | |
115 | | FUZZ_TEST(IccCodecFuzzTest, TestOneInput); |