/src/libjxl/tools/rans_fuzzer.cc
Line | Count | Source (jump to first uncovered line) |
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 <jxl/memory_manager.h> |
7 | | |
8 | | #include <cstddef> |
9 | | #include <cstdint> |
10 | | #include <vector> |
11 | | |
12 | | #include "lib/jxl/base/common.h" |
13 | | #include "lib/jxl/base/compiler_specific.h" |
14 | | #include "lib/jxl/base/span.h" |
15 | | #include "lib/jxl/base/status.h" |
16 | | #include "lib/jxl/dec_ans.h" |
17 | | #include "lib/jxl/dec_bit_reader.h" |
18 | | #include "lib/jxl/fuzztest.h" |
19 | | #include "tools/tracking_memory_manager.h" |
20 | | |
21 | | namespace { |
22 | | |
23 | | using ::jpegxl::tools::kGiB; |
24 | | using ::jpegxl::tools::TrackingMemoryManager; |
25 | | using ::jxl::ANSCode; |
26 | | using ::jxl::ANSSymbolReader; |
27 | | using ::jxl::BitReader; |
28 | | using ::jxl::BitReaderScopedCloser; |
29 | | using ::jxl::Bytes; |
30 | | using ::jxl::Status; |
31 | | |
32 | 2.09k | void Check(bool ok) { |
33 | 2.09k | if (!ok) { |
34 | 0 | JXL_CRASH(); |
35 | 0 | } |
36 | 2.09k | } |
37 | | |
38 | | Status Run(const uint8_t* data, size_t size, JxlMemoryManager* memory_manager, |
39 | 2.09k | size_t num_contexts) { |
40 | 2.09k | std::vector<uint8_t> context_map; |
41 | 2.09k | Status ret = true; |
42 | 2.09k | { |
43 | 2.09k | BitReader br(Bytes(data, size)); |
44 | 2.09k | BitReaderScopedCloser br_closer(br, ret); |
45 | 2.09k | ANSCode code; |
46 | 2.09k | JXL_RETURN_IF_ERROR(DecodeHistograms(memory_manager, &br, num_contexts, |
47 | 2.09k | &code, &context_map)); |
48 | 1.42k | JXL_ASSIGN_OR_RETURN(ANSSymbolReader ansreader, |
49 | 1.42k | ANSSymbolReader::Create(&code, &br)); |
50 | | |
51 | | // Limit the maximum amount of reads to avoid (valid) infinite loops. |
52 | 1.42k | const size_t maxreads = size * 8; |
53 | 1.42k | size_t numreads = 0; |
54 | 1.42k | int context = 0; |
55 | 67.9M | while (jxl::DivCeil(br.TotalBitsConsumed(), jxl::kBitsPerByte) < size && |
56 | 67.9M | numreads <= maxreads) { |
57 | 67.9M | int code = ansreader.ReadHybridUint(context, &br, context_map); |
58 | 67.9M | context = code % num_contexts; |
59 | 67.9M | numreads++; |
60 | 67.9M | } |
61 | 1.42k | } |
62 | 0 | return true; |
63 | 1.42k | } |
64 | | |
65 | 2.09k | int DoTestOneInput(const uint8_t* data, size_t size) { |
66 | 2.09k | if (size < 2) return 0; |
67 | 2.09k | size_t numContexts = data[0] * 256 * data[1] + 1; |
68 | 2.09k | data += 2; |
69 | 2.09k | size -= 2; |
70 | | |
71 | 2.09k | TrackingMemoryManager memory_manager{/* cap */ 1 * kGiB, |
72 | 2.09k | /* total_cap */ 5 * kGiB}; |
73 | | // It is OK to fail. |
74 | 2.09k | (void)Run(data, size, memory_manager.get(), numContexts); |
75 | 2.09k | Check(memory_manager.Reset()); |
76 | | |
77 | 2.09k | return 0; |
78 | 2.09k | } |
79 | | |
80 | | } // namespace |
81 | | |
82 | 2.09k | extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { |
83 | 2.09k | return DoTestOneInput(data, size); |
84 | 2.09k | } |
85 | | |
86 | 0 | void TestOneInput(const std::vector<uint8_t>& data) { |
87 | 0 | DoTestOneInput(data.data(), data.size()); |
88 | 0 | } |
89 | | |
90 | | FUZZ_TEST(RansFuzzTest, TestOneInput); |