diff --git a/Zend/tests/ignore_repeated_errors_interleaved.phpt b/Zend/tests/ignore_repeated_errors_interleaved.phpt new file mode 100644 index 000000000000..7dd764aa1871 --- /dev/null +++ b/Zend/tests/ignore_repeated_errors_interleaved.phpt @@ -0,0 +1,15 @@ +--TEST-- +Test ignore_repeated_errors with interleaved error types +--INI-- +ignore_repeated_errors=1 +error_reporting=-1 +--FILE-- + +--EXPECTF-- +Warning: Undefined variable $missing in %s on line %d + +Deprecated: trim(): Passing null to parameter #1 ($string) of type string is deprecated in %s on line %d diff --git a/main/main.c b/main/main.c index 1e4acfc8aa98..149b4967e60e 100644 --- a/main/main.c +++ b/main/main.c @@ -1286,7 +1286,7 @@ PHPAPI void php_html_puts(const char *str, size_t size) } /* }}} */ -static void clear_last_error(void) { +static void clear_last_error(bool clear_repeated_errors) { if (PG(last_error_message)) { zend_string_release(PG(last_error_message)); PG(last_error_message) = NULL; @@ -1295,6 +1295,16 @@ static void clear_last_error(void) { zend_string_release(PG(last_error_file)); PG(last_error_file) = NULL; } + if (clear_repeated_errors) { + for (uint32_t i = 0; i < 32; i++) { + if (PG(repeated_error_messages)[i]) { + zend_string_release(PG(repeated_error_messages)[i]); + PG(repeated_error_messages)[i] = NULL; + zend_string_release(PG(repeated_error_files)[i]); + PG(repeated_error_files)[i] = NULL; + } + } + } } #if ZEND_DEBUG @@ -1328,16 +1338,20 @@ static ZEND_COLD void php_error_cb(int orig_type, zend_string *error_filename, c { bool display; int type = orig_type & E_ALL; + uint32_t repeated_error_index = 0; zend_string *backtrace = ZSTR_EMPTY_ALLOC(); + zend_string *repeated_error_file = error_filename ? error_filename : ZSTR_KNOWN(ZEND_STR_UNKNOWN_CAPITALIZED); + + while (repeated_error_index < 31 && !(type & (1U << repeated_error_index))) { + repeated_error_index++; + } /* check for repeated errors to be ignored */ - if (PG(ignore_repeated_errors) && PG(last_error_message)) { - /* no check for PG(last_error_file) is needed since it cannot - * be NULL if PG(last_error_message) is not NULL */ - if (!zend_string_equals(PG(last_error_message), message) + if (PG(ignore_repeated_errors) && PG(repeated_error_messages)[repeated_error_index]) { + if (!zend_string_equals(PG(repeated_error_messages)[repeated_error_index], message) || (!PG(ignore_repeated_source) - && ((PG(last_error_lineno) != error_lineno) - || !zend_string_equals(PG(last_error_file), error_filename)))) { + && ((PG(repeated_error_linenos)[repeated_error_index] != (int)error_lineno) + || !zend_string_equals(PG(repeated_error_files)[repeated_error_index], repeated_error_file)))) { display = 1; } else { display = 0; @@ -1374,7 +1388,7 @@ static ZEND_COLD void php_error_cb(int orig_type, zend_string *error_filename, c /* store the error if it has changed */ if (display) { - clear_last_error(); + clear_last_error(false); if (!error_filename) { error_filename = ZSTR_KNOWN(ZEND_STR_UNKNOWN_CAPITALIZED); } @@ -1384,6 +1398,17 @@ static ZEND_COLD void php_error_cb(int orig_type, zend_string *error_filename, c PG(last_error_lineno) = error_lineno; } + if (!PG(repeated_error_messages)[repeated_error_index] + || display) { + if (PG(repeated_error_messages)[repeated_error_index]) { + zend_string_release(PG(repeated_error_messages)[repeated_error_index]); + zend_string_release(PG(repeated_error_files)[repeated_error_index]); + } + PG(repeated_error_linenos)[repeated_error_index] = error_lineno; + PG(repeated_error_messages)[repeated_error_index] = zend_string_copy(message); + PG(repeated_error_files)[repeated_error_index] = zend_string_copy(repeated_error_file); + } + /* Discarding the output buffers frees every handler on the stack, which is * not safe while one of them is running */ if (zend_alloc_in_memory_limit_error_reporting() @@ -1708,7 +1733,7 @@ static zval *php_get_configuration_directive_for_zend(zend_string *name) /* {{{ php_free_request_globals */ static void php_free_request_globals(void) { - clear_last_error(); + clear_last_error(true); if (PG(php_sys_temp_dir)) { efree(PG(php_sys_temp_dir)); PG(php_sys_temp_dir) = NULL; @@ -2039,7 +2064,7 @@ void php_request_shutdown(void *dummy) /* 16. Free Willy (here be crashes) */ zend_arena_destroy(CG(arena)); zend_interned_strings_deactivate(); - clear_last_error(); + clear_last_error(true); zend_try { shutdown_memory_manager(CG(unclean_shutdown) || !report_memleaks, 0); } zend_end_try(); @@ -2456,7 +2481,7 @@ zend_result php_module_startup(sapi_module_struct *sf, zend_module_entry *additi module_startup = false; /* Don't leak errors from startup into the per-request phase. */ - clear_last_error(); + clear_last_error(true); shutdown_memory_manager(1, 0); virtual_cwd_activate(); @@ -2519,7 +2544,7 @@ void php_module_shutdown(void) /* close down the ini config */ php_shutdown_config(); - clear_last_error(); + clear_last_error(true); #ifndef ZTS zend_ini_shutdown(); diff --git a/main/php_globals.h b/main/php_globals.h index e3cfe38a63fd..c45000494d2b 100644 --- a/main/php_globals.h +++ b/main/php_globals.h @@ -139,6 +139,9 @@ struct _php_core_globals { uint32_t last_error_lineno; zend_string *last_error_message; zend_string *last_error_file; + int repeated_error_linenos[32]; + zend_string *repeated_error_messages[32]; + zend_string *repeated_error_files[32]; char *php_sys_temp_dir;