mirror of
https://github.com/php/php-src.git
synced 2025-08-15 13:38:49 +02:00
Fix error handling inconsistency with opcache
When opcache is enabled, error handling is altered in the following ways: * Errors emitted during compilation bypass the user-defined error handler * Exceptions emitted during class linking are turned into fatal errors Changes here make the behavior consistent regardless of opcache being enabled or not: * Errors emitted during compilation and class linking are always delayed and handled after compilation or class linking. During handling, user-defined error handlers are not bypassed. Fatal errors emitted during compilation or class linking cause any delayed errors to be handled immediately (without calling user-defined error handlers, as it would be unsafe). * Exceptions thrown by user-defined error handlers when handling class linking error are not promoted to fatal errors anymore and do not prevent linking. Fixes GH-17422. Closes GH-18541. Closes GH-17627. Co-authored-by: Tim Düsterhus <tim@bastelstu.be>
This commit is contained in:
parent
9b777b3c35
commit
7b3e68ff69
36 changed files with 408 additions and 61 deletions
1
.github/scripts/windows/test_task.bat
vendored
1
.github/scripts/windows/test_task.bat
vendored
|
@ -128,6 +128,7 @@ mkdir %PHP_BUILD_DIR%\test_file_cache
|
||||||
rem generate php.ini
|
rem generate php.ini
|
||||||
echo extension_dir=%PHP_BUILD_DIR% > %PHP_BUILD_DIR%\php.ini
|
echo extension_dir=%PHP_BUILD_DIR% > %PHP_BUILD_DIR%\php.ini
|
||||||
echo opcache.file_cache=%PHP_BUILD_DIR%\test_file_cache >> %PHP_BUILD_DIR%\php.ini
|
echo opcache.file_cache=%PHP_BUILD_DIR%\test_file_cache >> %PHP_BUILD_DIR%\php.ini
|
||||||
|
echo opcache.record_warnings=1 >> %PHP_BUILD_DIR%\php.ini
|
||||||
rem work-around for some spawned PHP processes requiring OpenSSL and sockets
|
rem work-around for some spawned PHP processes requiring OpenSSL and sockets
|
||||||
echo extension=php_openssl.dll >> %PHP_BUILD_DIR%\php.ini
|
echo extension=php_openssl.dll >> %PHP_BUILD_DIR%\php.ini
|
||||||
echo extension=php_sockets.dll >> %PHP_BUILD_DIR%\php.ini
|
echo extension=php_sockets.dll >> %PHP_BUILD_DIR%\php.ini
|
||||||
|
|
5
NEWS
5
NEWS
|
@ -15,8 +15,11 @@ PHP NEWS
|
||||||
- OPcache:
|
- OPcache:
|
||||||
. Disallow changing opcache.memory_consumption when SHM is already set up.
|
. Disallow changing opcache.memory_consumption when SHM is already set up.
|
||||||
(timwolla)
|
(timwolla)
|
||||||
. Fixed GH-15074 (Compiling opcache statically into ZTS PHP fails). (Arnaud)
|
. Fixed bug GH-15074 (Compiling opcache statically into ZTS PHP fails).
|
||||||
|
(Arnaud)
|
||||||
. Make OPcache non-optional (Arnaud, timwolla)
|
. Make OPcache non-optional (Arnaud, timwolla)
|
||||||
|
. Fixed bug GH-17422 (OPcache bypasses the user-defined error handler for
|
||||||
|
deprecations). (Arnaud, timwolla)
|
||||||
|
|
||||||
- OpenSSL:
|
- OpenSSL:
|
||||||
. Add $digest_algo parameter to openssl_public_encrypt() and
|
. Add $digest_algo parameter to openssl_public_encrypt() and
|
||||||
|
|
|
@ -44,6 +44,12 @@ PHP 8.5 UPGRADE NOTES
|
||||||
. Traits are now bound before the parent class. This is a subtle behavioral
|
. Traits are now bound before the parent class. This is a subtle behavioral
|
||||||
change, but should more closely match user expectations, demonstrated by
|
change, but should more closely match user expectations, demonstrated by
|
||||||
GH-15753 and GH-16198.
|
GH-15753 and GH-16198.
|
||||||
|
. Errors emitted during compilation and class linking are now always delayed
|
||||||
|
and handled after compilation or class linking. Fatal errors emitted during
|
||||||
|
compilation or class linking cause any delayed errors to be handled
|
||||||
|
immediately, without calling user-defined error handlers.
|
||||||
|
. Exceptions thrown by user-defined error handlers when handling class linking
|
||||||
|
errors are not promoted to fatal errors anymore and do not prevent linking.
|
||||||
|
|
||||||
- DOM:
|
- DOM:
|
||||||
. Cloning a DOMNamedNodeMap, DOMNodeList, Dom\NamedNodeMap, Dom\NodeList,
|
. Cloning a DOMNamedNodeMap, DOMNodeList, Dom\NamedNodeMap, Dom\NodeList,
|
||||||
|
|
|
@ -71,6 +71,8 @@ PHP 8.5 INTERNALS UPGRADE NOTES
|
||||||
* zend_register_string_constant()
|
* zend_register_string_constant()
|
||||||
* zend_register_stringl_constant()
|
* zend_register_stringl_constant()
|
||||||
. EG(fake_scope) now is a _const_ zend_class_entry*.
|
. EG(fake_scope) now is a _const_ zend_class_entry*.
|
||||||
|
. zend_begin_record_errors() or EG(record_errors)=true cause errors to be
|
||||||
|
delayed. Before, errors would be recorded but not delayed.
|
||||||
|
|
||||||
========================
|
========================
|
||||||
2. Build system changes
|
2. Build system changes
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
--TEST--
|
--TEST--
|
||||||
Deprecation promoted to exception should result in fatal error during inheritance
|
Deprecation promoted to exception during inheritance
|
||||||
--SKIPIF--
|
--SKIPIF--
|
||||||
<?php
|
<?php
|
||||||
if (getenv('SKIP_PRELOAD')) die('skip Error handler not active during preloading');
|
if (getenv('SKIP_PRELOAD')) die('skip Error handler not active during preloading');
|
||||||
|
@ -17,7 +17,8 @@ $class = new class extends DateTime {
|
||||||
|
|
||||||
?>
|
?>
|
||||||
--EXPECTF--
|
--EXPECTF--
|
||||||
Fatal error: During inheritance of DateTime: Uncaught Exception: Return type of DateTime@anonymous::getTimezone() should either be compatible with DateTime::getTimezone(): DateTimeZone|false, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in %s:%d
|
Fatal error: Uncaught Exception: Return type of DateTime@anonymous::getTimezone() should either be compatible with DateTime::getTimezone(): DateTimeZone|false, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in %s:%d
|
||||||
Stack trace:
|
Stack trace:
|
||||||
#0 %s(%d): {closure:%s:%d}(8192, 'Return type of ...', '%s', 8)
|
#0 %s(%d): {closure:%s:%d}(8192, 'Return type of ...', '%s', 8)
|
||||||
#1 {main} in %s on line %d
|
#1 {main}
|
||||||
|
thrown in %s on line %d
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
--TEST--
|
||||||
|
Deprecation promoted to exception during inheritance
|
||||||
|
--SKIPIF--
|
||||||
|
<?php
|
||||||
|
if (getenv('SKIP_PRELOAD')) die('skip Error handler not active during preloading');
|
||||||
|
?>
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
set_error_handler(function($code, $message) {
|
||||||
|
throw new Exception($message);
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
class C extends DateTime {
|
||||||
|
public function getTimezone() {}
|
||||||
|
public function getTimestamp() {}
|
||||||
|
};
|
||||||
|
} catch (Exception $e) {
|
||||||
|
printf("%s: %s\n", $e::class, $e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
var_dump(new C());
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
Exception: Return type of C::getTimezone() should either be compatible with DateTime::getTimezone(): DateTimeZone|false, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice
|
||||||
|
object(C)#%d (3) {
|
||||||
|
["date"]=>
|
||||||
|
string(%d) "%s"
|
||||||
|
["timezone_type"]=>
|
||||||
|
int(3)
|
||||||
|
["timezone"]=>
|
||||||
|
string(3) "UTC"
|
||||||
|
}
|
|
@ -14,5 +14,8 @@ class C implements Serializable {
|
||||||
|
|
||||||
?>
|
?>
|
||||||
--EXPECTF--
|
--EXPECTF--
|
||||||
Fatal error: During inheritance of C, while implementing Serializable: Uncaught Exception: C implements the Serializable interface, which is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in %s:%d
|
Fatal error: Uncaught Exception: C implements the Serializable interface, which is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) in %s:%d
|
||||||
%a
|
Stack trace:
|
||||||
|
#0 %s(%d): {closure:%s:%d}(8192, 'C implements th...', '%s', 7)
|
||||||
|
#1 {main}
|
||||||
|
thrown in %s on line %d
|
||||||
|
|
41
Zend/zend.c
41
Zend/zend.c
|
@ -1452,6 +1452,29 @@ ZEND_API ZEND_COLD void zend_error_zstr_at(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Emit any delayed error before handling fatal error */
|
||||||
|
if ((type & E_FATAL_ERRORS) && !(type & E_DONT_BAIL) && EG(num_errors)) {
|
||||||
|
uint32_t num_errors = EG(num_errors);
|
||||||
|
zend_error_info **errors = EG(errors);
|
||||||
|
EG(num_errors) = 0;
|
||||||
|
EG(errors) = NULL;
|
||||||
|
|
||||||
|
bool orig_record_errors = EG(record_errors);
|
||||||
|
EG(record_errors) = false;
|
||||||
|
|
||||||
|
/* Disable user error handler before emitting delayed errors, as
|
||||||
|
* it's unsafe to execute user code after a fatal error. */
|
||||||
|
int orig_user_error_handler_error_reporting = EG(user_error_handler_error_reporting);
|
||||||
|
EG(user_error_handler_error_reporting) = 0;
|
||||||
|
|
||||||
|
zend_emit_recorded_errors_ex(num_errors, errors);
|
||||||
|
|
||||||
|
EG(user_error_handler_error_reporting) = orig_user_error_handler_error_reporting;
|
||||||
|
EG(record_errors) = orig_record_errors;
|
||||||
|
EG(num_errors) = num_errors;
|
||||||
|
EG(errors) = errors;
|
||||||
|
}
|
||||||
|
|
||||||
if (EG(record_errors)) {
|
if (EG(record_errors)) {
|
||||||
zend_error_info *info = emalloc(sizeof(zend_error_info));
|
zend_error_info *info = emalloc(sizeof(zend_error_info));
|
||||||
info->type = type;
|
info->type = type;
|
||||||
|
@ -1464,6 +1487,11 @@ ZEND_API ZEND_COLD void zend_error_zstr_at(
|
||||||
EG(num_errors)++;
|
EG(num_errors)++;
|
||||||
EG(errors) = erealloc(EG(errors), sizeof(zend_error_info*) * EG(num_errors));
|
EG(errors) = erealloc(EG(errors), sizeof(zend_error_info*) * EG(num_errors));
|
||||||
EG(errors)[EG(num_errors)-1] = info;
|
EG(errors)[EG(num_errors)-1] = info;
|
||||||
|
|
||||||
|
/* Do not process non-fatal recorded error */
|
||||||
|
if (!(type & E_FATAL_ERRORS) || (type & E_DONT_BAIL)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Always clear the last backtrace.
|
// Always clear the last backtrace.
|
||||||
|
@ -1752,13 +1780,18 @@ ZEND_API void zend_begin_record_errors(void)
|
||||||
EG(errors) = NULL;
|
EG(errors) = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ZEND_API void zend_emit_recorded_errors_ex(uint32_t num_errors, zend_error_info **errors)
|
||||||
|
{
|
||||||
|
for (uint32_t i = 0; i < num_errors; i++) {
|
||||||
|
zend_error_info *error = errors[i];
|
||||||
|
zend_error_zstr_at(error->type, error->filename, error->lineno, error->message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ZEND_API void zend_emit_recorded_errors(void)
|
ZEND_API void zend_emit_recorded_errors(void)
|
||||||
{
|
{
|
||||||
EG(record_errors) = false;
|
EG(record_errors) = false;
|
||||||
for (uint32_t i = 0; i < EG(num_errors); i++) {
|
zend_emit_recorded_errors_ex(EG(num_errors), EG(errors));
|
||||||
zend_error_info *error = EG(errors)[i];
|
|
||||||
zend_error_zstr_at(error->type, error->filename, error->lineno, error->message);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ZEND_API void zend_free_recorded_errors(void)
|
ZEND_API void zend_free_recorded_errors(void)
|
||||||
|
|
|
@ -444,6 +444,7 @@ ZEND_API void zend_replace_error_handling(zend_error_handling_t error_handling,
|
||||||
ZEND_API void zend_restore_error_handling(zend_error_handling *saved);
|
ZEND_API void zend_restore_error_handling(zend_error_handling *saved);
|
||||||
ZEND_API void zend_begin_record_errors(void);
|
ZEND_API void zend_begin_record_errors(void);
|
||||||
ZEND_API void zend_emit_recorded_errors(void);
|
ZEND_API void zend_emit_recorded_errors(void);
|
||||||
|
ZEND_API void zend_emit_recorded_errors_ex(uint32_t num_errors, zend_error_info **errors);
|
||||||
ZEND_API void zend_free_recorded_errors(void);
|
ZEND_API void zend_free_recorded_errors(void);
|
||||||
END_EXTERN_C()
|
END_EXTERN_C()
|
||||||
|
|
||||||
|
|
|
@ -1327,7 +1327,6 @@ ZEND_API zend_class_entry *zend_bind_class_in_slot(
|
||||||
|
|
||||||
ce = zend_do_link_class(ce, lc_parent_name, Z_STR_P(lcname));
|
ce = zend_do_link_class(ce, lc_parent_name, Z_STR_P(lcname));
|
||||||
if (ce) {
|
if (ce) {
|
||||||
ZEND_ASSERT(!EG(exception));
|
|
||||||
zend_observer_class_linked_notify(ce, Z_STR_P(lcname));
|
zend_observer_class_linked_notify(ce, Z_STR_P(lcname));
|
||||||
return ce;
|
return ce;
|
||||||
}
|
}
|
||||||
|
|
|
@ -295,7 +295,8 @@ struct _zend_executor_globals {
|
||||||
size_t fiber_stack_size;
|
size_t fiber_stack_size;
|
||||||
|
|
||||||
/* If record_errors is enabled, all emitted diagnostics will be recorded,
|
/* If record_errors is enabled, all emitted diagnostics will be recorded,
|
||||||
* in addition to being processed as usual. */
|
* and their processing is delayed until zend_emit_recorded_errors()
|
||||||
|
* is called or a fatal diagnostic is emitted. */
|
||||||
bool record_errors;
|
bool record_errors;
|
||||||
uint32_t num_errors;
|
uint32_t num_errors;
|
||||||
zend_error_info **errors;
|
zend_error_info **errors;
|
||||||
|
|
|
@ -1085,10 +1085,7 @@ static void ZEND_COLD emit_incompatible_method_error(
|
||||||
"Return type of %s should either be compatible with %s, "
|
"Return type of %s should either be compatible with %s, "
|
||||||
"or the #[\\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice",
|
"or the #[\\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice",
|
||||||
ZSTR_VAL(child_prototype), ZSTR_VAL(parent_prototype));
|
ZSTR_VAL(child_prototype), ZSTR_VAL(parent_prototype));
|
||||||
if (EG(exception)) {
|
ZEND_ASSERT(!EG(exception));
|
||||||
zend_exception_uncaught_error(
|
|
||||||
"During inheritance of %s", ZSTR_VAL(parent_scope->name));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
zend_error_at(E_COMPILE_ERROR, func_filename(child), func_lineno(child),
|
zend_error_at(E_COMPILE_ERROR, func_filename(child), func_lineno(child),
|
||||||
|
@ -3561,8 +3558,6 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool orig_record_errors = EG(record_errors);
|
|
||||||
|
|
||||||
if (ce->ce_flags & ZEND_ACC_IMMUTABLE && is_cacheable) {
|
if (ce->ce_flags & ZEND_ACC_IMMUTABLE && is_cacheable) {
|
||||||
if (zend_inheritance_cache_get && zend_inheritance_cache_add) {
|
if (zend_inheritance_cache_get && zend_inheritance_cache_add) {
|
||||||
zend_class_entry *ret = zend_inheritance_cache_get(ce, parent, traits_and_interfaces);
|
zend_class_entry *ret = zend_inheritance_cache_get(ce, parent, traits_and_interfaces);
|
||||||
|
@ -3574,16 +3569,21 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string
|
||||||
Z_CE_P(zv) = ret;
|
Z_CE_P(zv) = ret;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make sure warnings (such as deprecations) thrown during inheritance
|
|
||||||
* will be recorded in the inheritance cache. */
|
|
||||||
zend_begin_record_errors();
|
|
||||||
} else {
|
} else {
|
||||||
is_cacheable = 0;
|
is_cacheable = 0;
|
||||||
}
|
}
|
||||||
proto = ce;
|
proto = ce;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Delay and record warnings (such as deprecations) thrown during
|
||||||
|
* inheritance, so they will be recorded in the inheritance cache.
|
||||||
|
* Warnings must be delayed in all cases so that we get a consistent
|
||||||
|
* behavior regardless of cacheability. */
|
||||||
|
bool orig_record_errors = EG(record_errors);
|
||||||
|
if (!orig_record_errors) {
|
||||||
|
zend_begin_record_errors();
|
||||||
|
}
|
||||||
|
|
||||||
zend_try {
|
zend_try {
|
||||||
if (ce->ce_flags & ZEND_ACC_IMMUTABLE) {
|
if (ce->ce_flags & ZEND_ACC_IMMUTABLE) {
|
||||||
/* Lazy class loading */
|
/* Lazy class loading */
|
||||||
|
@ -3774,6 +3774,7 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!orig_record_errors) {
|
if (!orig_record_errors) {
|
||||||
|
zend_emit_recorded_errors();
|
||||||
zend_free_recorded_errors();
|
zend_free_recorded_errors();
|
||||||
}
|
}
|
||||||
if (traits_and_interfaces) {
|
if (traits_and_interfaces) {
|
||||||
|
@ -3934,10 +3935,12 @@ ZEND_API zend_class_entry *zend_try_early_bind(zend_class_entry *ce, zend_class_
|
||||||
orig_linking_class = CG(current_linking_class);
|
orig_linking_class = CG(current_linking_class);
|
||||||
CG(current_linking_class) = is_cacheable ? ce : NULL;
|
CG(current_linking_class) = is_cacheable ? ce : NULL;
|
||||||
|
|
||||||
|
bool orig_record_errors = EG(record_errors);
|
||||||
|
|
||||||
zend_try{
|
zend_try{
|
||||||
CG(zend_lineno) = ce->info.user.line_start;
|
CG(zend_lineno) = ce->info.user.line_start;
|
||||||
|
|
||||||
if (is_cacheable) {
|
if (!orig_record_errors) {
|
||||||
zend_begin_record_errors();
|
zend_begin_record_errors();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3959,13 +3962,13 @@ ZEND_API zend_class_entry *zend_try_early_bind(zend_class_entry *ce, zend_class_
|
||||||
|
|
||||||
CG(current_linking_class) = orig_linking_class;
|
CG(current_linking_class) = orig_linking_class;
|
||||||
} zend_catch {
|
} zend_catch {
|
||||||
EG(record_errors) = false;
|
if (!orig_record_errors) {
|
||||||
zend_free_recorded_errors();
|
EG(record_errors) = false;
|
||||||
|
zend_free_recorded_errors();
|
||||||
|
}
|
||||||
zend_bailout();
|
zend_bailout();
|
||||||
} zend_end_try();
|
} zend_end_try();
|
||||||
|
|
||||||
EG(record_errors) = false;
|
|
||||||
|
|
||||||
if (is_cacheable) {
|
if (is_cacheable) {
|
||||||
HashTable *ht = (HashTable*)ce->inheritance_cache;
|
HashTable *ht = (HashTable*)ce->inheritance_cache;
|
||||||
zend_class_entry *new_ce;
|
zend_class_entry *new_ce;
|
||||||
|
@ -3983,6 +3986,11 @@ ZEND_API zend_class_entry *zend_try_early_bind(zend_class_entry *ce, zend_class_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!orig_record_errors) {
|
||||||
|
zend_emit_recorded_errors();
|
||||||
|
zend_free_recorded_errors();
|
||||||
|
}
|
||||||
|
|
||||||
if (ZSTR_HAS_CE_CACHE(ce->name)) {
|
if (ZSTR_HAS_CE_CACHE(ce->name)) {
|
||||||
ZSTR_SET_CE_CACHE(ce->name, ce);
|
ZSTR_SET_CE_CACHE(ce->name, ce);
|
||||||
}
|
}
|
||||||
|
|
|
@ -650,7 +650,17 @@ ZEND_API zend_op_array *compile_file(zend_file_handle *file_handle, int type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
bool orig_record_errors = EG(record_errors);
|
||||||
|
if (!orig_record_errors) {
|
||||||
|
zend_begin_record_errors();
|
||||||
|
}
|
||||||
|
|
||||||
op_array = zend_compile(ZEND_USER_FUNCTION);
|
op_array = zend_compile(ZEND_USER_FUNCTION);
|
||||||
|
|
||||||
|
if (!orig_record_errors) {
|
||||||
|
zend_emit_recorded_errors();
|
||||||
|
zend_free_recorded_errors();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
zend_restore_lexical_state(&original_lex_state);
|
zend_restore_lexical_state(&original_lex_state);
|
||||||
|
|
|
@ -7938,7 +7938,7 @@ ZEND_VM_HANDLER(145, ZEND_DECLARE_CLASS_DELAYED, CONST, CONST)
|
||||||
if (zv) {
|
if (zv) {
|
||||||
SAVE_OPLINE();
|
SAVE_OPLINE();
|
||||||
ce = zend_bind_class_in_slot(zv, lcname, Z_STR_P(RT_CONSTANT(opline, opline->op2)));
|
ce = zend_bind_class_in_slot(zv, lcname, Z_STR_P(RT_CONSTANT(opline, opline->op2)));
|
||||||
if (!ce) {
|
if (EG(exception)) {
|
||||||
HANDLE_EXCEPTION();
|
HANDLE_EXCEPTION();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7962,7 +7962,7 @@ ZEND_VM_HANDLER(146, ZEND_DECLARE_ANON_CLASS, ANY, ANY, CACHE_SLOT)
|
||||||
if (!(ce->ce_flags & ZEND_ACC_LINKED)) {
|
if (!(ce->ce_flags & ZEND_ACC_LINKED)) {
|
||||||
SAVE_OPLINE();
|
SAVE_OPLINE();
|
||||||
ce = zend_do_link_class(ce, (OP2_TYPE == IS_CONST) ? Z_STR_P(RT_CONSTANT(opline, opline->op2)) : NULL, rtd_key);
|
ce = zend_do_link_class(ce, (OP2_TYPE == IS_CONST) ? Z_STR_P(RT_CONSTANT(opline, opline->op2)) : NULL, rtd_key);
|
||||||
if (!ce) {
|
if (EG(exception)) {
|
||||||
HANDLE_EXCEPTION();
|
HANDLE_EXCEPTION();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
4
Zend/zend_vm_execute.h
generated
4
Zend/zend_vm_execute.h
generated
|
@ -3212,7 +3212,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DECLARE_ANON_CLASS_SPEC_HANDLE
|
||||||
if (!(ce->ce_flags & ZEND_ACC_LINKED)) {
|
if (!(ce->ce_flags & ZEND_ACC_LINKED)) {
|
||||||
SAVE_OPLINE();
|
SAVE_OPLINE();
|
||||||
ce = zend_do_link_class(ce, (opline->op2_type == IS_CONST) ? Z_STR_P(RT_CONSTANT(opline, opline->op2)) : NULL, rtd_key);
|
ce = zend_do_link_class(ce, (opline->op2_type == IS_CONST) ? Z_STR_P(RT_CONSTANT(opline, opline->op2)) : NULL, rtd_key);
|
||||||
if (!ce) {
|
if (EG(exception)) {
|
||||||
HANDLE_EXCEPTION();
|
HANDLE_EXCEPTION();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8014,7 +8014,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DECLARE_CLASS_DELAYED_SPEC_CON
|
||||||
if (zv) {
|
if (zv) {
|
||||||
SAVE_OPLINE();
|
SAVE_OPLINE();
|
||||||
ce = zend_bind_class_in_slot(zv, lcname, Z_STR_P(RT_CONSTANT(opline, opline->op2)));
|
ce = zend_bind_class_in_slot(zv, lcname, Z_STR_P(RT_CONSTANT(opline, opline->op2)));
|
||||||
if (!ce) {
|
if (EG(exception)) {
|
||||||
HANDLE_EXCEPTION();
|
HANDLE_EXCEPTION();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1734,19 +1734,11 @@ static void zend_accel_set_auto_globals(int mask)
|
||||||
ZCG(auto_globals_mask) |= mask;
|
ZCG(auto_globals_mask) |= mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void replay_warnings(uint32_t num_warnings, zend_error_info **warnings) {
|
|
||||||
for (uint32_t i = 0; i < num_warnings; i++) {
|
|
||||||
zend_error_info *warning = warnings[i];
|
|
||||||
zend_error_zstr_at(warning->type, warning->filename, warning->lineno, warning->message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static zend_persistent_script *opcache_compile_file(zend_file_handle *file_handle, int type, zend_op_array **op_array_p)
|
static zend_persistent_script *opcache_compile_file(zend_file_handle *file_handle, int type, zend_op_array **op_array_p)
|
||||||
{
|
{
|
||||||
zend_persistent_script *new_persistent_script;
|
zend_persistent_script *new_persistent_script;
|
||||||
uint32_t orig_functions_count, orig_class_count;
|
uint32_t orig_functions_count, orig_class_count;
|
||||||
zend_op_array *orig_active_op_array;
|
zend_op_array *orig_active_op_array;
|
||||||
zval orig_user_error_handler;
|
|
||||||
zend_op_array *op_array;
|
zend_op_array *op_array;
|
||||||
bool do_bailout = false;
|
bool do_bailout = false;
|
||||||
accel_time_t timestamp = 0;
|
accel_time_t timestamp = 0;
|
||||||
|
@ -1814,13 +1806,6 @@ static zend_persistent_script *opcache_compile_file(zend_file_handle *file_handl
|
||||||
orig_active_op_array = CG(active_op_array);
|
orig_active_op_array = CG(active_op_array);
|
||||||
orig_functions_count = EG(function_table)->nNumUsed;
|
orig_functions_count = EG(function_table)->nNumUsed;
|
||||||
orig_class_count = EG(class_table)->nNumUsed;
|
orig_class_count = EG(class_table)->nNumUsed;
|
||||||
ZVAL_COPY_VALUE(&orig_user_error_handler, &EG(user_error_handler));
|
|
||||||
|
|
||||||
/* Override them with ours */
|
|
||||||
ZVAL_UNDEF(&EG(user_error_handler));
|
|
||||||
if (ZCG(accel_directives).record_warnings) {
|
|
||||||
zend_begin_record_errors();
|
|
||||||
}
|
|
||||||
|
|
||||||
zend_try {
|
zend_try {
|
||||||
orig_compiler_options = CG(compiler_options);
|
orig_compiler_options = CG(compiler_options);
|
||||||
|
@ -1850,13 +1835,12 @@ static zend_persistent_script *opcache_compile_file(zend_file_handle *file_handl
|
||||||
|
|
||||||
/* Restore originals */
|
/* Restore originals */
|
||||||
CG(active_op_array) = orig_active_op_array;
|
CG(active_op_array) = orig_active_op_array;
|
||||||
EG(user_error_handler) = orig_user_error_handler;
|
|
||||||
EG(record_errors) = 0;
|
|
||||||
|
|
||||||
if (!op_array) {
|
if (!op_array) {
|
||||||
/* compilation failed */
|
/* compilation failed */
|
||||||
zend_free_recorded_errors();
|
|
||||||
if (do_bailout) {
|
if (do_bailout) {
|
||||||
|
EG(record_errors) = false;
|
||||||
|
zend_free_recorded_errors();
|
||||||
zend_bailout();
|
zend_bailout();
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -1871,10 +1855,6 @@ static zend_persistent_script *opcache_compile_file(zend_file_handle *file_handl
|
||||||
zend_accel_move_user_functions(CG(function_table), CG(function_table)->nNumUsed - orig_functions_count, &new_persistent_script->script);
|
zend_accel_move_user_functions(CG(function_table), CG(function_table)->nNumUsed - orig_functions_count, &new_persistent_script->script);
|
||||||
zend_accel_move_user_classes(CG(class_table), CG(class_table)->nNumUsed - orig_class_count, &new_persistent_script->script);
|
zend_accel_move_user_classes(CG(class_table), CG(class_table)->nNumUsed - orig_class_count, &new_persistent_script->script);
|
||||||
zend_accel_build_delayed_early_binding_list(new_persistent_script);
|
zend_accel_build_delayed_early_binding_list(new_persistent_script);
|
||||||
new_persistent_script->num_warnings = EG(num_errors);
|
|
||||||
new_persistent_script->warnings = EG(errors);
|
|
||||||
EG(num_errors) = 0;
|
|
||||||
EG(errors) = NULL;
|
|
||||||
|
|
||||||
efree(op_array); /* we have valid persistent_script, so it's safe to free op_array */
|
efree(op_array); /* we have valid persistent_script, so it's safe to free op_array */
|
||||||
|
|
||||||
|
@ -1956,7 +1936,7 @@ static zend_op_array *file_cache_compile_file(zend_file_handle *file_handle, int
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
replay_warnings(persistent_script->num_warnings, persistent_script->warnings);
|
zend_emit_recorded_errors_ex(persistent_script->num_warnings, persistent_script->warnings);
|
||||||
|
|
||||||
if (persistent_script->ping_auto_globals_mask & ~ZCG(auto_globals_mask)) {
|
if (persistent_script->ping_auto_globals_mask & ~ZCG(auto_globals_mask)) {
|
||||||
zend_accel_set_auto_globals(persistent_script->ping_auto_globals_mask & ~ZCG(auto_globals_mask));
|
zend_accel_set_auto_globals(persistent_script->ping_auto_globals_mask & ~ZCG(auto_globals_mask));
|
||||||
|
@ -1965,11 +1945,22 @@ static zend_op_array *file_cache_compile_file(zend_file_handle *file_handle, int
|
||||||
return zend_accel_load_script(persistent_script, 1);
|
return zend_accel_load_script(persistent_script, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
zend_begin_record_errors();
|
||||||
|
|
||||||
persistent_script = opcache_compile_file(file_handle, type, &op_array);
|
persistent_script = opcache_compile_file(file_handle, type, &op_array);
|
||||||
|
|
||||||
if (persistent_script) {
|
if (persistent_script) {
|
||||||
|
if (ZCG(accel_directives).record_warnings) {
|
||||||
|
persistent_script->num_warnings = EG(num_errors);
|
||||||
|
persistent_script->warnings = EG(errors);
|
||||||
|
}
|
||||||
|
|
||||||
from_memory = false;
|
from_memory = false;
|
||||||
persistent_script = cache_script_in_file_cache(persistent_script, &from_memory);
|
persistent_script = cache_script_in_file_cache(persistent_script, &from_memory);
|
||||||
|
|
||||||
|
zend_emit_recorded_errors();
|
||||||
|
zend_free_recorded_errors();
|
||||||
|
|
||||||
return zend_accel_load_script(persistent_script, from_memory);
|
return zend_accel_load_script(persistent_script, from_memory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2168,6 +2159,8 @@ zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type)
|
||||||
return accelerator_orig_compile_file(file_handle, type);
|
return accelerator_orig_compile_file(file_handle, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
zend_begin_record_errors();
|
||||||
|
|
||||||
SHM_PROTECT();
|
SHM_PROTECT();
|
||||||
HANDLE_UNBLOCK_INTERRUPTIONS();
|
HANDLE_UNBLOCK_INTERRUPTIONS();
|
||||||
persistent_script = opcache_compile_file(file_handle, type, &op_array);
|
persistent_script = opcache_compile_file(file_handle, type, &op_array);
|
||||||
|
@ -2179,6 +2172,11 @@ zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type)
|
||||||
*/
|
*/
|
||||||
from_shared_memory = false;
|
from_shared_memory = false;
|
||||||
if (persistent_script) {
|
if (persistent_script) {
|
||||||
|
if (ZCG(accel_directives).record_warnings) {
|
||||||
|
persistent_script->num_warnings = EG(num_errors);
|
||||||
|
persistent_script->warnings = EG(errors);
|
||||||
|
}
|
||||||
|
|
||||||
/* See GH-17246: we disable GC so that user code cannot be executed during the optimizer run. */
|
/* See GH-17246: we disable GC so that user code cannot be executed during the optimizer run. */
|
||||||
bool orig_gc_state = gc_enable(false);
|
bool orig_gc_state = gc_enable(false);
|
||||||
persistent_script = cache_script_in_shared_memory(persistent_script, key, &from_shared_memory);
|
persistent_script = cache_script_in_shared_memory(persistent_script, key, &from_shared_memory);
|
||||||
|
@ -2191,6 +2189,8 @@ zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type)
|
||||||
if (!persistent_script) {
|
if (!persistent_script) {
|
||||||
SHM_PROTECT();
|
SHM_PROTECT();
|
||||||
HANDLE_UNBLOCK_INTERRUPTIONS();
|
HANDLE_UNBLOCK_INTERRUPTIONS();
|
||||||
|
zend_emit_recorded_errors();
|
||||||
|
zend_free_recorded_errors();
|
||||||
return op_array;
|
return op_array;
|
||||||
}
|
}
|
||||||
if (from_shared_memory) {
|
if (from_shared_memory) {
|
||||||
|
@ -2204,6 +2204,9 @@ zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type)
|
||||||
persistent_script->dynamic_members.last_used = ZCG(request_time);
|
persistent_script->dynamic_members.last_used = ZCG(request_time);
|
||||||
SHM_PROTECT();
|
SHM_PROTECT();
|
||||||
HANDLE_UNBLOCK_INTERRUPTIONS();
|
HANDLE_UNBLOCK_INTERRUPTIONS();
|
||||||
|
|
||||||
|
zend_emit_recorded_errors();
|
||||||
|
zend_free_recorded_errors();
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
#ifndef ZEND_WIN32
|
#ifndef ZEND_WIN32
|
||||||
|
@ -2246,7 +2249,7 @@ zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type)
|
||||||
SHM_PROTECT();
|
SHM_PROTECT();
|
||||||
HANDLE_UNBLOCK_INTERRUPTIONS();
|
HANDLE_UNBLOCK_INTERRUPTIONS();
|
||||||
|
|
||||||
replay_warnings(persistent_script->num_warnings, persistent_script->warnings);
|
zend_emit_recorded_errors_ex(persistent_script->num_warnings, persistent_script->warnings);
|
||||||
from_shared_memory = true;
|
from_shared_memory = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2313,7 +2316,7 @@ static zend_class_entry* zend_accel_inheritance_cache_get(zend_class_entry *ce,
|
||||||
entry = zend_accel_inheritance_cache_find(entry, ce, parent, traits_and_interfaces, &needs_autoload);
|
entry = zend_accel_inheritance_cache_find(entry, ce, parent, traits_and_interfaces, &needs_autoload);
|
||||||
if (entry) {
|
if (entry) {
|
||||||
if (!needs_autoload) {
|
if (!needs_autoload) {
|
||||||
replay_warnings(entry->num_warnings, entry->warnings);
|
zend_emit_recorded_errors_ex(entry->num_warnings, entry->warnings);
|
||||||
if (ZCSG(map_ptr_last) > CG(map_ptr_last)) {
|
if (ZCSG(map_ptr_last) > CG(map_ptr_last)) {
|
||||||
zend_map_ptr_extend(ZCSG(map_ptr_last));
|
zend_map_ptr_extend(ZCSG(map_ptr_last));
|
||||||
}
|
}
|
||||||
|
@ -2467,9 +2470,6 @@ static zend_class_entry* zend_accel_inheritance_cache_add(zend_class_entry *ce,
|
||||||
entry->next = proto->inheritance_cache;
|
entry->next = proto->inheritance_cache;
|
||||||
proto->inheritance_cache = entry;
|
proto->inheritance_cache = entry;
|
||||||
|
|
||||||
EG(num_errors) = 0;
|
|
||||||
EG(errors) = NULL;
|
|
||||||
|
|
||||||
ZCSG(map_ptr_last) = CG(map_ptr_last);
|
ZCSG(map_ptr_last) = CG(map_ptr_last);
|
||||||
|
|
||||||
zend_shared_alloc_destroy_xlat_table();
|
zend_shared_alloc_destroy_xlat_table();
|
||||||
|
|
17
ext/opcache/tests/gh17422/001.phpt
Normal file
17
ext/opcache/tests/gh17422/001.phpt
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
--TEST--
|
||||||
|
GH-17422 (OPcache bypasses the user-defined error handler for deprecations)
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
set_error_handler(static function (int $errno, string $errstr, string $errfile, int $errline) {
|
||||||
|
echo "set_error_handler: {$errstr}", PHP_EOL;
|
||||||
|
});
|
||||||
|
|
||||||
|
require __DIR__ . "/warning.inc";
|
||||||
|
|
||||||
|
warning();
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
set_error_handler: "continue" targeting switch is equivalent to "break"
|
||||||
|
OK: warning
|
21
ext/opcache/tests/gh17422/002.phpt
Normal file
21
ext/opcache/tests/gh17422/002.phpt
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
--TEST--
|
||||||
|
GH-17422 (OPcache bypasses the user-defined error handler for deprecations) - Throwing error handler
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
set_error_handler(static function (int $errno, string $errstr, string $errfile, int $errline) {
|
||||||
|
throw new \ErrorException($errstr, 0, $errno, $errfile, $errline);
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
require __DIR__ . "/warning.inc";
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
echo "Caught: ", $e->getMessage(), PHP_EOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
warning();
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
Caught: "continue" targeting switch is equivalent to "break"
|
||||||
|
OK: warning
|
17
ext/opcache/tests/gh17422/003.phpt
Normal file
17
ext/opcache/tests/gh17422/003.phpt
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
--TEST--
|
||||||
|
GH-17422 (OPcache bypasses the user-defined error handler for deprecations) - Fatal Error
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
set_error_handler(static function (int $errno, string $errstr, string $errfile, int $errline) {
|
||||||
|
function fatal_error() {}
|
||||||
|
function fatal_error() {}
|
||||||
|
});
|
||||||
|
|
||||||
|
require __DIR__ . "/warning.inc";
|
||||||
|
|
||||||
|
warning();
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
Fatal error: Cannot redeclare function fatal_error() (previously declared in %s:%d) in %s on line %d
|
22
ext/opcache/tests/gh17422/004.phpt
Normal file
22
ext/opcache/tests/gh17422/004.phpt
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
--TEST--
|
||||||
|
GH-17422 (OPcache bypasses the user-defined error handler for deprecations) - eval
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
set_error_handler(static function (int $errno, string $errstr, string $errfile, int $errline) {
|
||||||
|
eval(
|
||||||
|
<<<'PHP'
|
||||||
|
function warning() {
|
||||||
|
echo "NOK", PHP_EOL;
|
||||||
|
}
|
||||||
|
PHP
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
require __DIR__ . "/warning.inc";
|
||||||
|
|
||||||
|
warning();
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
Fatal error: Cannot redeclare function warning() %s
|
16
ext/opcache/tests/gh17422/005.phpt
Normal file
16
ext/opcache/tests/gh17422/005.phpt
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
--TEST--
|
||||||
|
GH-17422 (OPcache bypasses the user-defined error handler for deprecations) - require
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
set_error_handler(static function (int $errno, string $errstr, string $errfile, int $errline) {
|
||||||
|
require_once __DIR__ . "/dummy.inc";
|
||||||
|
});
|
||||||
|
|
||||||
|
require __DIR__ . "/warning.inc";
|
||||||
|
|
||||||
|
dummy();
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
OK: dummy
|
25
ext/opcache/tests/gh17422/006.phpt
Normal file
25
ext/opcache/tests/gh17422/006.phpt
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
--TEST--
|
||||||
|
GH-17422 (OPcache bypasses the user-defined error handler for deprecations) - File cache
|
||||||
|
--INI--
|
||||||
|
opcache.enable=1
|
||||||
|
opcache.enable_cli=1
|
||||||
|
opcache.file_cache="{TMP}"
|
||||||
|
opcache.file_cache_only=1
|
||||||
|
opcache.record_warnings=1
|
||||||
|
--EXTENSIONS--
|
||||||
|
opcache
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
set_error_handler(static function (int $errno, string $errstr, string $errfile, int $errline) {
|
||||||
|
echo "set_error_handler: {$errstr}", PHP_EOL;
|
||||||
|
});
|
||||||
|
|
||||||
|
require __DIR__ . "/warning.inc";
|
||||||
|
|
||||||
|
warning();
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
set_error_handler: "continue" targeting switch is equivalent to "break"
|
||||||
|
OK: warning
|
18
ext/opcache/tests/gh17422/007.phpt
Normal file
18
ext/opcache/tests/gh17422/007.phpt
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
--TEST--
|
||||||
|
GH-17422 (OPcache bypasses the user-defined error handler for deprecations) - Fatal after warning
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
set_error_handler(static function (int $errno, string $errstr, string $errfile, int $errline) {
|
||||||
|
echo "set_error_handler: {$errstr}", PHP_EOL;
|
||||||
|
});
|
||||||
|
|
||||||
|
require __DIR__ . "/warning-fatal.inc";
|
||||||
|
|
||||||
|
warning();
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
Warning: "continue" targeting switch is equivalent to "break" in %s on line %d
|
||||||
|
|
||||||
|
Fatal error: Cannot redeclare function warning() (previously declared in %s:%d) in %s on line %d
|
14
ext/opcache/tests/gh17422/008.phpt
Normal file
14
ext/opcache/tests/gh17422/008.phpt
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
--TEST--
|
||||||
|
GH-17422 (OPcache bypasses the user-defined error handler for deprecations) - Early binding warning
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
set_error_handler(static function (int $errno, string $errstr, string $errfile, int $errline) {
|
||||||
|
echo "set_error_handler: {$errstr}", PHP_EOL;
|
||||||
|
});
|
||||||
|
|
||||||
|
require __DIR__ . "/early-bind-warning.inc";
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
set_error_handler: Return type of C::getTimezone() should either be compatible with DateTime::getTimezone(): DateTimeZone|false, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice
|
16
ext/opcache/tests/gh17422/009.phpt
Normal file
16
ext/opcache/tests/gh17422/009.phpt
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
--TEST--
|
||||||
|
GH-17422 (OPcache bypasses the user-defined error handler for deprecations) - Early binding error after warning
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
set_error_handler(static function (int $errno, string $errstr, string $errfile, int $errline) {
|
||||||
|
echo "set_error_handler: {$errstr}", PHP_EOL;
|
||||||
|
});
|
||||||
|
|
||||||
|
require __DIR__ . "/early-bind-warning-error.inc";
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
Deprecated: Return type of C::getTimezone() should either be compatible with DateTime::getTimezone(): DateTimeZone|false, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in %s on line %d
|
||||||
|
|
||||||
|
Fatal error: Declaration of C::getTimestamp(C $arg): int must be compatible with DateTime::getTimestamp(): int in %s on line %d
|
14
ext/opcache/tests/gh17422/010.phpt
Normal file
14
ext/opcache/tests/gh17422/010.phpt
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
--TEST--
|
||||||
|
GH-17422 (OPcache bypasses the user-defined error handler for deprecations) - Inheritance warning
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
set_error_handler(static function (int $errno, string $errstr, string $errfile, int $errline) {
|
||||||
|
echo "set_error_handler: {$errstr}", PHP_EOL;
|
||||||
|
});
|
||||||
|
|
||||||
|
require __DIR__ . "/link-warning.inc";
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
set_error_handler: Return type of C::getTimezone() should either be compatible with DateTime::getTimezone(): DateTimeZone|false, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice
|
16
ext/opcache/tests/gh17422/011.phpt
Normal file
16
ext/opcache/tests/gh17422/011.phpt
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
--TEST--
|
||||||
|
GH-17422 (OPcache bypasses the user-defined error handler for deprecations) - Inheritance error after warning
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
set_error_handler(static function (int $errno, string $errstr, string $errfile, int $errline) {
|
||||||
|
echo "set_error_handler: {$errstr}", PHP_EOL;
|
||||||
|
});
|
||||||
|
|
||||||
|
require __DIR__ . "/link-warning-error.inc";
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
Deprecated: Return type of C::getTimezone() should either be compatible with DateTime::getTimezone(): DateTimeZone|false, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in %s on line %d
|
||||||
|
|
||||||
|
Fatal error: Declaration of C::getTimestamp(C $arg): int must be compatible with DateTime::getTimestamp(): int %s on line %d
|
4
ext/opcache/tests/gh17422/dummy.inc
Normal file
4
ext/opcache/tests/gh17422/dummy.inc
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
<?php
|
||||||
|
function dummy() {
|
||||||
|
echo "OK: ", __FUNCTION__, PHP_EOL;
|
||||||
|
}
|
6
ext/opcache/tests/gh17422/early-bind-warning-error.inc
Normal file
6
ext/opcache/tests/gh17422/early-bind-warning-error.inc
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class C extends DateTime {
|
||||||
|
public function getTimezone() {}
|
||||||
|
public function getTimestamp(C $arg): int {}
|
||||||
|
}
|
5
ext/opcache/tests/gh17422/early-bind-warning.inc
Normal file
5
ext/opcache/tests/gh17422/early-bind-warning.inc
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class C extends DateTime {
|
||||||
|
public function getTimezone() {}
|
||||||
|
}
|
8
ext/opcache/tests/gh17422/link-warning-error.inc
Normal file
8
ext/opcache/tests/gh17422/link-warning-error.inc
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
interface DisableEarlyBinding {}
|
||||||
|
|
||||||
|
class C extends DateTime implements DisableEarlyBinding {
|
||||||
|
public function getTimezone() {}
|
||||||
|
public function getTimestamp(C $arg): int {}
|
||||||
|
}
|
7
ext/opcache/tests/gh17422/link-warning.inc
Normal file
7
ext/opcache/tests/gh17422/link-warning.inc
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
interface DisableEarlyBinding {}
|
||||||
|
|
||||||
|
class C extends DateTime implements DisableEarlyBinding {
|
||||||
|
public function getTimezone() {}
|
||||||
|
}
|
9
ext/opcache/tests/gh17422/warning-fatal.inc
Normal file
9
ext/opcache/tests/gh17422/warning-fatal.inc
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<?php
|
||||||
|
function warning() {
|
||||||
|
switch (1) {
|
||||||
|
case 1:
|
||||||
|
echo "OK: ", __FUNCTION__, PHP_EOL;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function warning() {}
|
8
ext/opcache/tests/gh17422/warning.inc
Normal file
8
ext/opcache/tests/gh17422/warning.inc
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?php
|
||||||
|
function warning() {
|
||||||
|
switch (1) {
|
||||||
|
case 1:
|
||||||
|
echo "OK: ", __FUNCTION__, PHP_EOL;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1394,11 +1394,11 @@ static void zend_accel_persist_class_table(HashTable *class_table)
|
||||||
|
|
||||||
zend_error_info **zend_persist_warnings(uint32_t num_warnings, zend_error_info **warnings) {
|
zend_error_info **zend_persist_warnings(uint32_t num_warnings, zend_error_info **warnings) {
|
||||||
if (warnings) {
|
if (warnings) {
|
||||||
warnings = zend_shared_memdup_free(warnings, num_warnings * sizeof(zend_error_info *));
|
warnings = zend_shared_memdup(warnings, num_warnings * sizeof(zend_error_info *));
|
||||||
for (uint32_t i = 0; i < num_warnings; i++) {
|
for (uint32_t i = 0; i < num_warnings; i++) {
|
||||||
warnings[i] = zend_shared_memdup_free(warnings[i], sizeof(zend_error_info));
|
|
||||||
zend_accel_store_string(warnings[i]->filename);
|
zend_accel_store_string(warnings[i]->filename);
|
||||||
zend_accel_store_string(warnings[i]->message);
|
zend_accel_store_string(warnings[i]->message);
|
||||||
|
warnings[i] = zend_shared_memdup(warnings[i], sizeof(zend_error_info));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return warnings;
|
return warnings;
|
||||||
|
|
|
@ -2054,6 +2054,7 @@ function generate_tmp_php_ini()
|
||||||
|
|
||||||
/* Fallback is implied, if filecache is enabled. */
|
/* Fallback is implied, if filecache is enabled. */
|
||||||
INI.WriteLine("opcache.file_cache=" + dir);
|
INI.WriteLine("opcache.file_cache=" + dir);
|
||||||
|
INI.WriteLine("opcache.record_warnings=1");
|
||||||
INI.WriteLine("opcache.enable=1");
|
INI.WriteLine("opcache.enable=1");
|
||||||
INI.WriteLine("opcache.enable_cli=1");
|
INI.WriteLine("opcache.enable_cli=1");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue