/src/meshoptimizer/tools/codecfuzz.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | #include "../src/meshoptimizer.h" |
2 | | |
3 | | #include <stdint.h> |
4 | | #include <stdlib.h> |
5 | | #include <string.h> |
6 | | |
7 | | void fuzzDecoder(const uint8_t* data, size_t size, size_t stride, int (*decode)(void*, size_t, size_t, const unsigned char*, size_t)) |
8 | 10.5k | { |
9 | 10.5k | size_t count = 66; // must be divisible by 3 for decodeIndexBuffer; should be >=64 to cover large vertex blocks |
10 | | |
11 | 10.5k | void* destination = malloc(count * stride); |
12 | 10.5k | assert(destination); |
13 | | |
14 | 10.5k | int rc = decode(destination, count, stride, reinterpret_cast<const unsigned char*>(data), size); |
15 | 10.5k | (void)rc; |
16 | | |
17 | 10.5k | free(destination); |
18 | 10.5k | } |
19 | | |
20 | | void fuzzRoundtrip(const uint8_t* data, size_t size, size_t stride, int level) |
21 | 5.27k | { |
22 | 5.27k | size_t count = size / stride; |
23 | | |
24 | 5.27k | size_t bound = meshopt_encodeVertexBufferBound(count, stride); |
25 | 5.27k | void* encoded = malloc(bound); |
26 | 5.27k | void* decoded = malloc(count * stride); |
27 | 5.27k | assert(encoded && decoded); |
28 | | |
29 | 5.27k | size_t res = meshopt_encodeVertexBufferLevel(static_cast<unsigned char*>(encoded), bound, data, count, stride, level, -1); |
30 | 5.27k | assert(res > 0 && res <= bound); |
31 | | |
32 | | // encode again at the boundary to check for memory safety |
33 | | // this should produce the same output because encoder is deterministic |
34 | 5.27k | size_t rese = meshopt_encodeVertexBufferLevel(static_cast<unsigned char*>(encoded) + bound - res, res, data, count, stride, level, -1); |
35 | 5.27k | assert(rese == res); |
36 | | |
37 | 5.27k | int rc = meshopt_decodeVertexBuffer(decoded, count, stride, static_cast<unsigned char*>(encoded) + bound - res, res); |
38 | 5.27k | assert(rc == 0); |
39 | | |
40 | 5.27k | assert(memcmp(data, decoded, count * stride) == 0); |
41 | | |
42 | 5.27k | free(decoded); |
43 | 5.27k | free(encoded); |
44 | 5.27k | } |
45 | | |
46 | | extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) |
47 | 1.31k | { |
48 | | // decodeIndexBuffer supports 2 and 4-byte indices |
49 | 1.31k | fuzzDecoder(data, size, 2, meshopt_decodeIndexBuffer); |
50 | 1.31k | fuzzDecoder(data, size, 4, meshopt_decodeIndexBuffer); |
51 | | |
52 | | // decodeIndexSequence supports 2 and 4-byte indices |
53 | 1.31k | fuzzDecoder(data, size, 2, meshopt_decodeIndexSequence); |
54 | 1.31k | fuzzDecoder(data, size, 4, meshopt_decodeIndexSequence); |
55 | | |
56 | | // decodeVertexBuffer supports any strides divisible by 4 in 4-256 interval |
57 | | // it's a waste of time to check all of them, so we'll just check a few with different alignment mod 16 |
58 | 1.31k | fuzzDecoder(data, size, 4, meshopt_decodeVertexBuffer); |
59 | 1.31k | fuzzDecoder(data, size, 16, meshopt_decodeVertexBuffer); |
60 | 1.31k | fuzzDecoder(data, size, 24, meshopt_decodeVertexBuffer); |
61 | 1.31k | fuzzDecoder(data, size, 32, meshopt_decodeVertexBuffer); |
62 | | |
63 | | // encodeVertexBuffer/decodeVertexBuffer should roundtrip for any stride, check a few with different alignment mod 16 |
64 | | // this also checks memory safety properties of the encoder |
65 | | // to conserve time, we only check one version/level combination, biased towards version 1 |
66 | 1.31k | uint8_t data0 = size > 0 ? data[0] : 0; |
67 | 1.31k | int level = data0 % 5; |
68 | | |
69 | 1.31k | meshopt_encodeVertexVersion(level < 4 ? 1 : 0); |
70 | | |
71 | 1.31k | fuzzRoundtrip(data, size, 4, level); |
72 | 1.31k | fuzzRoundtrip(data, size, 16, level); |
73 | 1.31k | fuzzRoundtrip(data, size, 24, level); |
74 | 1.31k | fuzzRoundtrip(data, size, 32, level); |
75 | | |
76 | 1.31k | return 0; |
77 | 1.31k | } |