Skip to content

Commit f843aae

Browse files
authored
Merge pull request #1067 from zeux/gltf-fuzz
gltfpack: Improve fuzzing infrastructure
2 parents e759e60 + 65fe12f commit f843aae

3 files changed

Lines changed: 138 additions & 3 deletions

File tree

gltf/fuzz.dict

Lines changed: 80 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,12 @@
6969
"\"MAT3\""
7070
"\"MAT4\""
7171
"\"OPAQUE\""
72+
"\"POSITION\""
73+
"\"NORMAL\""
74+
"\"TANGENT\""
75+
"\"TEXCOORD\""
76+
"\"JOINTS\""
77+
"\"WEIGHTS\""
7278
"\"SCALAR\""
7379
"\"STEP\""
7480
"\"VEC2\""
@@ -181,6 +187,7 @@
181187
# AFL dictionary for GLTF extensions
182188
# -----------------------
183189
"\"KHR_materials_unlit\""
190+
"\"KHR_draco_mesh_compression\""
184191
"\"KHR_texture_basisu\""
185192

186193
"\"KHR_materials_pbrSpecularGlossiness\""
@@ -198,7 +205,12 @@
198205

199206
"\"KHR_lights_punctual\""
200207
"\"color\""
208+
"\"directional\""
201209
"\"intensity\""
210+
"\"light\""
211+
"\"lights\""
212+
"\"point\""
213+
"\"spot\""
202214
"\"type\""
203215
"\"range\""
204216
"\"innerConeAngle\""
@@ -221,4 +233,71 @@
221233
"\"sheenRoughnessTexture\""
222234

223235
"\"KHR_materials_emissive_strength\""
224-
"\"emissiveStrength"\""
236+
"\"emissiveStrength\""
237+
238+
"\"KHR_materials_clearcoat\""
239+
"\"clearcoatFactor\""
240+
"\"clearcoatTexture\""
241+
"\"clearcoatRoughnessFactor\""
242+
"\"clearcoatRoughnessTexture\""
243+
"\"clearcoatNormalTexture\""
244+
245+
"\"KHR_materials_ior\""
246+
"\"ior\""
247+
248+
"\"KHR_materials_specular\""
249+
"\"specularFactor\""
250+
"\"specularTexture\""
251+
"\"specularColorFactor\""
252+
"\"specularColorTexture\""
253+
254+
"\"KHR_materials_iridescence\""
255+
"\"iridescenceFactor\""
256+
"\"iridescenceTexture\""
257+
"\"iridescenceIor\""
258+
"\"iridescenceThicknessMinimum\""
259+
"\"iridescenceThicknessMaximum\""
260+
"\"iridescenceThicknessTexture\""
261+
262+
"\"KHR_materials_anisotropy\""
263+
"\"anisotropyStrength\""
264+
"\"anisotropyRotation\""
265+
"\"anisotropyTexture\""
266+
267+
"\"KHR_materials_dispersion\""
268+
"\"dispersion\""
269+
270+
"\"KHR_materials_diffuse_transmission\""
271+
"\"diffuseTransmissionFactor\""
272+
"\"diffuseTransmissionTexture\""
273+
"\"diffuseTransmissionColorFactor\""
274+
"\"diffuseTransmissionColorTexture\""
275+
276+
"\"KHR_materials_variants\""
277+
"\"mappings\""
278+
"\"targetNames\""
279+
"\"variants\""
280+
281+
"\"EXT_texture_webp\""
282+
283+
"\"EXT_mesh_gpu_instancing\""
284+
"\"TRANSLATION\""
285+
"\"ROTATION\""
286+
"\"SCALE\""
287+
"\"_COLOR_0\""
288+
289+
"\"EXT_meshopt_compression\""
290+
"\"KHR_meshopt_compression\""
291+
"\"mode\""
292+
"\"filter\""
293+
"\"fallback\""
294+
"\"ATTRIBUTES\""
295+
"\"TRIANGLES\""
296+
"\"INDICES\""
297+
"\"NONE\""
298+
"\"OCTAHEDRAL\""
299+
"\"QUATERNION\""
300+
"\"EXPONENTIAL\""
301+
"\"COLOR\""
302+
303+
"\"KHR_mesh_quantization\""

gltf/gltfpack.cpp

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1794,6 +1794,54 @@ extern "C" int pack(int argc, char** argv)
17941794
#endif
17951795

