Coverage Report

Created: 2025-10-13 06:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/meshoptimizer/tools/codecfuzz.cpp
Line
Count
Source
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
12.2k
{
9
12.2k
  size_t count = 66; // must be divisible by 3 for decodeIndexBuffer; should be >=64 to cover large vertex blocks
10
11
12.2k
  void* destination = malloc(count * stride);
12
12.2k
  assert(destination);
13
14
12.2k
  int rc = decode(destination, count, stride, reinterpret_cast<const unsigned char*>(data), size);
15
12.2k
  (void)rc;
16
17
12.2k
  free(destination);
18
12.2k
}
19
20
void fuzzRoundtrip(const uint8_t* data, size_t size, size_t stride, int level)
21
6.10k
{
22
6.10k
  size_t count = size / stride;
23
24
6.10k
  size_t bound = meshopt_encodeVertexBufferBound(count, stride);
25
6.10k
  void* encoded = malloc(bound);
26
6.10k
  void* decoded = malloc(count * stride);
27
6.10k
  assert(encoded && decoded);
28
29
6.10k
  size_t res = meshopt_encodeVertexBufferLevel(static_cast<unsigned char*>(encoded), bound, data, count, stride, level, -1);
30
6.10k
  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
6.10k
  size_t rese = meshopt_encodeVertexBufferLevel(static_cast<unsigned char*>(encoded) + bound - res, res, data, count, stride, level, -1);
35
6.10k
  assert(rese == res);
36
37
6.10k
  int rc = meshopt_decodeVertexBuffer(decoded, count, stride, static_cast<unsigned char*>(encoded) + bound - res, res);
38
6.10k
  assert(rc == 0);
39
40
6.10k
  assert(memcmp(data, decoded, count * stride) == 0);
41
42
6.10k
  free(decoded);
43
6.10k
  free(encoded);
44
6.10k
}
45
46
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
47
1.52k
{
48
  // decodeIndexBuffer supports 2 and 4-byte indices
49
1.52k
  fuzzDecoder(data, size, 2, meshopt_decodeIndexBuffer);
50
1.52k
  fuzzDecoder(data, size, 4, meshopt_decodeIndexBuffer);
51
52
  // decodeIndexSequence supports 2 and 4-byte indices
53
1.52k
  fuzzDecoder(data, size, 2, meshopt_decodeIndexSequence);
54
1.52k
  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.52k
  fuzzDecoder(data, size, 4, meshopt_decodeVertexBuffer);
59
1.52k
  fuzzDecoder(data, size, 16, meshopt_decodeVertexBuffer);
60
1.52k
  fuzzDecoder(data, size, 24, meshopt_decodeVertexBuffer);
61
1.52k
  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.52k
  uint8_t data0 = size > 0 ? data[0] : 0;
67
1.52k
  int level = data0 % 5;
68
69
1.52k
  meshopt_encodeVertexVersion(level < 4 ? 1 : 0);
70
71
1.52k
  fuzzRoundtrip(data, size, 4, level);
72
1.52k
  fuzzRoundtrip(data, size, 16, level);
73
1.52k
  fuzzRoundtrip(data, size, 24, level);
74
1.52k
  fuzzRoundtrip(data, size, 32, level);
75
76
1.52k
  return 0;
77
1.52k
}