diff --git a/sapi/fuzzer/fuzzer-json.c b/sapi/fuzzer/fuzzer-json.c index 0407a895835e..7ffa28df245a 100644 --- a/sapi/fuzzer/fuzzer-json.c +++ b/sapi/fuzzer/fuzzer-json.c @@ -27,6 +27,10 @@ #include "ext/json/php_json.h" #include "ext/json/php_json_parser.h" +/* Lower than the default depth of 512, so that deeply nested inputs fail quickly and the + * depth limit is reached with small inputs. */ +#define MAX_DEPTH 10 + int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { if (fuzzer_request_startup() == FAILURE){ @@ -55,10 +59,20 @@ int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { for (int index = 0; index < 12; ++index) { zval result; php_json_parser parser; - php_json_parser_init(&parser, &result, data, Size, options[index], 10); - if (php_json_yyparse(&parser) == SUCCESS) { + php_json_parser_init(&parser, &result, data, Size, options[index], MAX_DEPTH); + bool decoded = php_json_yyparse(&parser) == SUCCESS; + if (decoded) { zval_ptr_dtor(&result); } + + /* json_validate() must agree with json_decode(). Only compare when decoding to arrays, + * as decoding to objects additionally rejects property names starting with a NUL byte. */ + if (options[index] == PHP_JSON_OBJECT_AS_ARRAY + || options[index] == (PHP_JSON_OBJECT_AS_ARRAY | PHP_JSON_INVALID_UTF8_IGNORE)) { + bool valid = php_json_validate_ex(data, Size, + options[index] & PHP_JSON_INVALID_UTF8_IGNORE, MAX_DEPTH); + ZEND_ASSERT(valid == decoded); + } } php_request_shutdown(NULL);