diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index f0d3379534591..0456017dae055 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -2209,7 +2209,14 @@ zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type) SHM_PROTECT(); HANDLE_UNBLOCK_INTERRUPTIONS(); - zend_emit_recorded_errors(); + /* We may have switched to an existing persistent script that was persisted in + * the meantime. Make sure to use its warnings if available. */ + if (ZCG(accel_directives).record_warnings) { + EG(record_errors) = false; + zend_emit_recorded_errors_ex(persistent_script->num_warnings, persistent_script->warnings); + } else { + zend_emit_recorded_errors(); + } zend_free_recorded_errors(); } else { diff --git a/ext/opcache/tests/gh19984.phpt b/ext/opcache/tests/gh19984.phpt new file mode 100644 index 0000000000000..4584fa6494c18 --- /dev/null +++ b/ext/opcache/tests/gh19984.phpt @@ -0,0 +1,21 @@ +--TEST-- +GH-19984: Double-free of EG(errors)/persistent_script->warnings on persist of already persisted file +--EXTENSIONS-- +opcache +pcntl +--INI-- +opcache.enable_cli=1 +opcache.record_warnings=1 +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +Warning: Unsupported declare 'unknown' in %s on line %d + +Warning: Unsupported declare 'unknown' in %s on line %d diff --git a/ext/opcache/zend_accelerator_util_funcs.c b/ext/opcache/zend_accelerator_util_funcs.c index 21f056901fd1b..99523ca72279d 100644 --- a/ext/opcache/zend_accelerator_util_funcs.c +++ b/ext/opcache/zend_accelerator_util_funcs.c @@ -65,16 +65,6 @@ void free_persistent_script(zend_persistent_script *persistent_script, int destr zend_string_release_ex(persistent_script->script.filename, 0); } - if (persistent_script->warnings) { - for (uint32_t i = 0; i < persistent_script->num_warnings; i++) { - zend_error_info *info = persistent_script->warnings[i]; - zend_string_release(info->filename); - zend_string_release(info->message); - efree(info); - } - efree(persistent_script->warnings); - } - zend_accel_free_delayed_early_binding_list(persistent_script); efree(persistent_script);