1 // SPDX-License-Identifier: Apache-2.0
2 // ----------------------------------------------------------------------------
3 // Copyright 2020-2021 Arm Limited
4 //
5 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
6 // use this file except in compliance with the License. You may obtain a copy
7 // of the License at:
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 // License for the specific language governing permissions and limitations
15 // under the License.
16 // ----------------------------------------------------------------------------
17
18 /**
19 * @brief Fuzz target for physical_to_symbolic().
20 *
21 * This function is the first entrypoint for decompressing a 16 byte block of
22 * input ASTC data from disk. The 16 bytes can contain arbitrary data; they
23 * are read from an external source, but the block size used must be a valid
24 * ASTC block footprint.
25 */
26
27
28 #include "astcenc_internal.h"
29
30 #include <fuzzer/FuzzedDataProvider.h>
31 #include <array>
32 #include <vector>
33
34 struct BlockSizes
35 {
36 int x;
37 int y;
38 int z;
39 };
40
41 std::array<BlockSizes, 3> testSz {{
42 { 4, 4, 1}, // Highest bitrate
43 {12, 12, 1}, // Largest 2D block
44 {6, 6, 6} // Largest 3D block
45 }};
46
47 std::array<block_size_descriptor, 3> testBSD;
48
49 /**
50 * @brief Utility function to create all of the block size descriptors needed.
51 *
52 * This is triggered once via a static initializer.
53 *
54 * Triggering once is important so that we only create a single BSD per block
55 * size we need, rather than one per fuzzer iteration (it's expensive). This
56 * improves fuzzer throughput by ~ 1000x!
57 *
58 * Triggering via a static initializer, rather than a lazy init in the fuzzer
59 * function, is important because is means that the BSD is allocated before
60 * fuzzing starts. This means that leaksanitizer will ignore the fact that we
61 * "leak" the dynamic allocations inside the BSD (we never call term()).
62 */
bsd_initializer()63 bool bsd_initializer()
64 {
65 for (int i = 0; i < testSz.size(); i++)
66 {
67 init_block_size_descriptor(
68 testSz[i].x,
69 testSz[i].y,
70 testSz[i].z,
71 false,
72 4,
73 1.0f,
74 testBSD[i]);
75 }
76
77 return true;
78 }
79
LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)80 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
81 {
82 // Preinitialize the block size descriptors we need
83 static bool init = bsd_initializer();
84
85 // Must have 4 (select block size) and 16 (payload) bytes
86 if (size < 4 + 16)
87 {
88 return 0;
89 }
90
91 FuzzedDataProvider stream(data, size);
92
93 // Select a block size to test
94 int i = stream.ConsumeIntegralInRange<int>(0, testSz.size() - 1);
95
96 // Populate the physical block
97 uint8_t pcb[16];
98 std::vector<uint8_t> buffer = stream.ConsumeBytes<uint8_t>(16);
99 std::memcpy(pcb, buffer.data(), 16);
100
101 // Call the function under test
102 symbolic_compressed_block scb;
103 physical_to_symbolic(testBSD[i], pcb, scb);
104
105 return 0;
106 }
107