17961796
#ifdef GLTFFUZZ
1797+
extern "C" size_t LLVMFuzzerMutate(uint8_t* data, size_t size, size_t max_size);
1798+
1799+
extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* data, size_t size, size_t max_size, unsigned int seed)
1800+
{
1801+
// parse glTF/JSON chunk headers
1802+
if (size < 28 || memcmp(data, "glTF", 4) != 0 || memcmp(data + 16, "JSON", 4) != 0)
1803+
return LLVMFuzzerMutate(data, size, max_size);
1804+
1805+
uint32_t total_size, json_size;
1806+
memcpy(&total_size, data + 8, 4);
1807+
memcpy(&json_size, data + 12, 4);
1808+
1809+
// parse BIN chunk header (note, we assume it's required for simplicity)
1810+
if (json_size > size - 28 || memcmp(data + 24 + json_size, "BIN", 4) != 0)
1811+
return LLVMFuzzerMutate(data, size, max_size);
1812+
1813+
uint32_t bin_size;
1814+
memcpy(&bin_size, data + 20 + json_size, 4);
1815+
1816+
// final validation; note that all chunks must be 4 byte aligned
1817+
if (total_size != size || bin_size > size - 28 - json_size || 28 + json_size + bin_size != size || ((bin_size | json_size) & 3) != 0)
1818+
return LLVMFuzzerMutate(data, size, max_size);
1819+
1820+
// pick chunk to mutate; we default to mutating JSON but mutate BIN with 10% probability
1821+
bool mutate_bin = seed % 10 == 0;
1822+
size_t target_offset = mutate_bin ? 28 + json_size : 20;
1823+
size_t target_size = mutate_bin ? bin_size : json_size;
1824+
1825+
size_t target_capacity = (max_size - (size - target_size)) & ~3;
1826+
1827+
// mutate chunk and pad it to 4 byte boundary to maintain GLB alignment
1828+
std::vector<uint8_t> target(data + target_offset, data + target_offset + target_size);
1829+
target.resize(target_capacity);
1830+
target.resize(LLVMFuzzerMutate(target.data(), target_size, target_capacity));
1831+
target.resize((target.size() + 3) & ~3, mutate_bin ? 0 : ' ');
1832+
1833+
uint32_t new_target_size = uint32_t(target.size());
1834+
uint32_t new_total_size = uint32_t(size - target_size + new_target_size);
1835+
1836+
// patch the target chunk and update chunk length as well as total length
1837+
memmove(data + target_offset + new_target_size, data + target_offset + target_size, size - target_offset - target_size);
1838+
memcpy(data + target_offset, target.data(), new_target_size);
1839+
memcpy(data + 8, &new_total_size, 4);
1840+
memcpy(data + target_offset - 8, &new_target_size, 4);
1841+
1842+
return new_total_size;
1843+
}
1844+
17971845
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* buffer, size_t size)
17981846
{
17991847
Settings settings = defaults();
@@ -1816,7 +1864,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* buffer, size_t size)
18161864

18171865
std::string json, bin, fallback;
18181866
size_t fallback_size = 0;
1819-
process(data, NULL, NULL, NULL, meshes, animations, settings, json, bin, fallback, fallback_size, NULL);
1867+
process(data, NULL, NULL, NULL, meshes, animations, settings, json, bin, fallback, fallback_size, "KHR_meshopt_compression");
18201868

18211869
cgltf_free(data);
18221870

gltf/parsegltf.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,14 @@ static void parseMeshesGltf(cgltf_data* data, std::vector<Mesh>& meshes, std::ve
181181
continue;
182182
}
183183

184+
const cgltf_accessor* positions = cgltf_find_accessor(&primitive, cgltf_attribute_type_position, 0);
185+
186+
if (!positions)
187+
{
188+
fprintf(stderr, "Warning: ignoring primitive %d of mesh %d because it has no position data\n", int(pi), int(mi));
189+
continue;
190+
}
191+
184192
meshes.push_back(Mesh());
185193
Mesh& result = meshes.back();
186194

@@ -191,7 +199,7 @@ static void parseMeshesGltf(cgltf_data* data, std::vector<Mesh>& meshes, std::ve
191199

192200
result.streams.reserve(primitive.attributes_count);
193201

194-
size_t vertex_count = primitive.attributes_count ? primitive.attributes[0].data->count : 0;
202+
size_t vertex_count = positions->count;
195203

196204
if (primitive.indices)
197205
{

0 commit comments

Comments
 (0)