/src/astc-encoder/Source/Fuzzers/fuzz_astc_decompress.cpp
Line | Count | Source |
1 | | // SPDX-License-Identifier: Apache-2.0 |
2 | | // ---------------------------------------------------------------------------- |
3 | | // Copyright 2026 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 | | #include "astcenc.h" |
19 | | #include <fuzzer/FuzzedDataProvider.h> |
20 | | #include <vector> |
21 | | #include <iostream> |
22 | | |
23 | | extern "C" int LLVMFuzzerTestOneInput( |
24 | | const uint8_t *data, |
25 | | size_t size |
26 | 3.63k | ) { |
27 | 3.63k | FuzzedDataProvider fdp(data, size); |
28 | | |
29 | | // Randomize block size |
30 | | // Legal 2D block sizes: 4x4, 5x4, 5x5, 6x5, 6x6, 8x5, 8x6, 8x8, 10x5, 10x6, 10x8, 10x10, 12x10, 12x12 |
31 | 3.63k | static const struct { uint8_t x, y; } block_sizes[] = { |
32 | 3.63k | {4, 4}, {5, 4}, {5, 5}, {6, 5}, {6, 6}, {8, 5}, {8, 6}, {8, 8}, |
33 | 3.63k | {10, 5}, {10, 6}, {10, 8}, {10, 10}, {12, 10}, {12, 12} |
34 | 3.63k | }; |
35 | | |
36 | 3.63k | int bs_idx = fdp.ConsumeIntegralInRange<int>(0, (sizeof(block_sizes) / sizeof(block_sizes[0])) - 1); |
37 | 3.63k | uint32_t block_x = block_sizes[bs_idx].x; |
38 | 3.63k | uint32_t block_y = block_sizes[bs_idx].y; |
39 | 3.63k | uint32_t block_z = 1; |
40 | | |
41 | | // Randomize profile |
42 | 3.63k | astcenc_profile profile = (astcenc_profile)fdp.ConsumeIntegralInRange<int>(0, 3); |
43 | | |
44 | | // Randomize quality |
45 | 3.63k | float quality = fdp.ConsumeFloatingPointInRange<float>(ASTCENC_PRE_FASTEST, ASTCENC_PRE_EXHAUSTIVE); |
46 | | |
47 | | // Randomize flags, but constrain to be safe with arbitrary input data |
48 | 3.63k | unsigned int flags = fdp.ConsumeIntegralInRange<unsigned int>(0, ASTCENC_ALL_FLAGS); |
49 | 3.63k | flags &= ~ASTCENC_FLG_SELF_DECOMPRESS_ONLY; |
50 | | |
51 | 3.63k | astcenc_config config; |
52 | 3.63k | astcenc_error status = astcenc_config_init(profile, block_x, block_y, block_z, quality, flags, &config); |
53 | 3.63k | if (status != ASTCENC_SUCCESS) |
54 | 49 | { |
55 | 49 | return 0; |
56 | 49 | } |
57 | | |
58 | 3.58k | astcenc_context* context = nullptr; |
59 | 3.58k | status = astcenc_context_alloc(&config, 1, &context, nullptr); |
60 | 3.58k | if (status != ASTCENC_SUCCESS) |
61 | 0 | { |
62 | 0 | return 0; |
63 | 0 | } |
64 | | |
65 | | // Prepare for decompression |
66 | | // We need some "compressed" data. ASTC blocks are 16 bytes. |
67 | | // Let's decide how many blocks to decompress. |
68 | 3.58k | size_t num_blocks_x = fdp.ConsumeIntegralInRange<size_t>(1, 4); |
69 | 3.58k | size_t num_blocks_y = fdp.ConsumeIntegralInRange<size_t>(1, 4); |
70 | 3.58k | size_t compressed_data_len = num_blocks_x * num_blocks_y * 16; |
71 | | |
72 | 3.58k | if (fdp.remaining_bytes() < compressed_data_len) |
73 | 256 | { |
74 | 256 | astcenc_context_free(context); |
75 | 256 | return 0; |
76 | 256 | } |
77 | | |
78 | 3.32k | std::vector<uint8_t> compressed_data = fdp.ConsumeBytes<uint8_t>(compressed_data_len); |
79 | | |
80 | | // Image dimensions |
81 | 3.32k | uint32_t dim_x = num_blocks_x * block_x; |
82 | 3.32k | uint32_t dim_y = num_blocks_y * block_y; |
83 | 3.32k | uint32_t dim_z = 1; |
84 | | |
85 | | // Allocate output image |
86 | 3.32k | astcenc_image image_out; |
87 | 3.32k | image_out.dim_x = dim_x; |
88 | 3.32k | image_out.dim_y = dim_y; |
89 | 3.32k | image_out.dim_z = dim_z; |
90 | 3.32k | image_out.data_type = ASTCENC_TYPE_U8; |
91 | | |
92 | 3.32k | uint8_t* slice_data = new uint8_t[dim_x * dim_y * 4]; |
93 | 3.32k | void* slices[] = { slice_data }; |
94 | 3.32k | image_out.data = slices; |
95 | | |
96 | 3.32k | astcenc_swizzle swizzle = { |
97 | 3.32k | ASTCENC_SWZ_R, ASTCENC_SWZ_G, ASTCENC_SWZ_B, ASTCENC_SWZ_A |
98 | 3.32k | }; |
99 | | |
100 | 3.32k | status = astcenc_decompress_image(context, compressed_data.data(), compressed_data.size(), &image_out, &swizzle, 0); |
101 | | |
102 | 3.32k | delete[] slice_data; |
103 | 3.32k | astcenc_context_free(context); |
104 | | |
105 | 3.32k | return 0; |
106 | 3.58k | } |