Skip to content

Commit 4338079

Browse files
committed
Unify non-opcache behavior
1 parent 6b0cabc commit 4338079

19 files changed

+208
-94
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
--TEST--
2+
Deprecation promoted to exception during inheritance
3+
--SKIPIF--
4+
<?php
5+
if (getenv('SKIP_PRELOAD')) die('skip Error handler not active during preloading');
6+
?>
7+
--FILE--
8+
<?php
9+
10+
set_error_handler(function($code, $message) {
11+
throw new Exception($message);
12+
});
13+
14+
try {
15+
class C extends DateTime {
16+
public function getTimezone() {}
17+
public function getTimestamp() {}
18+
};
19+
} catch (Exception $e) {
20+
printf("%s: %s\n", $e::class, $e->getMessage());
21+
}
22+
23+
var_dump(new C());
24+
25+
?>
26+
--EXPECTF--
27+
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
28+
object(C)#%d (3) {
29+
["date"]=>
30+
string(%d) "%s"
31+
["timezone_type"]=>
32+
int(3)
33+
["timezone"]=>
34+
string(3) "UTC"
35+
}

Zend/zend_inheritance.c

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3543,8 +3543,6 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string
35433543
}
35443544
#endif
35453545

3546-
bool orig_record_errors = EG(record_errors);
3547-
35483546
if (ce->ce_flags & ZEND_ACC_IMMUTABLE && is_cacheable) {
35493547
if (zend_inheritance_cache_get && zend_inheritance_cache_add) {
35503548
zend_class_entry *ret = zend_inheritance_cache_get(ce, parent, traits_and_interfaces);
@@ -3556,16 +3554,21 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string
35563554
Z_CE_P(zv) = ret;
35573555
return ret;
35583556
}
3559-
3560-
/* Make sure warnings (such as deprecations) thrown during inheritance
3561-
* will be recorded in the inheritance cache. */
3562-
zend_begin_record_errors();
35633557
} else {
35643558
is_cacheable = 0;
35653559
}
35663560
proto = ce;
35673561
}
35683562

