diff --git a/tests/fuzzer/advanced_api_fuzzer.c b/tests/fuzzer/advanced_api_fuzzer.c index da4613bb..29b1f259 100644 --- a/tests/fuzzer/advanced_api_fuzzer.c +++ b/tests/fuzzer/advanced_api_fuzzer.c @@ -14,10 +14,13 @@ // //////////////////////////////////////////////////////////////////////////////// +#include + #include "./fuzz_utils.h" #include "webp/decode.h" int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) { + int i; WebPDecoderConfig config; if (!WebPInitDecoderConfig(&config)) return 0; if (WebPGetFeatures(data, size, &config.input) != VP8_STATUS_OK) return 0; @@ -59,39 +62,53 @@ int LLVMFuzzerTestOneInput(const uint8_t* const data, size_t size) { config.output.colorspace = (WEBP_CSP_MODE)(value % MODE_LAST); #endif // WEBP_REDUCE_CSP - if (size % 3) { - // Decodes incrementally in chunks of increasing size. - WebPIDecoder* idec = WebPIDecode(NULL, 0, &config); - if (!idec) return 0; - VP8StatusCode status; - if (size & 8) { - size_t available_size = value + 1; - while (1) { - if (available_size > size) available_size = size; - status = WebPIUpdate(idec, data, available_size); - if (status != VP8_STATUS_SUSPENDED || available_size == size) break; - available_size *= 2; - } - } else { - // WebPIAppend expects new data and its size with each call. - // Implemented here by simply advancing the pointer into data. - const uint8_t* new_data = data; - size_t new_size = value + 1; - while (1) { - if (new_data + new_size > data + size) { - new_size = data + size - new_data; - } - status = WebPIAppend(idec, new_data, new_size); - if (status != VP8_STATUS_SUSPENDED || new_size == 0) break; - new_data += new_size; - new_size *= 2; + for (i = 0; i < 2; ++i) { + if (i == 1) { + // Use the bitstream data to generate extreme ranges for the options. An + // alternative approach would be to use a custom corpus containing webp + // files prepended with sizeof(config.options) zeroes to allow the fuzzer + // to modify these independently. + const int data_offset = 50; + if (size > data_offset + sizeof(config.options)) { + memcpy(&config.options, data + data_offset, sizeof(config.options)); + } else { + break; } } - WebPIDelete(idec); - } else { - WebPDecode(data, size, &config); - } + if (size % 3) { + // Decodes incrementally in chunks of increasing size. + WebPIDecoder* idec = WebPIDecode(NULL, 0, &config); + if (!idec) return 0; + VP8StatusCode status; + if (size & 8) { + size_t available_size = value + 1; + while (1) { + if (available_size > size) available_size = size; + status = WebPIUpdate(idec, data, available_size); + if (status != VP8_STATUS_SUSPENDED || available_size == size) break; + available_size *= 2; + } + } else { + // WebPIAppend expects new data and its size with each call. + // Implemented here by simply advancing the pointer into data. + const uint8_t* new_data = data; + size_t new_size = value + 1; + while (1) { + if (new_data + new_size > data + size) { + new_size = data + size - new_data; + } + status = WebPIAppend(idec, new_data, new_size); + if (status != VP8_STATUS_SUSPENDED || new_size == 0) break; + new_data += new_size; + new_size *= 2; + } + } + WebPIDelete(idec); + } else { + WebPDecode(data, size, &config); + } - WebPFreeDecBuffer(&config.output); + WebPFreeDecBuffer(&config.output); + } return 0; }