diff --git a/sapi/fuzzer/fuzzer-execute.c b/sapi/fuzzer/fuzzer-execute.c index 83b56017300..a65c8819ab4 100644 --- a/sapi/fuzzer/fuzzer-execute.c +++ b/sapi/fuzzer/fuzzer-execute.c @@ -27,16 +27,19 @@ static uint32_t steps_left; * we can assume that we don't use global registers / hybrid VM. */ typedef int (ZEND_FASTCALL *opcode_handler_t)(zend_execute_data *); +static zend_always_inline void fuzzer_step(void) { + if (--steps_left == 0) { + /* Reset steps before bailing out, so code running after bailout (e.g. in + * destructors) will get another MAX_STEPS, rather than UINT32_MAX steps. */ + steps_left = MAX_STEPS; + zend_bailout(); + } +} + static void fuzzer_execute_ex(zend_execute_data *execute_data) { while (1) { int ret; - if (--steps_left == 0) { - /* Reset steps before bailing out, so code running after bailout (e.g. in - * destructors) will get another MAX_STEPS, rather than UINT32_MAX steps. */ - steps_left = MAX_STEPS; - zend_bailout(); - } - + fuzzer_step(); if ((ret = ((opcode_handler_t) EX(opline)->handler)(execute_data)) != 0) { if (ret > 0) { execute_data = EG(current_execute_data); @@ -58,6 +61,13 @@ static zend_op_array *fuzzer_compile_string(zend_string *str, const char *filena return orig_compile_string(str, filename); } +static void (*orig_execute_internal)(zend_execute_data *execute_data, zval *return_value); + +static void fuzzer_execute_internal(zend_execute_data *execute_data, zval *return_value) { + fuzzer_step(); + orig_execute_internal(execute_data, return_value); +} + int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { if (Size > MAX_SIZE) { /* Large inputs have a large impact on fuzzer performance, @@ -82,6 +92,8 @@ int LLVMFuzzerInitialize(int *argc, char ***argv) { fuzzer_init_php(); zend_execute_ex = fuzzer_execute_ex; + orig_execute_internal = zend_execute_internal ? zend_execute_internal : execute_internal; + zend_execute_internal = fuzzer_execute_internal; orig_compile_string = zend_compile_string; zend_compile_string = fuzzer_compile_string;