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