3563+
/* Delay and record warnings (such as deprecations) thrown during
3564+
* inheritance, so they will be recorded in the inheritance cache.
3565+
* Warnings must be delayed in all cases so that we get a consistent
3566+
* behavior regardless of cacheability. */
3567+
bool orig_record_errors = EG(record_errors);
3568+
if (!orig_record_errors) {
3569+
zend_begin_record_errors();
3570+
}
3571+
35693572
zend_try {
35703573
if (ce->ce_flags & ZEND_ACC_IMMUTABLE) {
35713574
/* Lazy class loading */
@@ -3917,10 +3920,12 @@ ZEND_API zend_class_entry *zend_try_early_bind(zend_class_entry *ce, zend_class_
39173920
orig_linking_class = CG(current_linking_class);
39183921
CG(current_linking_class) = is_cacheable ? ce : NULL;
39193922

3923+
bool orig_record_errors = EG(record_errors);
3924+
39203925
zend_try{
39213926
CG(zend_lineno) = ce->info.user.line_start;
39223927

3923-
if (is_cacheable) {
3928+
if (!orig_record_errors) {
39243929
zend_begin_record_errors();
39253930
}
39263931

@@ -3942,13 +3947,13 @@ ZEND_API zend_class_entry *zend_try_early_bind(zend_class_entry *ce, zend_class_
39423947

39433948
CG(current_linking_class) = orig_linking_class;
39443949
} zend_catch {
3945-
EG(record_errors) = false;
3946-
zend_free_recorded_errors();
3950+
if (!orig_record_errors) {
3951+
EG(record_errors) = false;
3952+
zend_free_recorded_errors();
3953+
}
39473954
zend_bailout();
39483955
} zend_end_try();
39493956

3950-
EG(record_errors) = false;
3951-
39523957
if (is_cacheable) {
39533958
HashTable *ht = (HashTable*)ce->inheritance_cache;
39543959
zend_class_entry *new_ce;
@@ -3966,6 +3971,11 @@ ZEND_API zend_class_entry *zend_try_early_bind(zend_class_entry *ce, zend_class_
39663971
}
39673972
}
39683973

3974+
if (!orig_record_errors) {
3975+
zend_emit_recorded_errors();
3976+
zend_free_recorded_errors();
3977+
}
3978+
39693979
if (ZSTR_HAS_CE_CACHE(ce->name)) {
39703980
ZSTR_SET_CE_CACHE(ce->name, ce);
39713981
}

Zend/zend_language_scanner.l

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -650,7 +650,17 @@ ZEND_API zend_op_array *compile_file(zend_file_handle *file_handle, int type)
650650
}
651651
}
652652
} else {
653+
bool orig_record_errors = EG(record_errors);
654+
if (!orig_record_errors) {
655+
zend_begin_record_errors();
656+
}
657+
653658
op_array = zend_compile(ZEND_USER_FUNCTION);
659+
660+
if (!orig_record_errors) {
661+
zend_emit_recorded_errors();
662+
zend_free_recorded_errors();
663+
}
654664
}
655665

656666
zend_restore_lexical_state(&original_lex_state);

ext/opcache/tests/gh17422/001.phpt

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,8 @@
11
--TEST--
22
GH-17422 (OPcache bypasses the user-defined error handler for deprecations)
3-
--INI--
4-
opcache.enable=1
5-
opcache.enable_cli=1
6-
--EXTENSIONS--
7-
opcache
83
--FILE--
94
<?php
105

11-
require __DIR__ . "/shutdown.inc";
12-
136
set_error_handler(static function (int $errno, string $errstr, string $errfile, int $errline) {
147
echo "set_error_handler: {$errstr}", PHP_EOL;
158
});
@@ -22,11 +15,3 @@ warning();
2215
--EXPECT--
2316
set_error_handler: "continue" targeting switch is equivalent to "break"
2417
OK: warning
25-
array(3) {
26-
[0]=>
27-
string(7) "001.php"
28-
[1]=>
29-
string(12) "shutdown.inc"
30-
[2]=>
31-
string(11) "warning.inc"
32-
}

ext/opcache/tests/gh17422/002.phpt

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,8 @@
11
--TEST--
22
GH-17422 (OPcache bypasses the user-defined error handler for deprecations) - Throwing error handler
3-
--INI--
4-
opcache.enable=1
5-
opcache.enable_cli=1
6-
--EXTENSIONS--
7-
opcache
83
--FILE--
94
<?php
105

11-
require __DIR__ . "/shutdown.inc";
12-
136
set_error_handler(static function (int $errno, string $errstr, string $errfile, int $errline) {
147
throw new \ErrorException($errstr, 0, $errno, $errfile, $errline);
158
});
@@ -26,11 +19,3 @@ warning();
2619
--EXPECT--
2720
Caught: "continue" targeting switch is equivalent to "break"
2821
OK: warning
29-
array(3) {
30-
[0]=>
31-
string(7) "002.php"
32-
[1]=>
33-
string(12) "shutdown.inc"
34-
[2]=>
35-
string(11) "warning.inc"
36-
}

ext/opcache/tests/gh17422/003.phpt

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,11 @@
11
--TEST--
22
GH-17422 (OPcache bypasses the user-defined error handler for deprecations) - Fatal Error
3-
--INI--
4-
opcache.enable=1
5-
opcache.enable_cli=1
6-
memory_limit=2M
7-
--EXTENSIONS--
8-
opcache
93
--FILE--
104
<?php
115

12-
require __DIR__ . "/shutdown.inc";
13-
146
set_error_handler(static function (int $errno, string $errstr, string $errfile, int $errline) {
15-
str_repeat('x', 1024 * 1024 * 1024);
7+
function fatal_error() {}
8+
function fatal_error() {}
169
});
1710

1811
require __DIR__ . "/warning.inc";
@@ -21,12 +14,4 @@ warning();
2114

2215
?>
2316
--EXPECTF--
24-
Fatal error: Allowed memory size of 2097152 bytes exhausted %s on line 6
25-
array(3) {
26-
[0]=>
27-
string(7) "003.php"
28-
[1]=>
29-
string(12) "shutdown.inc"
30-
[2]=>
31-
string(11) "warning.inc"
32-
}
17+
Fatal error: Cannot redeclare function fatal_error() (previously declared in %s:%d) in %s on line %d

ext/opcache/tests/gh17422/004.phpt

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,8 @@
11
--TEST--
22
GH-17422 (OPcache bypasses the user-defined error handler for deprecations) - eval
3-
--INI--
4-
opcache.enable=1
5-
opcache.enable_cli=1
6-
memory_limit=2M
7-
--EXTENSIONS--
8-
opcache
93
--FILE--
104
<?php
115

12-
require __DIR__ . "/shutdown.inc";
13-
146
set_error_handler(static function (int $errno, string $errstr, string $errfile, int $errline) {
157
eval(
168
<<<'PHP'
@@ -27,12 +19,4 @@ warning();
2719

2820
?>
2921
--EXPECTF--
30-
Fatal error: Cannot redeclare %Swarning() (previously declared in %s(8) : eval()'d code:1) in %swarning.inc on line 2
31-
array(3) {
32-
[0]=>
33-
string(7) "004.php"
34-
[1]=>
35-
string(12) "shutdown.inc"
36-
[2]=>
37-
string(11) "warning.inc"
38-
}
22+
Fatal error: Cannot redeclare function warning() %s

ext/opcache/tests/gh17422/005.phpt

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,8 @@
11
--TEST--
22
GH-17422 (OPcache bypasses the user-defined error handler for deprecations) - require
3-
--INI--
4-
opcache.enable=1
5-
opcache.enable_cli=1
6-
memory_limit=2M
7-
--EXTENSIONS--
8-
opcache
93
--FILE--
104
<?php
115

12-
require __DIR__ . "/shutdown.inc";
13-
146
set_error_handler(static function (int $errno, string $errstr, string $errfile, int $errline) {
157
require_once __DIR__ . "/dummy.inc";
168
});
@@ -22,13 +14,3 @@ dummy();
2214
?>
2315
--EXPECT--
2416
OK: dummy
25-
array(4) {
26-
[0]=>
27-
string(7) "005.php"
28-
[1]=>
29-
string(9) "dummy.inc"
30-
[2]=>
31-
string(12) "shutdown.inc"
32-
[3]=>
33-
string(11) "warning.inc"
34-
}

ext/opcache/tests/gh17422/006.phpt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
--TEST--
2+
GH-17422 (OPcache bypasses the user-defined error handler for deprecations) - File cache
3+
--INI--
4+
opcache.enable=1
5+
opcache.enable_cli=1
6+
opcache.file_cache={TMP}
7+
opcache.file_cache_only=1
8+
opcache.record_warnings=1
9+
--EXTENSIONS--
10+
opcache
11+
--FILE--
12+
<?php
13+
14+
set_error_handler(static function (int $errno, string $errstr, string $errfile, int $errline) {
15+
echo "set_error_handler: {$errstr}", PHP_EOL;
16+
});
17+
18+
require __DIR__ . "/warning.inc";
19+
20+
warning();
21+
22+
?>
23+
--EXPECT--
24+
set_error_handler: "continue" targeting switch is equivalent to "break"
25+
OK: warning

ext/opcache/tests/gh17422/007.phpt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--TEST--
2+
GH-17422 (OPcache bypasses the user-defined error handler for deprecations) - Fatal after warning
3+
--FILE--
4+
<?php
5+
6+
set_error_handler(static function (int $errno, string $errstr, string $errfile, int $errline) {
7+
echo "set_error_handler: {$errstr}", PHP_EOL;
8+
});
9+
10+
require __DIR__ . "/warning-fatal.inc";
11+
12+
warning();
13+
14+
?>
15+
--EXPECTF--
16+
Warning: "continue" targeting switch is equivalent to "break" in %s on line %d
17+
18+
Fatal error: Cannot redeclare function warning() (previously declared in %s:%d) in %s on line %d

ext/opcache/tests/gh17422/008.phpt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
--TEST--
2+
GH-17422 (OPcache bypasses the user-defined error handler for deprecations) - Early binding warning
3+
--FILE--
4+
<?php
5+
6+
set_error_handler(static function (int $errno, string $errstr, string $errfile, int $errline) {
7+
echo "set_error_handler: {$errstr}", PHP_EOL;
8+
});
9+
10+
require __DIR__ . "/early-bind-warning.inc";
11+
12+
?>
13+
--EXPECTF--
14+
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

ext/opcache/tests/gh17422/009.phpt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
--TEST--
2+
GH-17422 (OPcache bypasses the user-defined error handler for deprecations) - Early binding error after warning
3+
--FILE--
4+
<?php
5+
6+
set_error_handler(static function (int $errno, string $errstr, string $errfile, int $errline) {
7+
echo "set_error_handler: {$errstr}", PHP_EOL;
8+
});
9+
10+
require __DIR__ . "/early-bind-warning-error.inc";
11+
12+
?>
13+
--EXPECTF--
14+
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
15+
16+
Fatal error: Declaration of C::getTimestamp(C $arg): int must be compatible with DateTime::getTimestamp(): int in %s on line %d

ext/opcache/tests/gh17422/010.phpt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
--TEST--
2+
GH-17422 (OPcache bypasses the user-defined error handler for deprecations) - Inheritance warning
3+
--FILE--
4+
<?php
5+
6+
set_error_handler(static function (int $errno, string $errstr, string $errfile, int $errline) {
7+
echo "set_error_handler: {$errstr}", PHP_EOL;
8+
});
9+
10+
require __DIR__ . "/link-warning.inc";
11+
12+
?>
13+
--EXPECTF--
14+
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

ext/opcache/tests/gh17422/011.phpt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
--TEST--
2+
GH-17422 (OPcache bypasses the user-defined error handler for deprecations) - Inheritance error after warning
3+
--FILE--
4+
<?php
5+
6+
set_error_handler(static function (int $errno, string $errstr, string $errfile, int $errline) {
7+
echo "set_error_handler: {$errstr}", PHP_EOL;
8+
});
9+
10+
require __DIR__ . "/link-warning-error.inc";
11+
12+
?>
13+
--EXPECTF--
14+
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
15+
16+
Fatal error: Declaration of C::getTimestamp(C $arg): int must be compatible with DateTime::getTimestamp(): int %s on line %d

0 commit comments

Comments
 (0)