mirror of
https://github.com/php/php-src.git
synced 2025-08-15 21:48:51 +02:00
Clear recorded errors before executing shutdown functions
Recorded errors may be attached to the wrong cached script when a fatal error occurs during recording. This happens because the fatal error will cause a bailout, which may prevent the recorded errors from being freed. If an other script is compiled after bailout, or if a class is linked after bailout, the recorded errors will be attached to it. This change fixes this by freeing recorded errors before executing shutdown functions. Fixes GH-8063
This commit is contained in:
parent
15ee285f83
commit
f20e11cbe1
9 changed files with 245 additions and 97 deletions
|
@ -2775,8 +2775,8 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool orig_record_errors = EG(record_errors);
|
bool orig_record_errors = EG(record_errors);
|
||||||
if (ce->ce_flags & ZEND_ACC_IMMUTABLE) {
|
|
||||||
if (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);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
@ -2789,13 +2789,16 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make sure warnings (such as deprecations) thrown during inheritance
|
/* Make sure warnings (such as deprecations) thrown during inheritance
|
||||||
* will be recoreded in the inheritance cache. */
|
* will be recorded in the inheritance cache. */
|
||||||
zend_begin_record_errors();
|
zend_begin_record_errors();
|
||||||
} else {
|
} else {
|
||||||
is_cacheable = 0;
|
is_cacheable = 0;
|
||||||
}
|
}
|
||||||
proto = ce;
|
proto = ce;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
zend_try {
|
||||||
|
if (ce->ce_flags & ZEND_ACC_IMMUTABLE) {
|
||||||
/* Lazy class loading */
|
/* Lazy class loading */
|
||||||
ce = zend_lazy_class_load(ce);
|
ce = zend_lazy_class_load(ce);
|
||||||
zv = zend_hash_find_known_hash(CG(class_table), key);
|
zv = zend_hash_find_known_hash(CG(class_table), key);
|
||||||
|
@ -2870,6 +2873,15 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string
|
||||||
}
|
}
|
||||||
|
|
||||||
zend_build_properties_info_table(ce);
|
zend_build_properties_info_table(ce);
|
||||||
|
} zend_catch {
|
||||||
|
/* Do not leak recorded errors to the next linked class. */
|
||||||
|
if (!orig_record_errors) {
|
||||||
|
EG(record_errors) = false;
|
||||||
|
zend_free_recorded_errors();
|
||||||
|
}
|
||||||
|
zend_bailout();
|
||||||
|
} zend_end_try();
|
||||||
|
|
||||||
EG(record_errors) = orig_record_errors;
|
EG(record_errors) = orig_record_errors;
|
||||||
|
|
||||||
if (!(ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE)) {
|
if (!(ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE)) {
|
||||||
|
@ -3038,6 +3050,7 @@ zend_class_entry *zend_try_early_bind(zend_class_entry *ce, zend_class_entry *pa
|
||||||
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;
|
||||||
|
|
||||||
|
zend_try{
|
||||||
if (is_cacheable) {
|
if (is_cacheable) {
|
||||||
zend_begin_record_errors();
|
zend_begin_record_errors();
|
||||||
}
|
}
|
||||||
|
@ -3054,6 +3067,12 @@ zend_class_entry *zend_try_early_bind(zend_class_entry *ce, zend_class_entry *pa
|
||||||
ce->ce_flags |= ZEND_ACC_LINKED;
|
ce->ce_flags |= ZEND_ACC_LINKED;
|
||||||
|
|
||||||
CG(current_linking_class) = orig_linking_class;
|
CG(current_linking_class) = orig_linking_class;
|
||||||
|
} zend_catch {
|
||||||
|
EG(record_errors) = false;
|
||||||
|
zend_free_recorded_errors();
|
||||||
|
zend_bailout();
|
||||||
|
} zend_end_try();
|
||||||
|
|
||||||
EG(record_errors) = false;
|
EG(record_errors) = false;
|
||||||
|
|
||||||
if (is_cacheable) {
|
if (is_cacheable) {
|
||||||
|
|
31
ext/opcache/tests/gh8063-001.phpt
Normal file
31
ext/opcache/tests/gh8063-001.phpt
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
--TEST--
|
||||||
|
Bug GH-8063 (Opcache breaks autoloading after E_COMPILE_ERROR) 001
|
||||||
|
--INI--
|
||||||
|
opcache.enable=1
|
||||||
|
opcache.enable_cli=1
|
||||||
|
opcache.record_warnings=0
|
||||||
|
--EXTENSIONS--
|
||||||
|
opcache
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
spl_autoload_register(function ($class) {
|
||||||
|
printf("Autoloading %s\n", $class);
|
||||||
|
include __DIR__.DIRECTORY_SEPARATOR.'gh8063'.DIRECTORY_SEPARATOR.$class.'.inc';
|
||||||
|
});
|
||||||
|
|
||||||
|
register_shutdown_function(function () {
|
||||||
|
new Bar();
|
||||||
|
new Baz();
|
||||||
|
print "Finished\n";
|
||||||
|
});
|
||||||
|
|
||||||
|
new BadClass();
|
||||||
|
--EXPECTF--
|
||||||
|
Autoloading BadClass
|
||||||
|
Autoloading Foo
|
||||||
|
|
||||||
|
Fatal error: Declaration of BadClass::dummy() must be compatible with Foo::dummy(): void in %sBadClass.inc on line 5
|
||||||
|
Autoloading Bar
|
||||||
|
Autoloading Baz
|
||||||
|
Finished
|
31
ext/opcache/tests/gh8063-002.phpt
Normal file
31
ext/opcache/tests/gh8063-002.phpt
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
--TEST--
|
||||||
|
Bug GH-8063 (Opcache breaks autoloading after E_COMPILE_ERROR) 002
|
||||||
|
--INI--
|
||||||
|
opcache.enable=1
|
||||||
|
opcache.enable_cli=1
|
||||||
|
opcache.record_warnings=1
|
||||||
|
--EXTENSIONS--
|
||||||
|
opcache
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
spl_autoload_register(function ($class) {
|
||||||
|
printf("Autoloading %s\n", $class);
|
||||||
|
include __DIR__.DIRECTORY_SEPARATOR.'gh8063'.DIRECTORY_SEPARATOR.$class.'.inc';
|
||||||
|
});
|
||||||
|
|
||||||
|
register_shutdown_function(function () {
|
||||||
|
new Bar();
|
||||||
|
new Baz();
|
||||||
|
print "Finished\n";
|
||||||
|
});
|
||||||
|
|
||||||
|
new BadClass();
|
||||||
|
--EXPECTF--
|
||||||
|
Autoloading BadClass
|
||||||
|
Autoloading Foo
|
||||||
|
|
||||||
|
Fatal error: Declaration of BadClass::dummy() must be compatible with Foo::dummy(): void in %sBadClass.inc on line 5
|
||||||
|
Autoloading Bar
|
||||||
|
Autoloading Baz
|
||||||
|
Finished
|
30
ext/opcache/tests/gh8063-003.phpt
Normal file
30
ext/opcache/tests/gh8063-003.phpt
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
--TEST--
|
||||||
|
Bug GH-8063 (Opcache breaks autoloading after E_COMPILE_ERROR) 003
|
||||||
|
--INI--
|
||||||
|
opcache.enable=1
|
||||||
|
opcache.enable_cli=1
|
||||||
|
opcache.record_warnings=0
|
||||||
|
--EXTENSIONS--
|
||||||
|
opcache
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
spl_autoload_register(function ($class) {
|
||||||
|
printf("Autoloading %s\n", $class);
|
||||||
|
include __DIR__.DIRECTORY_SEPARATOR.'gh8063'.DIRECTORY_SEPARATOR.$class.'.inc';
|
||||||
|
});
|
||||||
|
|
||||||
|
register_shutdown_function(function () {
|
||||||
|
new Bar();
|
||||||
|
new Baz();
|
||||||
|
print "Finished\n";
|
||||||
|
});
|
||||||
|
|
||||||
|
new BadClass2();
|
||||||
|
--EXPECTF--
|
||||||
|
Autoloading BadClass2
|
||||||
|
|
||||||
|
Fatal error: Declaration of BadClass2::dummy() must be compatible with Foo2::dummy(): void in %sBadClass2.inc on line %d
|
||||||
|
Autoloading Bar
|
||||||
|
Autoloading Baz
|
||||||
|
Finished
|
8
ext/opcache/tests/gh8063/BadClass.inc
Normal file
8
ext/opcache/tests/gh8063/BadClass.inc
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class BadClass extends Foo
|
||||||
|
{
|
||||||
|
function dummy()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
15
ext/opcache/tests/gh8063/BadClass2.inc
Normal file
15
ext/opcache/tests/gh8063/BadClass2.inc
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class Foo2
|
||||||
|
{
|
||||||
|
function dummy(): void
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BadClass2 extends Foo2
|
||||||
|
{
|
||||||
|
function dummy()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
3
ext/opcache/tests/gh8063/Bar.inc
Normal file
3
ext/opcache/tests/gh8063/Bar.inc
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class Bar {}
|
3
ext/opcache/tests/gh8063/Baz.inc
Normal file
3
ext/opcache/tests/gh8063/Baz.inc
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class Baz {}
|
8
ext/opcache/tests/gh8063/Foo.inc
Normal file
8
ext/opcache/tests/gh8063/Foo.inc
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class Foo
|
||||||
|
{
|
||||||
|
function dummy(): void
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue