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