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