|
| 1 | +// SPDX-License-Identifier: Apache-2.0 |
| 2 | +// ---------------------------------------------------------------------------- |
| 3 | +// Copyright 2020 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 | + int x; |
| 36 | + int y; |
| 37 | + int z; |
| 38 | +}; |
| 39 | + |
| 40 | +std::array<BlockSizes, 3> testSz {{ |
| 41 | + { 4, 4, 1}, // Highest bitrate |
| 42 | + {12, 12, 1}, // Largest 2D block |
| 43 | + {6, 6, 6} // Largest 3D block |
| 44 | +}}; |
| 45 | + |
| 46 | +std::array<block_size_descriptor, 3> testBSD; |
| 47 | + |
| 48 | +/** |
| 49 | + * @brief Utility function to create all of the block size descriptors needed. |
| 50 | + * |
| 51 | + * This is triggered once via a static initializer. |
| 52 | + * |
| 53 | + * Triggering once is important so that we only create a single BSD per block |
| 54 | + * size we need, rather than one per fuzzer iteration (it's expensive). This |
| 55 | + * improves fuzzer throughput by ~ 1000x! |
| 56 | + * |
| 57 | + * Triggering via a static initializer, rather than a lazy init in the fuzzer |
| 58 | + * function, is important because is means that the BSD is allocated before |
| 59 | + * fuzzing starts. This means that leaksanitizer will ignore the fact that we |
| 60 | + * "leak" the dynamic allocations inside the BSD (we never call term()). |
| 61 | + */ |
| 62 | +bool bsd_initializer() |
| 63 | +{ |
| 64 | + for (int i = 0; i < testSz.size(); i++) |
| 65 | + { |
| 66 | + init_block_size_descriptor( |
| 67 | + testSz[i].x, |
| 68 | + testSz[i].y, |
| 69 | + testSz[i].z, |
| 70 | + &(testBSD[i])); |
| 71 | + } |
| 72 | + |
| 73 | + return true; |
| 74 | +} |
| 75 | + |
| 76 | +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) |
| 77 | +{ |
| 78 | + // Preinitialize the block size descriptors we need |
| 79 | + static bool init = bsd_initializer(); |
| 80 | + |
| 81 | + // Must have 4 (select block size) and 16 (payload) bytes |
| 82 | + if (size < 4 + 16) |
| 83 | + { |
| 84 | + return 0; |
| 85 | + } |
| 86 | + |
| 87 | + FuzzedDataProvider stream(data, size); |
| 88 | + |
| 89 | + // Select a block size to test |
| 90 | + int i = stream.ConsumeIntegralInRange<int>(0, testSz.size() - 1); |
| 91 | + block_size_descriptor* bsd = &(testBSD[i]); |
| 92 | + |
| 93 | + // Populate the physical block |
| 94 | + physical_compressed_block pcb; |
| 95 | + std::vector<uint8_t> buffer = stream.ConsumeBytes<uint8_t>(16); |
| 96 | + std::memcpy(&pcb, buffer.data(), 16); |
| 97 | + |
| 98 | + // Call the function under test |
| 99 | + symbolic_compressed_block scb; |
| 100 | + physical_to_symbolic(bsd, pcb, &scb); |
| 101 | + |
| 102 | + return 0; |
| 103 | +} |
0 commit comments