@@ -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+
17971845extern " 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
0 commit comments