diff --git a/Zend/Optimizer/zend_inference.c b/Zend/Optimizer/zend_inference.c index 05d33d3d75fb..62eb212eec78 100644 --- a/Zend/Optimizer/zend_inference.c +++ b/Zend/Optimizer/zend_inference.c @@ -4951,7 +4951,7 @@ ZEND_API bool zend_may_throw_ex(const zend_op *opline, const zend_ssa_op *ssa_op } } else if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) { if ((t1 & MAY_BE_RC1) - && (t1 & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY))) { + && (t1 & (MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY))) { switch (opline->opcode) { case ZEND_CASE: case ZEND_CASE_STRICT: @@ -4972,7 +4972,7 @@ ZEND_API bool zend_may_throw_ex(const zend_op *opline, const zend_ssa_op *ssa_op case ZEND_MAKE_REF: break; default: - /* destructor may be called */ + /* resource destructor may be called */ return 1; } } @@ -4992,14 +4992,14 @@ ZEND_API bool zend_may_throw_ex(const zend_op *opline, const zend_ssa_op *ssa_op } } else if (opline->op2_type & (IS_TMP_VAR|IS_VAR)) { if ((t2 & MAY_BE_RC1) - && (t2 & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY))) { + && (t2 & (MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY))) { switch (opline->opcode) { case ZEND_ASSIGN: case ZEND_FE_FETCH_R: case ZEND_FE_FETCH_RW: break; default: - /* destructor may be called */ + /* resource destructor may be called */ return 1; } } @@ -5178,11 +5178,11 @@ ZEND_API bool zend_may_throw_ex(const zend_op *opline, const zend_ssa_op *ssa_op } ZEND_FALLTHROUGH; case ZEND_UNSET_VAR: - return (t1 & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY)); + return (t1 & (MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY)); case ZEND_BIND_STATIC: case ZEND_BIND_INIT_STATIC_OR_JMP: - if (t1 & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY)) { - /* Destructor may throw. */ + if (t1 & (MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY)) { + /* resource destructor may throw. */ return 1; } return 0; @@ -5192,7 +5192,7 @@ ZEND_API bool zend_may_throw_ex(const zend_op *opline, const zend_ssa_op *ssa_op return 1; } } - if (t1 & (MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY|MAY_BE_ARRAY_OF_REF)) { + if (t1 & (MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY|MAY_BE_ARRAY_OF_REF)) { return 1; } return (t1 & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_TRUE|MAY_BE_FALSE|MAY_BE_STRING|MAY_BE_LONG|MAY_BE_DOUBLE)) || opline->op2_type == IS_UNUSED || @@ -5317,7 +5317,7 @@ ZEND_API bool zend_may_throw_ex(const zend_op *opline, const zend_ssa_op *ssa_op } if (opline->op2_type == IS_CV && (t2 & MAY_BE_RC1) - && (t2 & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY))) { + && (t2 & (MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY))) { return 1; } return 0; diff --git a/Zend/Optimizer/zend_inference.h b/Zend/Optimizer/zend_inference.h index e6b4207c7494..71785c2238ea 100644 --- a/Zend/Optimizer/zend_inference.h +++ b/Zend/Optimizer/zend_inference.h @@ -34,6 +34,10 @@ (MAY_BE_OBJECT|MAY_BE_RESOURCE \ |MAY_BE_ARRAY_OF_ARRAY|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE) +#define MAY_HAVE_UNDELAYED_DTOR \ + (MAY_BE_RESOURCE \ + |MAY_BE_ARRAY_OF_ARRAY|MAY_BE_ARRAY_OF_RESOURCE) + #define DEFINE_SSA_OP_HAS_RANGE(opN) \ static zend_always_inline bool _ssa_##opN##_has_range(const zend_op_array *op_array, const zend_ssa *ssa, const zend_op *opline, const zend_ssa_op *ssa_op) \ { \ diff --git a/Zend/tests/ArrayAccess/bug41209.phpt b/Zend/tests/ArrayAccess/bug41209.phpt index 1a7ee8aa515c..956d77f6fed9 100644 --- a/Zend/tests/ArrayAccess/bug41209.phpt +++ b/Zend/tests/ArrayAccess/bug41209.phpt @@ -7,7 +7,7 @@ class env { public function __construct() { - set_error_handler(array(__CLASS__, 'errorHandler')); + set_error_handler(array(__CLASS__, 'errorHandler'), delay: false); } public static function errorHandler($errno, $errstr, $errfile, $errline) diff --git a/Zend/tests/attributes/deprecated/class_constants/deprecated_constant_as_message_002.phpt b/Zend/tests/attributes/deprecated/class_constants/deprecated_constant_as_message_002.phpt index ab84d4724226..ba6103145957 100644 --- a/Zend/tests/attributes/deprecated/class_constants/deprecated_constant_as_message_002.phpt +++ b/Zend/tests/attributes/deprecated/class_constants/deprecated_constant_as_message_002.phpt @@ -5,7 +5,7 @@ set_error_handler(function (int $errno, string $errstr, ?string $errfile = null, ?int $errline = null) { throw new \ErrorException($errstr, 0, $errno, $errfile, $errline); -}); +}, delay: false); class Clazz { #[\Deprecated(self::TEST)] diff --git a/Zend/tests/attributes/deprecated/constants/deprecated_constant_as_message_002.phpt b/Zend/tests/attributes/deprecated/constants/deprecated_constant_as_message_002.phpt index f749293d8fac..5fb3359c138e 100644 --- a/Zend/tests/attributes/deprecated/constants/deprecated_constant_as_message_002.phpt +++ b/Zend/tests/attributes/deprecated/constants/deprecated_constant_as_message_002.phpt @@ -5,7 +5,7 @@ set_error_handler(function (int $errno, string $errstr, ?string $errfile = null, ?int $errline = null) { throw new \ErrorException($errstr, 0, $errno, $errfile, $errline); -}); +}, delay: false); #[\Deprecated(TEST)] const TEST = "from itself"; diff --git a/Zend/tests/attributes/deprecated/functions/throwing_error_handler_001.phpt b/Zend/tests/attributes/deprecated/functions/throwing_error_handler_001.phpt index af816aea6c4b..3e151479e599 100644 --- a/Zend/tests/attributes/deprecated/functions/throwing_error_handler_001.phpt +++ b/Zend/tests/attributes/deprecated/functions/throwing_error_handler_001.phpt @@ -5,7 +5,7 @@ set_error_handler(function (int $errno, string $errstr, ?string $errfile = null, ?int $errline = null) { throw new \ErrorException($errstr, 0, $errno, $errfile, $errline); -}); +}, delay: false); #[\Deprecated("convert to exception")] function test() { @@ -76,7 +76,7 @@ class Destructor { } try { - new Destructor(); + (function () { new Destructor(); })(); } catch (ErrorException $e) { echo "Caught: ", $e->getMessage(), PHP_EOL; } diff --git a/Zend/tests/backtrace/debug_backtrace_with_include_and_this.phpt b/Zend/tests/backtrace/debug_backtrace_with_include_and_this.phpt index 49796a9b9103..5a8474d14963 100644 --- a/Zend/tests/backtrace/debug_backtrace_with_include_and_this.phpt +++ b/Zend/tests/backtrace/debug_backtrace_with_include_and_this.phpt @@ -30,8 +30,8 @@ try { } ?> --EXPECTF-- -ERR#2: include(class://non.existent.Class): Failed to open stream: "CLWrapper::stream_open" call failed @ include -ERR#2: include(): Failed opening 'class://non.existent.Class' for inclusion (include_path='%s') @ include +ERR#2: include(class://non.existent.Class): Failed to open stream: "CLWrapper::stream_open" call failed @ __construct +ERR#2: include(): Failed opening 'class://non.existent.Class' for inclusion (include_path='.:') @ __construct Fatal error: Uncaught Exception: Failed loading class://non.existent.Class in %s Stack trace: diff --git a/Zend/tests/bind_static_exception.phpt b/Zend/tests/bind_static_exception.phpt index c374130aaecf..a0dc1ed6db3f 100644 --- a/Zend/tests/bind_static_exception.phpt +++ b/Zend/tests/bind_static_exception.phpt @@ -8,8 +8,10 @@ class Test { } } try { - $new = new Test; - static $new; + (function () { + $new = new Test; + static $new; + })(); } catch (Exception $e) { echo $e->getMessage(), "\n"; } diff --git a/Zend/tests/bitwise_not_precision_exception.phpt b/Zend/tests/bitwise_not_precision_exception.phpt index e28bf8f4e17b..044b3362d9c4 100644 --- a/Zend/tests/bitwise_not_precision_exception.phpt +++ b/Zend/tests/bitwise_not_precision_exception.phpt @@ -4,7 +4,7 @@ Promoting float precision warning to exception in bitwise_not --EXPECTF-- #0 %s(%d): userErrorHandler(2, 'Undefined varia...', '%s', %d) -#1 %s(%d): GenerateError1('Test1') -#2 %s(%d): GenerateError2('Test2') +#1 %s(%d): GenerateError2('Test2') diff --git a/Zend/tests/bug35017.phpt b/Zend/tests/bug35017.phpt index 0b9e9a95e2c4..760de4a551dd 100644 --- a/Zend/tests/bug35017.phpt +++ b/Zend/tests/bug35017.phpt @@ -2,7 +2,7 @@ Bug #35017 (Exception thrown in error handler may cause unexpected behavior) --FILE-- obj = $this; + (function (){})(); echo "before call $method\n"; print_r($this); diff --git a/Zend/tests/bug49893.phpt b/Zend/tests/bug49893.phpt index 0832b0b0ef4c..ff0b740a68bb 100644 --- a/Zend/tests/bug49893.phpt +++ b/Zend/tests/bug49893.phpt @@ -18,8 +18,11 @@ class B { throw new Exception("1"); } } -try { +function f() { $b = new B(); +} +try { + f(); } catch(Exception $e) { echo $e->getMessage() . "\n"; } diff --git a/Zend/tests/bug52041.phpt b/Zend/tests/bug52041.phpt index 7debab3f8beb..83fbf2f26fd9 100644 --- a/Zend/tests/bug52041.phpt +++ b/Zend/tests/bug52041.phpt @@ -1,5 +1,7 @@ --TEST-- Bug #52041 (Memory leak when writing on uninitialized variable returned from function) +--INI-- +opcache.jit=0 --FILE-- diff --git a/Zend/tests/bug61767.phpt b/Zend/tests/bug61767.phpt index a12c5716e9ae..6ee7c0a8843c 100644 --- a/Zend/tests/bug61767.phpt +++ b/Zend/tests/bug61767.phpt @@ -5,7 +5,7 @@ Bug #61767 (Shutdown functions not called in certain error situation) set_error_handler(function($code, $msg, $file = null, $line = null) { echo "Error handler called ($msg)\n"; throw new \ErrorException($msg, $code, 0, $file, $line); -}); +}, delay: false); register_shutdown_function(function(){ echo "Shutting down\n"; diff --git a/Zend/tests/bug63206.phpt b/Zend/tests/bug63206.phpt index 6aba55eca1ba..8921a8685f9b 100644 --- a/Zend/tests/bug63206.phpt +++ b/Zend/tests/bug63206.phpt @@ -14,13 +14,19 @@ set_error_handler(function() { echo 'Internal handler' . PHP_EOL; }); + global $tmp; $triggerInternalNotice++; // warnings while handling the error should go into internal handler + fwrite($tmp, "."); // handle errors restore_error_handler(); }); +$tmp = tmpfile(); + $triggerNotice1++; +fwrite($tmp, "."); // handle errors $triggerNotice2++; +fwrite($tmp, "."); // handle errors ?> --EXPECT-- Second handler diff --git a/Zend/tests/bug70662.phpt b/Zend/tests/bug70662.phpt index ab540c9d16e5..2bda8141bab4 100644 --- a/Zend/tests/bug70662.phpt +++ b/Zend/tests/bug70662.phpt @@ -14,5 +14,5 @@ var_dump($a); --EXPECT-- array(1) { ["b"]=> - int(2) + int(1) } diff --git a/Zend/tests/bug70785.phpt b/Zend/tests/bug70785.phpt index 05b1b6afa0a0..363cea1deb63 100644 --- a/Zend/tests/bug70785.phpt +++ b/Zend/tests/bug70785.phpt @@ -5,7 +5,7 @@ Bug #70785 (Infinite loop due to exception during identical comparison) set_error_handler(function($no, $msg) { throw new Exception($msg); -}); +}, delay: false); try { if ($a === null) { // ZEND_VM_SMART_BRANCH diff --git a/Zend/tests/bug72101.phpt b/Zend/tests/bug72101.phpt index 6362a7ccb303..51c67071519e 100644 --- a/Zend/tests/bug72101.phpt +++ b/Zend/tests/bug72101.phpt @@ -63,7 +63,7 @@ class Mock_MethodCallbackByReference_7b180d26 extends MethodCallbackByReference set_error_handler(function() { // var_dump(func_get_args()); DoesNotExists::$nope = true; -}, E_ALL); +}, E_ALL, delay: false); $foo = new Mock_MethodCallbackByReference_7b180d26(); $InvMocker = new PHPUnit_Framework_MockObject_InvocationMocker(); diff --git a/Zend/tests/bug74164.phpt b/Zend/tests/bug74164.phpt index ef56f10225fd..e4de55253161 100644 --- a/Zend/tests/bug74164.phpt +++ b/Zend/tests/bug74164.phpt @@ -7,14 +7,13 @@ namespace Foo; set_error_handler(function ($type, $msg) { throw new \Exception($msg); -}); +}, delay: false); call_user_func(function (array &$ref) {var_dump("xxx");}, 'not_an_array_variable'); ?> --EXPECTF-- Fatal error: Uncaught Exception: {closure:%s:%d}(): Argument #1 ($ref) must be passed by reference, value given in %s:%d Stack trace: -#0 [internal function]: {closure:%s:%d}(2, '%s', '%s', 9) -#1 %sbug74164.php(%d): call_user_func(%s) -#2 {main} +#0 %s(%d): {closure:%s:%d}(2, '{closure:%s', '%s', 9) +#1 {main} thrown in %sbug74164.php on line %d diff --git a/Zend/tests/bug76534.phpt b/Zend/tests/bug76534.phpt index c9c897110d6c..d39714b7a62d 100644 --- a/Zend/tests/bug76534.phpt +++ b/Zend/tests/bug76534.phpt @@ -4,7 +4,7 @@ Bug #76534 (PHP hangs on 'illegal string offset on string references with an err --EXPECT-- -int(0) -int(0) -int(0) -int(0) +array(1) { + [0]=> + string(3) "xyz" +} +array(1) { + [0]=> + array(1) { + [0]=> + array(1) { + [0]=> + string(3) "xyz" + } + } +} +array(1) { + ["foo"]=> + string(3) "xyz" +} +array(1) { + ["foo"]=> + array(1) { + ["bar"]=> + array(1) { + ["baz"]=> + string(3) "xyz" + } + } +} diff --git a/Zend/tests/bug79599.phpt b/Zend/tests/bug79599.phpt index 57e5332431f5..1cca9d84a61b 100644 --- a/Zend/tests/bug79599.phpt +++ b/Zend/tests/bug79599.phpt @@ -4,7 +4,7 @@ Bug #79599 (coredump in set_error_handler) --EXPECT-- -NULL -NULL -NULL +array(1) { + [""]=> + string(1) "x" +} +array(1) { + [""]=> + string(1) "x" +} +array(1) { + [""]=> + array(1) { + [""]=> + string(1) "x" + } +} diff --git a/Zend/tests/bug79793.phpt b/Zend/tests/bug79793.phpt index 5491a2669ed9..4af55ffd07cb 100644 --- a/Zend/tests/bug79793.phpt +++ b/Zend/tests/bug79793.phpt @@ -18,15 +18,15 @@ var_dump($ary); ?> --EXPECT-- -Undefined array key "foobar" array(1) { ["foobar"]=> int(1) } -Undefined array key "foobarbaz" +Undefined array key "foobar" array(2) { ["foobar"]=> int(1) ["foobarbaz"]=> int(1) } +Undefined array key "foobarbaz" diff --git a/Zend/tests/closures/closure_031.phpt b/Zend/tests/closures/closure_031.phpt index 19f3dc6e3212..7f9d3780e4ff 100644 --- a/Zend/tests/closures/closure_031.phpt +++ b/Zend/tests/closures/closure_031.phpt @@ -15,5 +15,5 @@ try { } ?> --EXPECT-- -Warning: Undefined property: Closure::$a NULL +Warning: Undefined property: Closure::$a diff --git a/Zend/tests/coalesce/assign_coalesce_002.phpt b/Zend/tests/coalesce/assign_coalesce_002.phpt index 0b2c5374bc7a..c6297fd623d1 100644 --- a/Zend/tests/coalesce/assign_coalesce_002.phpt +++ b/Zend/tests/coalesce/assign_coalesce_002.phpt @@ -46,6 +46,7 @@ class Dtor { $ary = new AA; try { $ary[new Dtor][id($foo)] ??= $bar; + (function () {})(); } catch (Exception $e) { echo $e->getMessage(), "\n"; } diff --git a/Zend/tests/compound_assign_failure.phpt b/Zend/tests/compound_assign_failure.phpt index 0dc9af85f253..2e4db29950d5 100644 --- a/Zend/tests/compound_assign_failure.phpt +++ b/Zend/tests/compound_assign_failure.phpt @@ -20,7 +20,7 @@ try { $a <<= -1; } catch (Error $e) { var_dump($a); } -set_error_handler(function($type, $msg) { throw new Exception($msg); }); +set_error_handler(function($type, $msg) { throw new Exception($msg); }, delay: false); try { $a = []; diff --git a/Zend/tests/concat/bug81705.phpt b/Zend/tests/concat/bug81705.phpt index 1c00b1c77d4b..ba3d956f6bd2 100644 --- a/Zend/tests/concat/bug81705.phpt +++ b/Zend/tests/concat/bug81705.phpt @@ -15,5 +15,5 @@ $my_var .= $GLOBALS["arr"]; var_dump($my_var); ?> --EXPECT-- +string(6) "aArray" error -string(6) "aArray" \ No newline at end of file diff --git a/Zend/tests/constants/gh18463-class-constant.phpt b/Zend/tests/constants/gh18463-class-constant.phpt index 2af977205dc8..40b96e8f7231 100644 --- a/Zend/tests/constants/gh18463-class-constant.phpt +++ b/Zend/tests/constants/gh18463-class-constant.phpt @@ -15,6 +15,7 @@ set_error_handler('handler'); var_dump(_ZendTestClass::ZEND_TEST_DEPRECATED); ?> --EXPECTF-- +int(42) Constant _ZendTestClass::ZEND_TEST_DEPRECATED is deprecated in %s on line %d Fatal error: Cannot use "string" as a class name as it is reserved in %s(%d) : eval()'d code on line %d diff --git a/Zend/tests/debug_info/recursion_return_null.phpt b/Zend/tests/debug_info/recursion_return_null.phpt index b6ca9c824cb7..9fb525923d7f 100644 --- a/Zend/tests/debug_info/recursion_return_null.phpt +++ b/Zend/tests/debug_info/recursion_return_null.phpt @@ -22,10 +22,10 @@ var_dump($f); ?> --EXPECTF-- +object(Foo)#%d (0) { +} in handler Deprecated: Returning null from Foo::__debugInfo() is deprecated, return an empty array instead in %s on line %d object(Foo)#3 (0) { } -object(Foo)#2 (0) { -} diff --git a/Zend/tests/delayed_error_001.phpt b/Zend/tests/delayed_error_001.phpt new file mode 100644 index 000000000000..668eb0da68f1 --- /dev/null +++ b/Zend/tests/delayed_error_001.phpt @@ -0,0 +1,43 @@ +--TEST-- +Delayed error 001 +--INI-- +opcache.jit=0 +--FILE-- + +--EXPECTF-- +Warning: Undefined variable $array in %s on line %d + +Warning: Undefined array key 0 in %s on line %d + +Warning: Undefined array key 1 in %s on line %d + +Warning: Undefined array key 2 in %s on line %d + +Warning: Undefined array key 3 in %s on line %d + +Warning: Undefined array key 3 in %s on line %d + +Warning: Undefined array key 4 in %s on line %d + +Warning: Decrement on type null has no effect, this will change in the next major version of PHP in %s on line %d + +Warning: Undefined array key 5 in %s on line %d + +Warning: Undefined array key 6 in %s on line %d + +Warning: Undefined array key 7 in %s on line %d + +Warning: Undefined array key 8 in %s on line %d + +Warning: Decrement on type null has no effect, this will change in the next major version of PHP in %s on line %d + +Warning: Undefined array key 9 in %s on line %d + +Warning: Undefined array key 10 in %s on line %d diff --git a/Zend/tests/delayed_error_002.phpt b/Zend/tests/delayed_error_002.phpt new file mode 100644 index 000000000000..2b26907d1c30 --- /dev/null +++ b/Zend/tests/delayed_error_002.phpt @@ -0,0 +1,19 @@ +--TEST-- +Delayed errors: Exception thrown while delayed errors are pending +--FILE-- +getMessage(), "\n"; +} + +?> +--EXPECT-- +Warning: A non-numeric value encountered +TypeError: Unsupported operand types: string + array diff --git a/Zend/tests/delayed_error_003.phpt b/Zend/tests/delayed_error_003.phpt new file mode 100644 index 000000000000..2c7a867e1b6d --- /dev/null +++ b/Zend/tests/delayed_error_003.phpt @@ -0,0 +1,24 @@ +--TEST-- +Delayed errors: Exception thrown while delayed errors are pending, handler throws +--FILE-- +getMessage(), "\n"; + $e = $e->getPrevious(); + $prefix = 'Previous: '; + } while ($e !== null); +} + +?> +--EXPECT-- +ErrorException: Warning: A non-numeric value encountered +Previous: TypeError: Unsupported operand types: string + array diff --git a/Zend/tests/delayed_error_004.phpt b/Zend/tests/delayed_error_004.phpt new file mode 100644 index 000000000000..9f498a099a13 --- /dev/null +++ b/Zend/tests/delayed_error_004.phpt @@ -0,0 +1,23 @@ +--TEST-- +Delayed errors: The first error promoted to exception takes precedence +--FILE-- +getMessage()); +} + +?> +--EXPECT-- +ErrorException: Warning: 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 diff --git a/Zend/tests/delayed_error_005.phpt b/Zend/tests/delayed_error_005.phpt new file mode 100644 index 000000000000..c4282b6ae3d7 --- /dev/null +++ b/Zend/tests/delayed_error_005.phpt @@ -0,0 +1,29 @@ +--TEST-- +Delayed errors: Promoted errors take precedence +--FILE-- +getMessage(), "\n"; +} + +?> +--EXPECT-- +ErrorException: Warning: Use of "static" in callables is deprecated diff --git a/Zend/tests/delayed_error_006.phpt b/Zend/tests/delayed_error_006.phpt new file mode 100644 index 000000000000..ec66c1da5508 --- /dev/null +++ b/Zend/tests/delayed_error_006.phpt @@ -0,0 +1,17 @@ +--TEST-- +Delayed errors: Promoted errors take precedence +--FILE-- + +==DONE== +--EXPECT-- +==DONE== diff --git a/Zend/tests/delayed_error_007.inc b/Zend/tests/delayed_error_007.inc new file mode 100644 index 000000000000..b24b583fc27b --- /dev/null +++ b/Zend/tests/delayed_error_007.inc @@ -0,0 +1,2 @@ +getMessage(), "\n"; +} + +class C { + function f($name) { + new Dtor(); + $this->$name(); + } + function g($name) { + $this->$name(); + } +} + +try { + echo "INIT_METHOD_CALL\n"; + $c = new C(); + $c->f(zend_test_rc_string('g')); +} catch (Exception $e) { + echo $e::class, ": ", $e->getMessage(), "\n"; +} + +class D { + static function f($cname, $fname) { + new Dtor(); + $cname::$fname(); + } + static function g($cname, $fname) { + $cname::$fname(); + } +} + +try { + echo "INIT_STATIC_METHOD_CALL\n"; + D::f(zend_test_rc_string('D'), zend_test_rc_string('g')); +} catch (Exception $e) { + echo $e::class, ": ", $e->getMessage(), "\n"; +} + +function uf($f) { + new Dtor(); + call_user_func($f); +} + +function ug($f) { + call_user_func($f, $f); +} + +try { + echo "INIT_USER_CALL\n"; + uf(zend_test_rc_string('ug')); +} catch (Exception $e) { + echo $e::class, ": ", $e->getMessage(), "\n"; +} + +class E { + function __construct() { + new E(); + } +} + +function e() { + new Dtor(); + new E(); +} + +try { + echo "NEW\n"; + e(); +} catch (Exception $e) { + echo $e::class, ": ", $e->getMessage(), "\n"; +} + +function i() { + new Dtor(); + include __DIR__ . '/delayed_error_007.inc'; +} + +try { + echo "INCLUDE_OR_EVAL\n"; + i(); +} catch (Exception $e) { + echo $e::class, ": ", $e->getMessage(), "\n"; +} + +function d($f) { + new Dtor(); + $f(); +} + +function df($f) { + $f($f); +} + +try { + echo "INIT_DYNAMIC_CALL\n"; + d(zend_test_rc_string('df')); +} catch (Exception $e) { + echo $e::class, ": ", $e->getMessage(), "\n"; +} + +?> +==DONE== +--EXPECT-- +INIT_FCALL +Exception: Dtor::__destruct +INIT_METHOD_CALL +Exception: Dtor::__destruct +INIT_STATIC_METHOD_CALL +Exception: Dtor::__destruct +INIT_USER_CALL +Exception: Dtor::__destruct +NEW +Exception: Dtor::__destruct +INCLUDE_OR_EVAL +Exception: Dtor::__destruct +INIT_DYNAMIC_CALL +Exception: Dtor::__destruct +==DONE== diff --git a/Zend/tests/dynamic_prop_deprecation_002.phpt b/Zend/tests/dynamic_prop_deprecation_002.phpt index bd0d3aa5a7df..20182d2a8923 100644 --- a/Zend/tests/dynamic_prop_deprecation_002.phpt +++ b/Zend/tests/dynamic_prop_deprecation_002.phpt @@ -15,4 +15,3 @@ try { ?> --EXPECT-- Err: Creation of dynamic property class@anonymous::$y is deprecated -Exception: Cannot create dynamic property class@anonymous::$y diff --git a/Zend/tests/ex_func_null_during_property_write.phpt b/Zend/tests/ex_func_null_during_property_write.phpt index 6a253f760e0b..125ab4c411e8 100644 --- a/Zend/tests/ex_func_null_during_property_write.phpt +++ b/Zend/tests/ex_func_null_during_property_write.phpt @@ -13,13 +13,8 @@ class a { new a; ?> --EXPECTF-- -Fatal error: Uncaught Error: Object of class a could not be converted to string in %s:%d +Fatal error: Uncaught Exception in %s:%d Stack trace: -#0 %s(%d): a->__destruct() -#1 {main} - -Next Exception in %s:%d -Stack trace: -#0 %s(%d): a->__destruct() +#0 [internal function]: a->__destruct() #1 {main} thrown in %s on line %d diff --git a/Zend/tests/exception_in_nested_rope.phpt b/Zend/tests/exception_in_nested_rope.phpt index 7afd1412354a..9ebe82e1eafd 100644 --- a/Zend/tests/exception_in_nested_rope.phpt +++ b/Zend/tests/exception_in_nested_rope.phpt @@ -3,7 +3,7 @@ Exception during nested rope --FILE-- bar(); --EXPECTF-- Fatal error: Uncaught RuntimeException in %sbug45805.php:%d Stack trace: -#0 %sbug45805.php(%d): PHPUnit_Util_ErrorHandler::handleError(8, 'Only variables ...', '%s', %d) -#1 [internal function]: B->foo() -#2 %sbug45805.php(%d): ReflectionMethod->invoke(Object(B)) -#3 %sbug45805.php(%d): B->bar() -#4 {main} +#0 [internal function]: PHPUnit_Util_ErrorHandler::handleError(8, 'Only variables ...', '/home/arnaud/de...', 19) +#1 %s(%d): ReflectionMethod->invoke(Object(B)) +#2 %s(%d): B->bar() +#3 {main} thrown in %sbug45805.php on line %d diff --git a/Zend/tests/exceptions/bug51394.phpt b/Zend/tests/exceptions/bug51394.phpt index 629ebec622b2..09ad1c398af1 100644 --- a/Zend/tests/exceptions/bug51394.phpt +++ b/Zend/tests/exceptions/bug51394.phpt @@ -10,7 +10,7 @@ function eh() return false; } -set_error_handler("eh"); +set_error_handler("eh", delay: false); $a = $empty($b); ?> --EXPECTF-- diff --git a/Zend/tests/exceptions/bug53511.phpt b/Zend/tests/exceptions/bug53511.phpt index b07504506a94..33430c31569c 100644 --- a/Zend/tests/exceptions/bug53511.phpt +++ b/Zend/tests/exceptions/bug53511.phpt @@ -1,5 +1,7 @@ --TEST-- Bug #53511 (Exceptions are lost in case an exception is thrown in catch operator) +--XFAIL-- +FIXME --FILE-- --EXPECTF-- diff --git a/Zend/tests/exceptions/bug78239.phpt b/Zend/tests/exceptions/bug78239.phpt index afc7176800e1..24f70807fb78 100644 --- a/Zend/tests/exceptions/bug78239.phpt +++ b/Zend/tests/exceptions/bug78239.phpt @@ -9,7 +9,7 @@ function handleError($level, $message, $file = '', $line = 0, $context = []) throw new ErrorException($message, 0, $level, $file, $line); } -set_error_handler('handleError'); +set_error_handler('handleError', delay: false); $r = new _ZendTestClass; (string)$r ?: ""; diff --git a/Zend/tests/exceptions/exception_008.phpt b/Zend/tests/exceptions/exception_008.phpt index 4640ec965ad5..11058b7127d4 100644 --- a/Zend/tests/exceptions/exception_008.phpt +++ b/Zend/tests/exceptions/exception_008.phpt @@ -20,6 +20,7 @@ class TestSecond $ar = array(new TestFirst, new TestSecond); unset($ar); +(function () {})(); ?> ===DONE=== diff --git a/Zend/tests/exceptions/exception_026.phpt b/Zend/tests/exceptions/exception_026.phpt index 0c47a449a4bf..cbcc913153c2 100644 --- a/Zend/tests/exceptions/exception_026.phpt +++ b/Zend/tests/exceptions/exception_026.phpt @@ -6,21 +6,16 @@ class A { static $max=0; function __destruct() { if (self::$max--<0) - X; + X; $a = new A; - Y; + Y; } } new A; ?> --EXPECTF-- -Fatal error: Uncaught Error: Undefined constant "Y" in %s:8 +Fatal error: Uncaught Error: Undefined constant "X" in %s:%d Stack trace: -#0 %s(11): A->__destruct() -#1 {main} - -Next Error: Undefined constant "X" in %s:6 -Stack trace: -#0 %s(11): A->__destruct() +#0 [internal function]: A->__destruct() #1 {main} thrown in %s on line 6 diff --git a/Zend/tests/exceptions/exception_before_fatal.phpt b/Zend/tests/exceptions/exception_before_fatal.phpt index edc63b2394cd..7dc71bbdce87 100644 --- a/Zend/tests/exceptions/exception_before_fatal.phpt +++ b/Zend/tests/exceptions/exception_before_fatal.phpt @@ -6,7 +6,7 @@ function exception_error_handler($code, $msg) { throw new Exception($msg); } -set_error_handler("exception_error_handler"); +set_error_handler("exception_error_handler", delay: false); try { $foo->a(); diff --git a/Zend/tests/falsetoarray_002.phpt b/Zend/tests/falsetoarray_002.phpt index c01b79954596..639cd51b3661 100644 --- a/Zend/tests/falsetoarray_002.phpt +++ b/Zend/tests/falsetoarray_002.phpt @@ -11,5 +11,13 @@ $a[0][$d]='b'; var_dump($a); ?> --EXPECT-- +array(1) { + [0]=> + array(1) { + [""]=> + string(1) "b" + } +} Err: Automatic conversion of false to array is deprecated -string(0) "" +Err: Undefined variable $d +Err: Using null as an array offset is deprecated, use an empty string instead diff --git a/Zend/tests/falsetoarray_003.phpt b/Zend/tests/falsetoarray_003.phpt index 117e443ef958..d62dff41941c 100644 --- a/Zend/tests/falsetoarray_003.phpt +++ b/Zend/tests/falsetoarray_003.phpt @@ -11,6 +11,6 @@ $a=[]; ?> DONE --EXPECTF-- +DONE Err: The float %f is not representable as an int, cast occurred Err: Undefined array key %i -DONE diff --git a/Zend/tests/fe_fetch_dtor_exception.phpt b/Zend/tests/fe_fetch_dtor_exception.phpt index 99378e739a8b..e014d72ec224 100644 --- a/Zend/tests/fe_fetch_dtor_exception.phpt +++ b/Zend/tests/fe_fetch_dtor_exception.phpt @@ -19,4 +19,5 @@ try { ?> --EXPECT-- +int(1) foo diff --git a/Zend/tests/fibers/gh9735-008.phpt b/Zend/tests/fibers/gh9735-008.phpt index ec6f29fb79de..a2b39558d59c 100644 --- a/Zend/tests/fibers/gh9735-008.phpt +++ b/Zend/tests/fibers/gh9735-008.phpt @@ -30,6 +30,7 @@ gc_collect_cycles(); print "2\n"; $fiber = null; +(function () {})(); gc_collect_cycles(); print "3\n"; diff --git a/Zend/tests/fibers/throw-in-multiple-destroyed-fibers-after-shutdown.phpt b/Zend/tests/fibers/throw-in-multiple-destroyed-fibers-after-shutdown.phpt index f2f09911fbb1..15c8dbf98f99 100644 --- a/Zend/tests/fibers/throw-in-multiple-destroyed-fibers-after-shutdown.phpt +++ b/Zend/tests/fibers/throw-in-multiple-destroyed-fibers-after-shutdown.phpt @@ -35,12 +35,12 @@ echo "done\n"; --EXPECTF-- done -Fatal error: Uncaught Exception: test1 in %sthrow-in-multiple-destroyed-fibers-after-shutdown.php:%d +Fatal error: Uncaught Exception: test1 in %s:%d Stack trace: #0 [internal function]: {closure:%s:%d}() #1 {main} -Next Exception: test2 in %sthrow-in-multiple-destroyed-fibers-after-shutdown.php:%d +Next Exception: test2 in %s:%d Stack trace: #0 [internal function]: {closure:%s:%d}() #1 {main} diff --git a/Zend/tests/fibers/unfinished-fiber-with-finally.phpt b/Zend/tests/fibers/unfinished-fiber-with-finally.phpt index 84ba74e646c6..8948a8a6a8d4 100644 --- a/Zend/tests/fibers/unfinished-fiber-with-finally.phpt +++ b/Zend/tests/fibers/unfinished-fiber-with-finally.phpt @@ -20,6 +20,7 @@ $fiber = new Fiber(function (): void { $fiber->start(); unset($fiber); // Destroy fiber object, executing finally block. +(function () {})(); echo "done\n"; diff --git a/Zend/tests/fibers/unfinished-fiber-with-nested-try-catch.phpt b/Zend/tests/fibers/unfinished-fiber-with-nested-try-catch.phpt index 664e4a052b8f..2d62ba0419ea 100644 --- a/Zend/tests/fibers/unfinished-fiber-with-nested-try-catch.phpt +++ b/Zend/tests/fibers/unfinished-fiber-with-nested-try-catch.phpt @@ -36,6 +36,7 @@ $fiber = new Fiber(function (): void { $fiber->start(); unset($fiber); // Destroy fiber object, executing finally block. +(function () {})(); echo "done\n"; diff --git a/Zend/tests/fibers/unfinished-fiber-with-suspend-in-finally.phpt b/Zend/tests/fibers/unfinished-fiber-with-suspend-in-finally.phpt index e38774df82bf..39a0b569cdb9 100644 --- a/Zend/tests/fibers/unfinished-fiber-with-suspend-in-finally.phpt +++ b/Zend/tests/fibers/unfinished-fiber-with-suspend-in-finally.phpt @@ -25,6 +25,7 @@ $fiber = new Fiber(function (): object { $fiber->start(); unset($fiber); // Destroy fiber object, executing finally block. +(function () {})(); echo "done\n"; diff --git a/Zend/tests/fibers/unfinished-fiber-with-throw-in-finally.phpt b/Zend/tests/fibers/unfinished-fiber-with-throw-in-finally.phpt index f1b17caeb5d7..202a079ba9fe 100644 --- a/Zend/tests/fibers/unfinished-fiber-with-throw-in-finally.phpt +++ b/Zend/tests/fibers/unfinished-fiber-with-throw-in-finally.phpt @@ -35,6 +35,7 @@ $fiber = new Fiber(function (): void { $fiber->start(); unset($fiber); // Destroy fiber object, executing finally block. +(function () {})(); echo "done\n"; diff --git a/Zend/tests/first_class_callable/constexpr/error_static_call_trait_method_002.phpt b/Zend/tests/first_class_callable/constexpr/error_static_call_trait_method_002.phpt index 97831a8d65f0..37dc81052723 100644 --- a/Zend/tests/first_class_callable/constexpr/error_static_call_trait_method_002.phpt +++ b/Zend/tests/first_class_callable/constexpr/error_static_call_trait_method_002.phpt @@ -5,7 +5,7 @@ FCC in initializer emits deprecation for static reference to trait method (Excep set_error_handler(function (int $errno, string $errstr, ?string $errfile = null, ?int $errline = null) { throw new \ErrorException($errstr, 0, $errno, $errfile, $errline); -}); +}, delay: false); trait Foo { public static function myMethod(string $foo) { @@ -16,7 +16,7 @@ trait Foo { function foo(Closure $c = Foo::myMethod(...)) { var_dump($c); - $c("abc"); + $c("abc"); } try { diff --git a/Zend/tests/frameless_throwing_destructor.phpt b/Zend/tests/frameless_throwing_destructor.phpt index ad555d860e66..28bb6caf4ba4 100644 --- a/Zend/tests/frameless_throwing_destructor.phpt +++ b/Zend/tests/frameless_throwing_destructor.phpt @@ -13,6 +13,6 @@ in_array(new Foo(), [new Bar()], true); --EXPECTF-- Fatal error: Uncaught Exception in %s:%d Stack trace: -#0 %s(%d): Bar->__destruct() +#0 [internal function]: Bar->__destruct() #1 {main} thrown in %s on line %d diff --git a/Zend/tests/frameless_undefined_var.phpt b/Zend/tests/frameless_undefined_var.phpt index e9c5aac58236..027b1c414134 100644 --- a/Zend/tests/frameless_undefined_var.phpt +++ b/Zend/tests/frameless_undefined_var.phpt @@ -4,7 +4,7 @@ Undefined var in frameless call getValue()->getId()); echo "Before unset", PHP_EOL; unset($v); +(function () {})(); echo "After unset", PHP_EOL; diff --git a/Zend/tests/functions/zend_call_function_deprecated_frame.phpt b/Zend/tests/functions/zend_call_function_deprecated_frame.phpt index 83d05144c0bd..44834c8a9d80 100644 --- a/Zend/tests/functions/zend_call_function_deprecated_frame.phpt +++ b/Zend/tests/functions/zend_call_function_deprecated_frame.phpt @@ -10,7 +10,7 @@ function foo(string $v) { set_error_handler(function ($number, $message) { throw new Exception($message); -}); +}, delay: false); $a = array_map(foo(...), ['Hello', 'World']); var_dump($a); diff --git a/Zend/tests/gc/bug64960.phpt b/Zend/tests/gc/bug64960.phpt index d3dcc4da8c5e..171293d0b564 100644 --- a/Zend/tests/gc/bug64960.phpt +++ b/Zend/tests/gc/bug64960.phpt @@ -23,7 +23,7 @@ set_error_handler(function() $e->_trace = debug_backtrace(); throw $e; -}); +}, delay: false); // trigger error handler $a['waa']; @@ -37,8 +37,7 @@ Deprecated: Creation of dynamic property Exception::$_trace is deprecated in %s Fatal error: Uncaught Exception in %sbug64960.php:19 Stack trace: -#0 [internal function]: {closure:%s:%d}(8, 'ob_end_clean():...', '%s', 9) -#1 %sbug64960.php(9): ob_end_clean() -#2 [internal function]: ExceptionHandler->__invoke(Object(Exception)) -#3 {main} +#0 %s(%d): {closure:%s:%d}(8, 'ob_end_clean():...', '/home/arnaud/de...', 9) +#1 [internal function]: ExceptionHandler->__invoke(Object(Exception)) +#2 {main} thrown in %sbug64960.php on line 19 diff --git a/Zend/tests/gc_053.phpt b/Zend/tests/gc_053.phpt index 858be7cbebd5..c9035f2527bf 100644 --- a/Zend/tests/gc_053.phpt +++ b/Zend/tests/gc_053.phpt @@ -22,6 +22,7 @@ $o = new WithDestructor(); $weakO = \WeakReference::create($o); echo "---\n"; unset($o); +(function () {})(); echo "---\n"; var_dump($weakO->get() !== null); // verify if kept allocated G::$v = null; diff --git a/Zend/tests/generators/bug71601.phpt b/Zend/tests/generators/bug71601.phpt index c8e226329dfe..3d4a11be63cc 100644 --- a/Zend/tests/generators/bug71601.phpt +++ b/Zend/tests/generators/bug71601.phpt @@ -27,6 +27,7 @@ $generator = gen2(); var_dump($generator->current()); unset($generator); +(function() {})(); echo "Done\n"; diff --git a/Zend/tests/generators/errors/yield_in_force_closed_finally_error.phpt b/Zend/tests/generators/errors/yield_in_force_closed_finally_error.phpt index af84e50215ce..894a4d7e8e4b 100644 --- a/Zend/tests/generators/errors/yield_in_force_closed_finally_error.phpt +++ b/Zend/tests/generators/errors/yield_in_force_closed_finally_error.phpt @@ -28,6 +28,6 @@ before yield in finally Fatal error: Uncaught Error: Cannot yield from finally in a force-closed generator in %s:%d Stack trace: -#0 %s(%d): gen() +#0 [internal function]: gen() #1 {main} thrown in %s on line %d diff --git a/Zend/tests/generators/generator_closure_collection.phpt b/Zend/tests/generators/generator_closure_collection.phpt index 7386adeb80c5..34c8552df60c 100644 --- a/Zend/tests/generators/generator_closure_collection.phpt +++ b/Zend/tests/generators/generator_closure_collection.phpt @@ -12,6 +12,7 @@ $genFactory = function() { $r = WeakReference::create($genFactory); $generator = $genFactory(); unset($genFactory); +(function () {})(); var_dump($r->get()); @@ -20,6 +21,7 @@ foreach ($generator as $value) var_dump($value); var_dump($r->get()); unset($generator); +(function () {})(); var_dump($r->get()); diff --git a/Zend/tests/generators/gh9750-001.phpt b/Zend/tests/generators/gh9750-001.phpt index 9a64912c2525..a958f36de53e 100644 --- a/Zend/tests/generators/gh9750-001.phpt +++ b/Zend/tests/generators/gh9750-001.phpt @@ -23,6 +23,7 @@ foreach ($gen as $value) { } $gen = null; +(function () {})(); gc_collect_cycles(); diff --git a/Zend/tests/generators/gh9750-002.phpt b/Zend/tests/generators/gh9750-002.phpt index f46bd381283e..4594782dcbe5 100644 --- a/Zend/tests/generators/gh9750-002.phpt +++ b/Zend/tests/generators/gh9750-002.phpt @@ -23,6 +23,7 @@ foreach ($gen as $value) { } $gen = null; +(function () {})(); gc_collect_cycles(); diff --git a/Zend/tests/generators/gh9750-003.phpt b/Zend/tests/generators/gh9750-003.phpt index f58abb243312..82e2cf90ee00 100644 --- a/Zend/tests/generators/gh9750-003.phpt +++ b/Zend/tests/generators/gh9750-003.phpt @@ -23,6 +23,7 @@ foreach ($gen as $value) { } $gen = null; +(function () {})(); gc_collect_cycles(); diff --git a/Zend/tests/generators/gh9750-004.phpt b/Zend/tests/generators/gh9750-004.phpt index ad26a9029e4b..555819d8eb48 100644 --- a/Zend/tests/generators/gh9750-004.phpt +++ b/Zend/tests/generators/gh9750-004.phpt @@ -23,6 +23,7 @@ foreach ($gen as $value) { } $gen = null; +(function () {})(); gc_collect_cycles(); diff --git a/Zend/tests/generators/gh9750-005.phpt b/Zend/tests/generators/gh9750-005.phpt index 1e849946917a..31942fc71270 100644 --- a/Zend/tests/generators/gh9750-005.phpt +++ b/Zend/tests/generators/gh9750-005.phpt @@ -24,6 +24,7 @@ foreach ($gen as $value) { $gen = null; $c = null; +(function () {})(); gc_collect_cycles(); diff --git a/Zend/tests/generators/gh9750-006.phpt b/Zend/tests/generators/gh9750-006.phpt index 6ba6c416d4af..23a37577a91b 100644 --- a/Zend/tests/generators/gh9750-006.phpt +++ b/Zend/tests/generators/gh9750-006.phpt @@ -23,6 +23,7 @@ foreach ($gen as $value) { } $gen = null; +(function () {})(); gc_collect_cycles(); diff --git a/Zend/tests/generators/gh9750-007.phpt b/Zend/tests/generators/gh9750-007.phpt index dbf91752ef5a..a62cfebab582 100644 --- a/Zend/tests/generators/gh9750-007.phpt +++ b/Zend/tests/generators/gh9750-007.phpt @@ -29,5 +29,5 @@ gc_collect_cycles(); ?> ==DONE== --EXPECT-- -C::__destruct ==DONE== +C::__destruct diff --git a/Zend/tests/generators/gh9750-008.phpt b/Zend/tests/generators/gh9750-008.phpt index a9cdacd19d15..63f05b3cb1fd 100644 --- a/Zend/tests/generators/gh9750-008.phpt +++ b/Zend/tests/generators/gh9750-008.phpt @@ -36,5 +36,5 @@ gc_collect_cycles(); ?> ==DONE== --EXPECT-- -C::__destruct ==DONE== +C::__destruct diff --git a/Zend/tests/generators/gh9750-009.phpt b/Zend/tests/generators/gh9750-009.phpt index 561ed081e379..82f5bcb6a870 100644 --- a/Zend/tests/generators/gh9750-009.phpt +++ b/Zend/tests/generators/gh9750-009.phpt @@ -33,5 +33,5 @@ gc_collect_cycles(); ?> ==DONE== --EXPECT-- -C::__destruct ==DONE== +C::__destruct diff --git a/Zend/tests/generators/gh9750-010.phpt b/Zend/tests/generators/gh9750-010.phpt index ab5b6bf6d48c..4e1d2039f06c 100644 --- a/Zend/tests/generators/gh9750-010.phpt +++ b/Zend/tests/generators/gh9750-010.phpt @@ -29,5 +29,5 @@ gc_collect_cycles(); ?> ==DONE== --EXPECT-- -C::__destruct ==DONE== +C::__destruct diff --git a/Zend/tests/generators/gh9750-011.phpt b/Zend/tests/generators/gh9750-011.phpt index ab4c00a17358..cec207b97ec0 100644 --- a/Zend/tests/generators/gh9750-011.phpt +++ b/Zend/tests/generators/gh9750-011.phpt @@ -34,5 +34,5 @@ gc_collect_cycles(); ?> ==DONE== --EXPECT-- -C::__destruct ==DONE== +C::__destruct diff --git a/Zend/tests/generators/yield_from_force_closed.phpt b/Zend/tests/generators/yield_from_force_closed.phpt index 87fcd2e8ed93..fa5cc183ca06 100644 --- a/Zend/tests/generators/yield_from_force_closed.phpt +++ b/Zend/tests/generators/yield_from_force_closed.phpt @@ -22,6 +22,7 @@ try { $gen = gen2(); $gen->rewind(); unset($gen); + (function () {})(); } catch (Error $e) { echo $e, "\n"; } diff --git a/Zend/tests/get_class_basic.phpt b/Zend/tests/get_class_basic.phpt index f6dcbccb6916..43dec0e592f6 100644 --- a/Zend/tests/get_class_basic.phpt +++ b/Zend/tests/get_class_basic.phpt @@ -25,7 +25,7 @@ $f2 = new foo2; set_error_handler(function ($severity, $message, $file, $line) { throw new Exception($message); -}); +}, delay: false); try { $f1->bar(); } catch (Exception $e) { diff --git a/Zend/tests/gh10168/assign_prop_ref.phpt b/Zend/tests/gh10168/assign_prop_ref.phpt index 606542fbd6c6..e8efb1d7051a 100644 --- a/Zend/tests/gh10168/assign_prop_ref.phpt +++ b/Zend/tests/gh10168/assign_prop_ref.phpt @@ -26,7 +26,8 @@ test($box); test($box); ?> ---EXPECT-- -NULL -object(Test)#2 (0) { +--EXPECTF-- +object(Test)#%d (0) { +} +object(Test)#%d (0) { } diff --git a/Zend/tests/gh10168/assign_prop_ref_with_prop_ref.phpt b/Zend/tests/gh10168/assign_prop_ref_with_prop_ref.phpt index f887acbc1d06..62ff10c2b876 100644 --- a/Zend/tests/gh10168/assign_prop_ref_with_prop_ref.phpt +++ b/Zend/tests/gh10168/assign_prop_ref_with_prop_ref.phpt @@ -29,7 +29,8 @@ test($box); test($box); ?> ---EXPECT-- -object(Test)#3 (0) { +--EXPECTF-- +object(Test)#%d (0) { +} +object(Test)#%d (0) { } -NULL diff --git a/Zend/tests/gh10168/assign_ref.phpt b/Zend/tests/gh10168/assign_ref.phpt index 9f3be5619d1a..b6348e21e4ca 100644 --- a/Zend/tests/gh10168/assign_ref.phpt +++ b/Zend/tests/gh10168/assign_ref.phpt @@ -12,7 +12,9 @@ class Test { $a = new Test; $tmp = new Test; var_dump($a = &$tmp); +(function () {})(); ?> ---EXPECT-- -NULL +--EXPECTF-- +object(Test)#%d (0) { +} diff --git a/Zend/tests/gh10168/assign_ref_with_prop_ref.phpt b/Zend/tests/gh10168/assign_ref_with_prop_ref.phpt index 42ce94b3f83e..2bade8437744 100644 --- a/Zend/tests/gh10168/assign_ref_with_prop_ref.phpt +++ b/Zend/tests/gh10168/assign_ref_with_prop_ref.phpt @@ -16,5 +16,6 @@ $tmp = new Test; var_dump($a = &$tmp); ?> ---EXPECT-- -NULL +--EXPECTF-- +object(Test)#%d (0) { +} diff --git a/Zend/tests/gh10168/assign_static_prop_ref.phpt b/Zend/tests/gh10168/assign_static_prop_ref.phpt index 2e90be884ded..c05ac00ebdb8 100644 --- a/Zend/tests/gh10168/assign_static_prop_ref.phpt +++ b/Zend/tests/gh10168/assign_static_prop_ref.phpt @@ -16,5 +16,6 @@ $tmp = new Test; var_dump(Test::$test = &$tmp); ?> ---EXPECT-- -NULL +--EXPECTF-- +object(Test)#%d (0) { +} diff --git a/Zend/tests/gh10168/assign_static_untyped_prop_ref.phpt b/Zend/tests/gh10168/assign_static_untyped_prop_ref.phpt index dfef8ead26f6..0592cf9de5aa 100644 --- a/Zend/tests/gh10168/assign_static_untyped_prop_ref.phpt +++ b/Zend/tests/gh10168/assign_static_untyped_prop_ref.phpt @@ -16,5 +16,6 @@ $tmp = new Test; var_dump(Test::$test = &$tmp); ?> ---EXPECT-- -NULL +--EXPECTF-- +object(Test)#%d (0) { +} diff --git a/Zend/tests/gh10168/assign_untyped_prop_ref.phpt b/Zend/tests/gh10168/assign_untyped_prop_ref.phpt index a28395d43bbb..81e2f306b3e1 100644 --- a/Zend/tests/gh10168/assign_untyped_prop_ref.phpt +++ b/Zend/tests/gh10168/assign_untyped_prop_ref.phpt @@ -26,7 +26,8 @@ test($box); test($box); ?> ---EXPECT-- -NULL -object(Test)#2 (0) { +--EXPECTF-- +object(Test)#%d (0) { +} +object(Test)#%d (0) { } diff --git a/Zend/tests/gh10168/assign_untyped_prop_ref_with_prop_ref.phpt b/Zend/tests/gh10168/assign_untyped_prop_ref_with_prop_ref.phpt index 79ff5fefc07e..de4d855b006f 100644 --- a/Zend/tests/gh10168/assign_untyped_prop_ref_with_prop_ref.phpt +++ b/Zend/tests/gh10168/assign_untyped_prop_ref_with_prop_ref.phpt @@ -29,7 +29,8 @@ test($box); test($box); ?> ---EXPECT-- -object(Test)#3 (0) { +--EXPECTF-- +object(Test)#%d (0) { +} +object(Test)#%d (0) { } -NULL diff --git a/Zend/tests/gh16799.phpt b/Zend/tests/gh16799.phpt index d31d1a5705c6..ef2e20c1260a 100644 --- a/Zend/tests/gh16799.phpt +++ b/Zend/tests/gh16799.phpt @@ -2,7 +2,7 @@ GH-16799 (Assertion failure at Zend/zend_vm_execute.h) --FILE-- getMessage(), "\n"; } ?> ---EXPECT-- -Attempt to assign property "value" on null +--EXPECTF-- +Warning: getimagesize(dummy): Failed to open stream: No such file or directory in %s on line %d +Attempt to assign property "value" on array diff --git a/Zend/tests/gh20183_001.phpt b/Zend/tests/gh20183_001.phpt index 9468bcaea567..12423ede91ac 100644 --- a/Zend/tests/gh20183_001.phpt +++ b/Zend/tests/gh20183_001.phpt @@ -16,7 +16,7 @@ B::$b = new A; ?> --EXPECTF-- -#0 %s(10): A->__destruct() +#0 %s(%d): A->__destruct() Fatal error: Uncaught Error: Class "B" not found in %s:10 Stack trace: diff --git a/Zend/tests/gh20183_002.phpt b/Zend/tests/gh20183_002.phpt index ec4d62d0960d..97e58da5e79c 100644 --- a/Zend/tests/gh20183_002.phpt +++ b/Zend/tests/gh20183_002.phpt @@ -26,7 +26,7 @@ B::$a = new A(); ?> --EXPECTF-- -#0 %s(20): gen() +#0 %s(%d): gen() Fatal error: Uncaught Error: Class "B" not found in %s:20 Stack trace: diff --git a/Zend/tests/gh_21699.phpt b/Zend/tests/gh_21699.phpt index 49b58365dabf..197e6c23c6ba 100644 --- a/Zend/tests/gh_21699.phpt +++ b/Zend/tests/gh_21699.phpt @@ -2,9 +2,9 @@ GH-21699: Assertion failure in shutdown_executor when error handler throws during self:: callable resolution --FILE-- test(); ?> --EXPECTF-- -Fatal error: Uncaught Exception in %s:%d +Fatal error: Uncaught Exception: Use of "self" in callables is deprecated in %s:%d Stack trace: #0 %s(%d): {closure:%s}(%d, 'Use of "self" i%s', '%s', %d) #1 %s(%d): bar->test() #2 {main} - -Next TypeError: call_user_func(): Argument #1 ($callback) must be a valid callback, (null) in %s:%d -Stack trace: -#0 %s(%d): bar->test() -#1 {main} thrown in %s on line %d diff --git a/Zend/tests/gh_21699_parent.phpt b/Zend/tests/gh_21699_parent.phpt index 73cae41f3f5b..75535f349cc7 100644 --- a/Zend/tests/gh_21699_parent.phpt +++ b/Zend/tests/gh_21699_parent.phpt @@ -2,9 +2,9 @@ GH-21699 (parent::): no shutdown_executor trampoline assertion when error handler throws during parent:: callable resolution --FILE-- test(); ?> --EXPECTF-- -Fatal error: Uncaught Exception in %s:%d +Fatal error: Uncaught Exception: Use of "parent" in callables is deprecated in %s:%d Stack trace: #0 %s(%d): {closure:%s}(%d, 'Use of "parent"%s', '%s', %d) #1 %s(%d): Child->test() #2 {main} - -Next TypeError: call_user_func(): Argument #1 ($callback) must be a valid callback, (null) in %s:%d -Stack trace: -#0 %s(%d): Child->test() -#1 {main} thrown in %s on line %d diff --git a/Zend/tests/gh_21699_static.phpt b/Zend/tests/gh_21699_static.phpt index 4d9604ebe77b..fb5e34fdd83b 100644 --- a/Zend/tests/gh_21699_static.phpt +++ b/Zend/tests/gh_21699_static.phpt @@ -2,9 +2,9 @@ GH-21699 (static::): no shutdown_executor trampoline assertion when error handler throws during static:: callable resolution --FILE-- test(); ?> --EXPECTF-- -Fatal error: Uncaught Exception in %s:%d +Fatal error: Uncaught Exception: Use of "static" in callables is deprecated in %s:%d Stack trace: #0 %s(%d): {closure:%s}(%d, 'Use of "static"%s', '%s', %d) #1 %s(%d): bar->test() #2 {main} - -Next TypeError: call_user_func(): Argument #1 ($callback) must be a valid callback, (null) in %s:%d -Stack trace: -#0 %s(%d): bar->test() -#1 {main} thrown in %s on line %d diff --git a/Zend/tests/in-de-crement/incdec_bool_exception.phpt b/Zend/tests/in-de-crement/incdec_bool_exception.phpt index f819af1e2395..2e07f904169d 100644 --- a/Zend/tests/in-de-crement/incdec_bool_exception.phpt +++ b/Zend/tests/in-de-crement/incdec_bool_exception.phpt @@ -5,7 +5,7 @@ Inc/dec on bool: warning converted to exception set_error_handler(function($severity, $m) { throw new Exception($m, $severity); -}); +}, delay: false); $values = [false, true]; foreach ($values as $value) { diff --git a/Zend/tests/in-de-crement/incdec_strings_exception.phpt b/Zend/tests/in-de-crement/incdec_strings_exception.phpt index 5acbb1041222..e374f49a3408 100644 --- a/Zend/tests/in-de-crement/incdec_strings_exception.phpt +++ b/Zend/tests/in-de-crement/incdec_strings_exception.phpt @@ -11,7 +11,7 @@ set_error_handler(function($severity, $m) { $m = 'Warning: ' . $m; } throw new Exception($m, $severity); -}); +}, delay: false); $values = [ '', diff --git a/Zend/tests/in-de-crement/incdec_undef.phpt b/Zend/tests/in-de-crement/incdec_undef.phpt index db560e31c99f..549c64fea87e 100644 --- a/Zend/tests/in-de-crement/incdec_undef.phpt +++ b/Zend/tests/in-de-crement/incdec_undef.phpt @@ -14,6 +14,7 @@ unset($x); var_dump(++$x); ?> --EXPECT-- +NULL Undefined variable $x Decrement on type null has no effect, this will change in the next major version of PHP NULL @@ -21,6 +22,5 @@ Undefined variable $x NULL Undefined variable $x Decrement on type null has no effect, this will change in the next major version of PHP -NULL -Undefined variable $x int(1) +Undefined variable $x diff --git a/Zend/tests/in-de-crement/increment_diagnostic_change_type.phpt b/Zend/tests/in-de-crement/increment_diagnostic_change_type.phpt index 11a0edac1917..b55c8c6b811e 100644 --- a/Zend/tests/in-de-crement/increment_diagnostic_change_type.phpt +++ b/Zend/tests/in-de-crement/increment_diagnostic_change_type.phpt @@ -31,8 +31,8 @@ var_dump($x); DONE --EXPECT-- string(1) "1" -string(74) "Increment on non-numeric string is deprecated, use str_increment() instead" string(4) "foo!" string(74) "Increment on non-numeric string is deprecated, use str_increment() instead" string(1) "!" +string(74) "Increment on non-numeric string is deprecated, use str_increment() instead" DONE diff --git a/Zend/tests/in-de-crement/oss-fuzz-60709_globals_unset_after_undef_warning.phpt b/Zend/tests/in-de-crement/oss-fuzz-60709_globals_unset_after_undef_warning.phpt index e981800eeac1..1f1fc7228134 100644 --- a/Zend/tests/in-de-crement/oss-fuzz-60709_globals_unset_after_undef_warning.phpt +++ b/Zend/tests/in-de-crement/oss-fuzz-60709_globals_unset_after_undef_warning.phpt @@ -21,16 +21,16 @@ var_dump(++$x); ?> --EXPECT-- POST DEC +NULL Undefined variable $x Decrement on type null has no effect, this will change in the next major version of PHP -NULL POST INC -Undefined variable $x NULL +Undefined variable $x PRE DEC +NULL Undefined variable $x Decrement on type null has no effect, this will change in the next major version of PHP -NULL PRE INC -Undefined variable $x int(1) +Undefined variable $x diff --git a/Zend/tests/in-de-crement/oss-fuzz-62294_globals_unset_after_string_warning.phpt b/Zend/tests/in-de-crement/oss-fuzz-62294_globals_unset_after_string_warning.phpt index f52dff52e631..e39184e68154 100644 --- a/Zend/tests/in-de-crement/oss-fuzz-62294_globals_unset_after_string_warning.phpt +++ b/Zend/tests/in-de-crement/oss-fuzz-62294_globals_unset_after_string_warning.phpt @@ -25,14 +25,14 @@ var_dump(++$x); ?> --EXPECT-- POST DEC -Decrement on non-numeric string has no effect and is deprecated string(1) " " -PRE DEC Decrement on non-numeric string has no effect and is deprecated +PRE DEC string(1) " " +Decrement on non-numeric string has no effect and is deprecated POST INC -Increment on non-numeric string is deprecated, use str_increment() instead string(1) " " -PRE INC Increment on non-numeric string is deprecated, use str_increment() instead +PRE INC string(1) " " +Increment on non-numeric string is deprecated, use str_increment() instead diff --git a/Zend/tests/in-de-crement/unset_globals_in_error_handler.phpt b/Zend/tests/in-de-crement/unset_globals_in_error_handler.phpt index 31ffea22467b..88302517ce05 100644 --- a/Zend/tests/in-de-crement/unset_globals_in_error_handler.phpt +++ b/Zend/tests/in-de-crement/unset_globals_in_error_handler.phpt @@ -78,53 +78,53 @@ unset($x); --EXPECT-- NULL (only --) POST DEC -Decrement on type null has no effect, this will change in the next major version of PHP NULL -PRE DEC Decrement on type null has no effect, this will change in the next major version of PHP +PRE DEC NULL +Decrement on type null has no effect, this will change in the next major version of PHP Empty string POST INC -Increment on non-numeric string is deprecated, use str_increment() instead string(0) "" +Increment on non-numeric string is deprecated, use str_increment() instead POST DEC -Decrement on empty string is deprecated as non-numeric string(0) "" +Decrement on empty string is deprecated as non-numeric PRE INC -Increment on non-numeric string is deprecated, use str_increment() instead string(1) "1" +Increment on non-numeric string is deprecated, use str_increment() instead PRE DEC -Decrement on empty string is deprecated as non-numeric int(-1) +Decrement on empty string is deprecated as non-numeric Non fill ASCII (only ++) POST INC -Increment on non-numeric string is deprecated, use str_increment() instead string(4) " ad " -PRE INC Increment on non-numeric string is deprecated, use str_increment() instead +PRE INC string(4) " ad " +Increment on non-numeric string is deprecated, use str_increment() instead Bool POST INC -Increment on type bool has no effect, this will change in the next major version of PHP bool(false) +Increment on type bool has no effect, this will change in the next major version of PHP POST DEC -Decrement on type bool has no effect, this will change in the next major version of PHP bool(false) +Decrement on type bool has no effect, this will change in the next major version of PHP PRE INC -Increment on type bool has no effect, this will change in the next major version of PHP bool(false) +Increment on type bool has no effect, this will change in the next major version of PHP PRE DEC -Decrement on type bool has no effect, this will change in the next major version of PHP bool(false) +Decrement on type bool has no effect, this will change in the next major version of PHP POST INC -Increment on type bool has no effect, this will change in the next major version of PHP bool(true) +Increment on type bool has no effect, this will change in the next major version of PHP POST DEC -Decrement on type bool has no effect, this will change in the next major version of PHP bool(true) +Decrement on type bool has no effect, this will change in the next major version of PHP PRE INC -Increment on type bool has no effect, this will change in the next major version of PHP bool(true) +Increment on type bool has no effect, this will change in the next major version of PHP PRE DEC -Decrement on type bool has no effect, this will change in the next major version of PHP bool(true) +Decrement on type bool has no effect, this will change in the next major version of PHP diff --git a/Zend/tests/in-de-crement/unset_object_property_in_error_handler.phpt b/Zend/tests/in-de-crement/unset_object_property_in_error_handler.phpt index 4d2a4705588a..b00ba707cecf 100644 --- a/Zend/tests/in-de-crement/unset_object_property_in_error_handler.phpt +++ b/Zend/tests/in-de-crement/unset_object_property_in_error_handler.phpt @@ -87,57 +87,57 @@ var_dump(--$c->a); unset($c->a); ?> --EXPECT-- -string(87) "Decrement on type null has no effect, this will change in the next major version of PHP" NULL +string(87) "Decrement on type null has no effect, this will change in the next major version of PHP" NULL (only --) POST DEC -string(87) "Decrement on type null has no effect, this will change in the next major version of PHP" NULL -PRE DEC string(87) "Decrement on type null has no effect, this will change in the next major version of PHP" +PRE DEC NULL +string(87) "Decrement on type null has no effect, this will change in the next major version of PHP" Empty string POST INC -string(74) "Increment on non-numeric string is deprecated, use str_increment() instead" string(0) "" +string(74) "Increment on non-numeric string is deprecated, use str_increment() instead" POST DEC -string(54) "Decrement on empty string is deprecated as non-numeric" string(0) "" +string(54) "Decrement on empty string is deprecated as non-numeric" PRE INC -string(74) "Increment on non-numeric string is deprecated, use str_increment() instead" string(1) "1" +string(74) "Increment on non-numeric string is deprecated, use str_increment() instead" PRE DEC -string(54) "Decrement on empty string is deprecated as non-numeric" int(-1) +string(54) "Decrement on empty string is deprecated as non-numeric" Non fill ASCII (only ++) POST INC -string(74) "Increment on non-numeric string is deprecated, use str_increment() instead" string(4) " ad " -PRE INC string(74) "Increment on non-numeric string is deprecated, use str_increment() instead" +PRE INC string(4) " ad " +string(74) "Increment on non-numeric string is deprecated, use str_increment() instead" Bool POST INC -string(87) "Increment on type bool has no effect, this will change in the next major version of PHP" bool(false) +string(87) "Increment on type bool has no effect, this will change in the next major version of PHP" POST DEC -string(87) "Decrement on type bool has no effect, this will change in the next major version of PHP" bool(false) +string(87) "Decrement on type bool has no effect, this will change in the next major version of PHP" PRE INC -string(87) "Increment on type bool has no effect, this will change in the next major version of PHP" bool(false) +string(87) "Increment on type bool has no effect, this will change in the next major version of PHP" PRE DEC -string(87) "Decrement on type bool has no effect, this will change in the next major version of PHP" bool(false) +string(87) "Decrement on type bool has no effect, this will change in the next major version of PHP" POST INC -string(87) "Increment on type bool has no effect, this will change in the next major version of PHP" bool(true) +string(87) "Increment on type bool has no effect, this will change in the next major version of PHP" POST DEC -string(87) "Decrement on type bool has no effect, this will change in the next major version of PHP" bool(true) +string(87) "Decrement on type bool has no effect, this will change in the next major version of PHP" PRE INC -string(87) "Increment on type bool has no effect, this will change in the next major version of PHP" bool(true) +string(87) "Increment on type bool has no effect, this will change in the next major version of PHP" PRE DEC -string(87) "Decrement on type bool has no effect, this will change in the next major version of PHP" bool(true) +string(87) "Decrement on type bool has no effect, this will change in the next major version of PHP" diff --git a/Zend/tests/in-de-crement/unset_property_converted_to_obj_in_error_handler.phpt b/Zend/tests/in-de-crement/unset_property_converted_to_obj_in_error_handler.phpt index d435c9fb4029..821b8abbade0 100644 --- a/Zend/tests/in-de-crement/unset_property_converted_to_obj_in_error_handler.phpt +++ b/Zend/tests/in-de-crement/unset_property_converted_to_obj_in_error_handler.phpt @@ -19,7 +19,6 @@ try { } var_dump($c->a); ?> ---EXPECT-- -Cannot increment stdClass -object(stdClass)#2 (0) { +--EXPECTF-- +object(stdClass)#%d (0) { } diff --git a/Zend/tests/inheritance/deprecation_to_exception_during_inheritance.phpt b/Zend/tests/inheritance/deprecation_to_exception_during_inheritance.phpt index 4bdf4b5d1b95..ede49e580ce7 100644 --- a/Zend/tests/inheritance/deprecation_to_exception_during_inheritance.phpt +++ b/Zend/tests/inheritance/deprecation_to_exception_during_inheritance.phpt @@ -9,7 +9,7 @@ if (getenv('SKIP_PRELOAD')) die('skip Error handler not active during preloading set_error_handler(function($code, $message) { throw new Exception($message); -}); +}, delay: false); $class = new class extends DateTime { public function getTimezone() {} diff --git a/Zend/tests/inheritance/deprecation_to_exception_during_inheritance_can_be_caught.phpt b/Zend/tests/inheritance/deprecation_to_exception_during_inheritance_can_be_caught.phpt index 7a59cca70bd6..8b8c88c4833f 100644 --- a/Zend/tests/inheritance/deprecation_to_exception_during_inheritance_can_be_caught.phpt +++ b/Zend/tests/inheritance/deprecation_to_exception_during_inheritance_can_be_caught.phpt @@ -9,7 +9,7 @@ if (getenv('SKIP_PRELOAD')) die('skip Error handler not active during preloading set_error_handler(function($code, $message) { throw new Exception($message); -}); +}, delay: false); try { class C extends DateTime { diff --git a/Zend/tests/inheritance/gh15907.phpt b/Zend/tests/inheritance/gh15907.phpt index c92e40a4ba30..c19222d5efd1 100644 --- a/Zend/tests/inheritance/gh15907.phpt +++ b/Zend/tests/inheritance/gh15907.phpt @@ -5,7 +5,7 @@ GH-15907: Failed assertion when promoting inheritance error to exception set_error_handler(function($errno, $msg) { throw new Exception($msg); -}); +}, delay: false); class C implements Serializable { public function serialize() {} diff --git a/Zend/tests/lazy_objects/gh15999_001.phpt b/Zend/tests/lazy_objects/gh15999_001.phpt index 9fa70752d6b4..64dbf5cb5e15 100644 --- a/Zend/tests/lazy_objects/gh15999_001.phpt +++ b/Zend/tests/lazy_objects/gh15999_001.phpt @@ -5,9 +5,6 @@ Lazy Objects: GH-15999 001: Object is released during initialization class C { public $s; - public function __destruct() { - var_dump(__METHOD__); - } } print "# Ghost:\n"; @@ -96,13 +93,10 @@ try { ==DONE== --EXPECT-- # Ghost: -string(13) "C::__destruct" Error: Lazy object was released during initialization # Proxy: -string(13) "C::__destruct" Error: Lazy object was released during initialization # GC cycle: -string(13) "C::__destruct" # Nested error (ghost): Error: Lazy object was released during initialization TypeError: Lazy object initializer must return NULL or no value diff --git a/Zend/tests/lazy_objects/reset_as_lazy_calls_destructor.phpt b/Zend/tests/lazy_objects/reset_as_lazy_calls_destructor.phpt index 733da55a5cbc..315cfaeb4d4b 100644 --- a/Zend/tests/lazy_objects/reset_as_lazy_calls_destructor.phpt +++ b/Zend/tests/lazy_objects/reset_as_lazy_calls_destructor.phpt @@ -29,6 +29,7 @@ print "After makeLazy\n"; var_dump($obj->a); $obj = null; +(function () {})(); print "# Proxy:\n"; diff --git a/Zend/tests/lazy_objects/reset_as_lazy_can_reset_initialized_proxies.phpt b/Zend/tests/lazy_objects/reset_as_lazy_can_reset_initialized_proxies.phpt index 0ac167724c7d..36faddf32da5 100644 --- a/Zend/tests/lazy_objects/reset_as_lazy_can_reset_initialized_proxies.phpt +++ b/Zend/tests/lazy_objects/reset_as_lazy_can_reset_initialized_proxies.phpt @@ -50,6 +50,6 @@ object(A)#%d (2) { ["a"]=> int(1) ["proxy"]=> - object(A)#%d (0) { + lazy proxy object(A)#%d (0) { } } diff --git a/Zend/tests/lazy_objects/reset_as_lazy_may_skip_destructor.phpt b/Zend/tests/lazy_objects/reset_as_lazy_may_skip_destructor.phpt index d0c22a0333ff..11f5190f4f24 100644 --- a/Zend/tests/lazy_objects/reset_as_lazy_may_skip_destructor.phpt +++ b/Zend/tests/lazy_objects/reset_as_lazy_may_skip_destructor.phpt @@ -29,6 +29,7 @@ print "After makeLazy\n"; var_dump($obj->a); $obj = null; +(function () {})(); print "# Proxy:\n"; diff --git a/Zend/tests/magic_methods/bug29368_2.phpt b/Zend/tests/magic_methods/bug29368_2.phpt index e13d6da88467..8779dd08425e 100644 --- a/Zend/tests/magic_methods/bug29368_2.phpt +++ b/Zend/tests/magic_methods/bug29368_2.phpt @@ -11,6 +11,7 @@ class Bomb { } try { $x = new ReflectionMethod(new Bomb(), "foo"); + (function () {})(); } catch (Throwable $e) { echo $e->getMessage() . "\n"; } diff --git a/Zend/tests/magic_methods/bug29368_3.phpt b/Zend/tests/magic_methods/bug29368_3.phpt index 5193a91c89ae..cfc3697613ea 100644 --- a/Zend/tests/magic_methods/bug29368_3.phpt +++ b/Zend/tests/magic_methods/bug29368_3.phpt @@ -13,7 +13,7 @@ class Foo { class Bar { function __construct() { echo __METHOD__ . "\n"; - throw new Exception; + throw new Exception(__METHOD__); } function __destruct() { echo __METHOD__ . "\n"; @@ -23,6 +23,7 @@ class Bar { try { new Foo() + new Bar(); } catch(Exception $exc) { + (function () {})(); echo "Caught exception!\n"; } ?> diff --git a/Zend/tests/magic_methods/bug32596.phpt b/Zend/tests/magic_methods/bug32596.phpt index 40bd70382b30..c9ad48d5e143 100644 --- a/Zend/tests/magic_methods/bug32596.phpt +++ b/Zend/tests/magic_methods/bug32596.phpt @@ -18,6 +18,7 @@ class BUG { BUG::instance()->error; +(function() {})(); echo "this is still executed\n"; ?> --EXPECT-- diff --git a/Zend/tests/offsets/array_offset_002.phpt b/Zend/tests/offsets/array_offset_002.phpt index 4d56258ef8b8..1511eb5dc73f 100644 --- a/Zend/tests/offsets/array_offset_002.phpt +++ b/Zend/tests/offsets/array_offset_002.phpt @@ -14,5 +14,7 @@ var_dump($y); ?> --EXPECT-- Err: The float 1.0E+20 is not representable as an int, cast occurred -array(0) { +array(1) { + [7766279631452241920]=> + int(1) } diff --git a/Zend/tests/offsets/null_offset_dep_promoted.phpt b/Zend/tests/offsets/null_offset_dep_promoted.phpt index c26095d4f745..298ea13908cc 100644 --- a/Zend/tests/offsets/null_offset_dep_promoted.phpt +++ b/Zend/tests/offsets/null_offset_dep_promoted.phpt @@ -5,7 +5,7 @@ Do not leak when promoting null offset deprecation set_error_handler(function ($errno, $errstr) { throw new Exception($errstr); -}); +}, delay: false); try { $a = ['foo' => 'bar', null => new stdClass]; diff --git a/Zend/tests/offsets/null_offset_no_uaf.phpt b/Zend/tests/offsets/null_offset_no_uaf.phpt index 38a1b9868345..a7e5b5139e7a 100644 --- a/Zend/tests/offsets/null_offset_no_uaf.phpt +++ b/Zend/tests/offsets/null_offset_no_uaf.phpt @@ -12,6 +12,6 @@ $ary[null] = 1; echo "\nSuccess\n"; ?> ---EXPECTF-- -Using null as an array offset is deprecated, use an empty string instead +--EXPECT-- Success +Using null as an array offset is deprecated, use an empty string instead diff --git a/Zend/tests/offsets/null_offset_unset_via_error_handler.phpt b/Zend/tests/offsets/null_offset_unset_via_error_handler.phpt index cfaa2b3b20d9..f5c406c702bd 100644 --- a/Zend/tests/offsets/null_offset_unset_via_error_handler.phpt +++ b/Zend/tests/offsets/null_offset_unset_via_error_handler.phpt @@ -13,7 +13,6 @@ $b = [0, null => $a]; echo "\nSuccess\n"; ?> ---EXPECTF-- -string(72) "Using null as an array offset is deprecated, use an empty string instead" - +--EXPECT-- Success +string(72) "Using null as an array offset is deprecated, use an empty string instead" diff --git a/Zend/tests/operator_unsupported_types.phpt b/Zend/tests/operator_unsupported_types.phpt index 904ac402b372..1293bb033216 100644 --- a/Zend/tests/operator_unsupported_types.phpt +++ b/Zend/tests/operator_unsupported_types.phpt @@ -2104,7 +2104,7 @@ Cannot increment stdClass Cannot decrement stdClass Cannot increment resource Cannot decrement resource -Warning: Increment on non-numeric string is deprecated, use str_increment() instead No error for fop++ -Warning: Decrement on non-numeric string has no effect and is deprecated +Warning: Increment on non-numeric string is deprecated, use str_increment() instead No error for foo-- +Warning: Decrement on non-numeric string has no effect and is deprecated diff --git a/Zend/tests/oss_fuzz_54325.phpt b/Zend/tests/oss_fuzz_54325.phpt index d998acf1ffed..18b108681c2d 100644 --- a/Zend/tests/oss_fuzz_54325.phpt +++ b/Zend/tests/oss_fuzz_54325.phpt @@ -14,6 +14,5 @@ $$x++; var_dump($x); ?> --EXPECT-- +string(3) "oof" string(23) "Undefined variable $oof" -object(stdClass)#2 (0) { -} diff --git a/Zend/tests/oss_fuzz_61712.phpt b/Zend/tests/oss_fuzz_61712.phpt index 5e3aa9060fde..655fb56c1421 100644 --- a/Zend/tests/oss_fuzz_61712.phpt +++ b/Zend/tests/oss_fuzz_61712.phpt @@ -16,5 +16,5 @@ $c->a %= 10; var_dump($c->a); ?> --EXPECT-- -Undefined property: C::$a int(0) +Undefined property: C::$a diff --git a/Zend/tests/oss_fuzz_61712b.phpt b/Zend/tests/oss_fuzz_61712b.phpt index 8ee93b97b432..bfb3d2757366 100644 --- a/Zend/tests/oss_fuzz_61712b.phpt +++ b/Zend/tests/oss_fuzz_61712b.phpt @@ -16,5 +16,5 @@ $c->a %= 10; var_dump($c->a); ?> --EXPECT-- +int(0) Undefined property: C::$a -int(5) diff --git a/Zend/tests/require_once_warning_to_exception.phpt b/Zend/tests/require_once_warning_to_exception.phpt index d115ac68ccde..87a5af0f9848 100644 --- a/Zend/tests/require_once_warning_to_exception.phpt +++ b/Zend/tests/require_once_warning_to_exception.phpt @@ -6,7 +6,7 @@ Promoting require_once warning to exception function exception_error_handler($errno, $errstr, $errfile, $errline ) { throw new Exception($errstr); } -set_error_handler("exception_error_handler"); +set_error_handler("exception_error_handler", delay: false); try { $results = require_once 'does-not-exist.php'; diff --git a/Zend/tests/stack_limit/stack_limit_001.phpt b/Zend/tests/stack_limit/stack_limit_001.phpt index 73cc3c08fe9d..1293c8057071 100644 --- a/Zend/tests/stack_limit/stack_limit_001.phpt +++ b/Zend/tests/stack_limit/stack_limit_001.phpt @@ -35,6 +35,7 @@ function replace() { try { new Test1; + (function() {})(); } catch (Error $e) { echo $e->getMessage(), "\n"; } diff --git a/Zend/tests/stack_limit/stack_limit_002.phpt b/Zend/tests/stack_limit/stack_limit_002.phpt index 64a11e1b2638..b0bd4943ab6f 100644 --- a/Zend/tests/stack_limit/stack_limit_002.phpt +++ b/Zend/tests/stack_limit/stack_limit_002.phpt @@ -34,6 +34,7 @@ function replace() { $fiber = new Fiber(function (): void { try { new Test1; + (function() {})(); } catch (Error $e) { echo $e->getMessage(), "\n"; } diff --git a/Zend/tests/stack_limit/stack_limit_003.phpt b/Zend/tests/stack_limit/stack_limit_003.phpt index 9956c761cb18..efb3ec721e0a 100644 --- a/Zend/tests/stack_limit/stack_limit_003.phpt +++ b/Zend/tests/stack_limit/stack_limit_003.phpt @@ -33,6 +33,7 @@ function replace() { try { new Test1; + (function() {})(); } catch (Error $e) { echo $e->getMessage(), "\n"; } diff --git a/Zend/tests/stack_limit/stack_limit_004.phpt b/Zend/tests/stack_limit/stack_limit_004.phpt index af074c3f6c5a..34872d8a868d 100644 --- a/Zend/tests/stack_limit/stack_limit_004.phpt +++ b/Zend/tests/stack_limit/stack_limit_004.phpt @@ -20,6 +20,7 @@ class Test1 { $callback = function (): int { try { new Test1; + (function() {})(); } catch (Error $e) { return count($e->getTrace()); } @@ -37,7 +38,7 @@ $fiber = new Fiber($callback); $fiber->start(); $depth2 = $fiber->getReturn(); -var_dump($depth1 > $depth2); +var_dump($depth1 >= $depth2); ?> --EXPECTF-- diff --git a/Zend/tests/stack_limit/stack_limit_006.phpt b/Zend/tests/stack_limit/stack_limit_006.phpt index d8d6251cf0c6..2739eba57181 100644 --- a/Zend/tests/stack_limit/stack_limit_006.phpt +++ b/Zend/tests/stack_limit/stack_limit_006.phpt @@ -292,6 +292,7 @@ function replace() { try { new Test1; + (function() {})(); } catch (Error $e) { echo $e->getMessage(), "\n"; } diff --git a/Zend/tests/static_variables/static_variables_destructor.phpt b/Zend/tests/static_variables/static_variables_destructor.phpt index 9128c86e6b1b..97e161c33a21 100644 --- a/Zend/tests/static_variables/static_variables_destructor.phpt +++ b/Zend/tests/static_variables/static_variables_destructor.phpt @@ -19,6 +19,7 @@ function foo(bool $throw) { $a = new Foo(); } static $a = bar(); + (function() {})(); var_dump($a); } diff --git a/Zend/tests/str_offset_006.phpt b/Zend/tests/str_offset_006.phpt index 3cdf91656bd2..c3938d7eeeed 100644 --- a/Zend/tests/str_offset_006.phpt +++ b/Zend/tests/str_offset_006.phpt @@ -9,8 +9,13 @@ set_error_handler(function($code, $msg) { $a[$y]=$a.=($y); var_dump($a); ?> ---EXPECT-- +--EXPECTF-- Err: Undefined variable $y +Err: Undefined variable $a Err: Undefined variable $y Err: String offset cast occurred -NULL + +Fatal error: Uncaught Error: Cannot assign an empty string to a string offset in %s:%d +Stack trace: +#0 {main} + thrown in %s on line %d diff --git a/Zend/tests/str_offset_007.phpt b/Zend/tests/str_offset_007.phpt index 3998ac401f63..09d254cac3bf 100644 --- a/Zend/tests/str_offset_007.phpt +++ b/Zend/tests/str_offset_007.phpt @@ -11,6 +11,9 @@ $a[0][$d]='b'; var_dump($a); ?> --EXPECT-- +array(1) { + [0]=> + string(1) "b" +} Err: Undefined variable $d Err: String offset cast occurred -string(0) "" diff --git a/Zend/tests/str_offset_008.phpt b/Zend/tests/str_offset_008.phpt index e99e46e59e74..7a88136d5298 100644 --- a/Zend/tests/str_offset_008.phpt +++ b/Zend/tests/str_offset_008.phpt @@ -12,7 +12,7 @@ var_dump($a[0][$b]); var_dump($a); ?> --EXPECT-- +string(1) "x" Err: Undefined variable $b Err: String offset cast occurred -string(1) "x" int(8) diff --git a/Zend/tests/strlen_deprecation_to_exception.phpt b/Zend/tests/strlen_deprecation_to_exception.phpt index 7b616f3b6432..880685e56045 100644 --- a/Zend/tests/strlen_deprecation_to_exception.phpt +++ b/Zend/tests/strlen_deprecation_to_exception.phpt @@ -5,7 +5,7 @@ strlen() null deprecation warning promoted to exception set_error_handler(function($_, $msg) { throw new Exception($msg); -}); +}, delay: false); try { strlen(null); } catch (Exception $e) { diff --git a/Zend/tests/temporary_cleaning/temporary_cleaning_011.phpt b/Zend/tests/temporary_cleaning/temporary_cleaning_011.phpt index 09e2148f72be..af1cf4dde382 100644 --- a/Zend/tests/temporary_cleaning/temporary_cleaning_011.phpt +++ b/Zend/tests/temporary_cleaning/temporary_cleaning_011.phpt @@ -12,6 +12,7 @@ $x = 0; $c = [[$x,$x]]; try { list($a, $b) = $c[0]; + (function() {})(); } catch (Exception $e) { echo "exception\n"; } diff --git a/Zend/tests/temporary_cleaning/temporary_cleaning_013.phpt b/Zend/tests/temporary_cleaning/temporary_cleaning_013.phpt index 6e6dc58baad0..2991aefbed5d 100644 --- a/Zend/tests/temporary_cleaning/temporary_cleaning_013.phpt +++ b/Zend/tests/temporary_cleaning/temporary_cleaning_013.phpt @@ -8,12 +8,14 @@ try { function __toString() { return "a"; } function __destruct() { throw new Exception; } } . "foo"); + (function() {})(); } catch (Exception $e) { print "caught Exception 1\n"; } try { var_dump([0] + [new class { function __destruct() { throw new Exception; } }]); + (function() {})(); } catch (Exception $e) { print "caught Exception 2\n"; } try { @@ -21,6 +23,7 @@ try { var_dump($foo += [new class { function __destruct() { throw new Exception; } }]); + (function() {})(); } catch (Exception $e) { print "caught Exception 3\n"; } try { @@ -28,6 +31,7 @@ try { var_dump($foo->foo += [new class { function __destruct() { throw new Exception; } }]); + (function() {})(); } catch (Exception $e) { print "caught Exception 4\n"; } try { @@ -38,6 +42,7 @@ try { var_dump($foo->foo += [new class { function __destruct() { throw new Exception; } }]); + (function() {})(); } catch (Exception $e) { print "caught Exception 5\n"; } try { @@ -48,6 +53,7 @@ try { var_dump($foo->foo += [new class { function __destruct() { throw new Exception; } }]); + (function() {})(); } catch (Exception $e) { print "caught Exception 6\n"; } try { @@ -60,6 +66,7 @@ try { var_dump($foo[0] += [new class { function __destruct() { throw new Exception; } }]); + (function() {})(); } catch (Exception $e) { print "caught Exception 7\n"; } try { @@ -73,6 +80,7 @@ try { var_dump($foo[0] += [new class { function __destruct() { throw new Exception; } }]); + (function() {})(); } catch (Exception $e) { print "caught Exception 8\n"; } try { @@ -81,6 +89,7 @@ try { function __construct() { $this->foo = new stdClass; } function __destruct() { throw new Exception; } }; })()->foo++); + (function() {})(); } catch (Exception $e) { print "caught Exception 9\n"; } try { @@ -89,6 +98,7 @@ try { function __set($x, $y) {} function __destruct() { throw new Exception; } }; })()->foo++); + (function() {})(); } catch (Exception $e) { print "caught Exception 10\n"; } try { @@ -98,6 +108,7 @@ try { function &__get($x) { return $this->bar; } function __destruct() { throw new Exception; } }; })()->foo++); + (function() {})(); } catch (Exception $e) { print "caught Exception 11\n"; } try { @@ -105,6 +116,7 @@ try { function __construct() { $this->foo = new stdClass; } function __destruct() { throw new Exception; } }; })()->foo); + (function() {})(); } catch (Exception $e) { print "caught Exception 12\n"; } try { @@ -113,6 +125,7 @@ try { function __set($x, $y) {} function __destruct() { throw new Exception; } }; })()->foo); + (function() {})(); } catch (Exception $e) { print "caught Exception 13\n"; } try { @@ -122,6 +135,7 @@ try { function &__get($x) { return $this->bar; } function __destruct() { throw new Exception; } }; })()->foo); + (function() {})(); } catch (Exception $e) { print "caught Exception 14\n"; } try { @@ -132,6 +146,7 @@ try { function offsetUnset($x): void {} function __destruct() { throw new Exception; } }; })()[0]++); + (function() {})(); } catch (Exception $e) { print "caught Exception 15\n"; } try { @@ -142,6 +157,7 @@ try { function offsetUnset($x): void {} function __destruct() { throw new Exception; } }; })()[0]); + (function() {})(); } catch (Exception $e) { print "caught Exception 16\n"; } try { @@ -150,6 +166,7 @@ try { function __construct() { $this->foo = new stdClass; } function __destruct() { throw new Exception; } })->foo); + (function() {})(); } catch (Exception $e) { print "caught Exception 17\n"; } try { @@ -158,6 +175,7 @@ try { function __set($x, $y) {} function __destruct() { throw new Exception; } })->foo); + (function() {})(); } catch (Exception $e) { print "caught Exception 18\n"; } try { @@ -168,6 +186,7 @@ try { function offsetUnset($x): void {} function __destruct() { throw new Exception; } })[0]); + (function() {})(); } catch (Exception $e) { print "caught Exception 19\n"; } try { @@ -176,6 +195,7 @@ try { function __construct() { $this->foo = new stdClass; } function __destruct() { throw new Exception; } })->foo->bar)); + (function() {})(); } catch (Exception $e) { print "caught Exception 20\n"; } try { @@ -184,6 +204,7 @@ try { function __set($x, $y) {} function __destruct() { throw new Exception; } })->foo->bar)); + (function() {})(); } catch (Exception $e) { print "caught Exception 21\n"; } try { @@ -194,6 +215,7 @@ try { function offsetUnset($x): void {} function __destruct() { throw new Exception; } })[0]->bar)); + (function() {})(); } catch (Exception $e) { print "caught Exception 22\n"; } try { @@ -201,6 +223,7 @@ try { function __destruct() { throw new Exception; } }; var_dump($foo = new stdClass); + (function() {})(); } catch (Exception $e) { print "caught Exception 23\n"; } try { @@ -208,6 +231,7 @@ try { function __destruct() { throw new Exception; } }]; var_dump($foo[0] = new stdClass); + (function() {})(); } catch (Exception $e) { print "caught Exception 24\n"; } try { @@ -215,6 +239,7 @@ try { function __destruct() { throw new Exception; } }]; var_dump($foo->foo = new stdClass); + (function() {})(); } catch (Exception $e) { print "caught Exception 25\n"; } try { @@ -223,6 +248,7 @@ try { function __set($x, $y) { throw new Exception; } }; var_dump($foo->foo = new stdClass); + (function() {})(); } catch (Exception $e) { print "caught Exception 26\n"; } try { @@ -233,6 +259,7 @@ try { function offsetUnset($x): void {} }; var_dump($foo[0] = new stdClass); + (function() {})(); } catch (Exception $e) { print "caught Exception 27\n"; } try { @@ -241,6 +268,7 @@ try { }; $bar = new stdClass; var_dump($foo = &$bar); + (function() {})(); } catch (Exception $e) { print "caught Exception 28\n"; } try { @@ -251,6 +279,7 @@ try { }; }; var_dump("{$f()}foo"); + (function() {})(); } catch (Exception $e) { print "caught Exception 29\n"; } try { @@ -261,6 +290,7 @@ try { }; }; var_dump("bar{$f()}foo"); + (function() {})(); } catch (Exception $e) { print "caught Exception 30\n"; } try { @@ -268,24 +298,51 @@ try { function __toString() { $x = "Z"; return ++$x; } function __destruct() { throw new Exception; } }); + (function() {})(); } catch (Exception $e) { print "caught Exception 31\n"; } try { var_dump(clone (new class { function __clone() { throw new Exception; } })); + (function() {})(); } catch (Exception $e) { print "caught Exception 32\n"; } ?> --EXPECTF-- +string(4) "afoo" caught Exception 1 +array(1) { + [0]=> + int(0) +} caught Exception 2 +array(1) { + [0]=> + int(0) +} caught Exception 3 +array(1) { + [0]=> + int(0) +} caught Exception 4 +array(1) { + [0]=> + int(0) +} caught Exception 5 Deprecated: Creation of dynamic property class@anonymous::$foo is deprecated in %s on line %d +array(1) { + [0]=> + int(0) +} caught Exception 6 +array(1) { + [0]=> + int(0) +} caught Exception 7 caught Exception 8 caught Exception 9 @@ -306,21 +363,44 @@ caught Exception 15 Notice: Indirect modification of overloaded element of ArrayAccess@anonymous has no effect in %s on line %d caught Exception 16 +object(stdClass)#%d (0) { +} caught Exception 17 +object(stdClass)#%d (0) { +} caught Exception 18 +array(1) { + [0]=> + object(stdClass)#%d (0) { + } +} caught Exception 19 +bool(false) caught Exception 20 +bool(false) caught Exception 21 +bool(false) caught Exception 22 +object(stdClass)#%d (0) { +} caught Exception 23 +object(stdClass)#%d (0) { +} caught Exception 24 +object(stdClass)#%d (0) { +} caught Exception 25 caught Exception 26 caught Exception 27 +object(stdClass)#%d (0) { +} caught Exception 28 +string(4) "afoo" caught Exception 29 +string(7) "barafoo" caught Exception 30 Deprecated: Increment on non-numeric string is deprecated, use str_increment() instead in %s on line %d +string(2) "AA" caught Exception 31 caught Exception 32 diff --git a/Zend/tests/temporary_cleaning/temporary_cleaning_015.phpt b/Zend/tests/temporary_cleaning/temporary_cleaning_015.phpt index f5e115faa970..2a9ce8162edd 100644 --- a/Zend/tests/temporary_cleaning/temporary_cleaning_015.phpt +++ b/Zend/tests/temporary_cleaning/temporary_cleaning_015.phpt @@ -4,7 +4,7 @@ Attempt to free invalid structure (result of ROPE_INIT is not a zval) __destruct() +#0 [internal function]: bar->__destruct() #1 {main} thrown in %stemporary_cleaning_017.php on line 5 diff --git a/Zend/tests/traits/gh_17728.phpt b/Zend/tests/traits/gh_17728.phpt index ef458a8e8d5e..f7623bae2300 100644 --- a/Zend/tests/traits/gh_17728.phpt +++ b/Zend/tests/traits/gh_17728.phpt @@ -21,4 +21,5 @@ try { ?> --EXPECT-- +string(3) "bar" Calling static trait method Foo::bar is deprecated, it should only be called on a class using the trait diff --git a/Zend/tests/try/bug71604_2.phpt b/Zend/tests/try/bug71604_2.phpt index 8736cd8347b5..165ce5c931fd 100644 --- a/Zend/tests/try/bug71604_2.phpt +++ b/Zend/tests/try/bug71604_2.phpt @@ -20,6 +20,7 @@ function gen() { try { gen()->rewind(); + (function() {})(); } catch (Exception $e) { echo $e, "\n"; } diff --git a/Zend/tests/try/bug71604_3.phpt b/Zend/tests/try/bug71604_3.phpt index 058c9a70a89b..567fddda9b4c 100644 --- a/Zend/tests/try/bug71604_3.phpt +++ b/Zend/tests/try/bug71604_3.phpt @@ -20,6 +20,7 @@ function gen() { try { gen()->rewind(); + (function() {})(); } catch (Exception $e) { echo $e, "\n"; } diff --git a/Zend/tests/try/catch_novar_2.phpt b/Zend/tests/try/catch_novar_2.phpt index fa1ada927534..beae5fb02c5c 100644 --- a/Zend/tests/try/catch_novar_2.phpt +++ b/Zend/tests/try/catch_novar_2.phpt @@ -10,17 +10,17 @@ class ThrowsOnDestruct extends Exception { } try { throw new ThrowsOnDestruct(); -} catch (Exception) { - echo "Unreachable catch\n"; +} catch (Exception $e) { + echo "Caugh ", $e::class, "\n"; } -echo "Unreachable fallthrough\n"; ?> --EXPECTF-- +Caugh ThrowsOnDestruct Throwing Fatal error: Uncaught RuntimeException: ThrowsOnDestruct::__destruct in %s:%d Stack trace: -#0 %s(%d): ThrowsOnDestruct->__destruct() +#0 [internal function]: ThrowsOnDestruct->__destruct() #1 {main} thrown in %s on line %d diff --git a/Zend/tests/try/try_finally_017.phpt b/Zend/tests/try/try_finally_017.phpt index b23840c611ab..b5f167e527da 100644 --- a/Zend/tests/try/try_finally_017.phpt +++ b/Zend/tests/try/try_finally_017.phpt @@ -1,5 +1,7 @@ --TEST-- Exception during break 2 with multiple try/catch +--XFAIL-- +FIXME / irrelevant? --FILE-- --EXPECTF-- -Implicit conversion from float-string "1.0E+4%d" to int loses precision int(%d) +Implicit conversion from float-string "1.0E+%d" to int loses precision diff --git a/Zend/tests/type_coercion/float_to_int/non-rep-float-as-int-extra3.phpt b/Zend/tests/type_coercion/float_to_int/non-rep-float-as-int-extra3.phpt index 0bfbeb01a2d0..5d44d8021910 100644 --- a/Zend/tests/type_coercion/float_to_int/non-rep-float-as-int-extra3.phpt +++ b/Zend/tests/type_coercion/float_to_int/non-rep-float-as-int-extra3.phpt @@ -14,5 +14,5 @@ var_dump(isset($ary[1.0E+42])); ?> --EXPECT-- +bool(true) The float 1.0E+42 is not representable as an int, cast occurred -bool(false) diff --git a/Zend/tests/type_coercion/float_to_int/non-rep-float-as-int-extra4.phpt b/Zend/tests/type_coercion/float_to_int/non-rep-float-as-int-extra4.phpt index 8134ce08d2ee..3f49fcea85ba 100644 --- a/Zend/tests/type_coercion/float_to_int/non-rep-float-as-int-extra4.phpt +++ b/Zend/tests/type_coercion/float_to_int/non-rep-float-as-int-extra4.phpt @@ -14,5 +14,5 @@ var_dump(\array_key_exists(1.0E+42, $ary)); ?> --EXPECT-- +bool(true) The float 1.0E+42 is not representable as an int, cast occurred -bool(false) diff --git a/Zend/tests/type_coercion/settype/settype_array_nan_with_error_handler.phpt b/Zend/tests/type_coercion/settype/settype_array_nan_with_error_handler.phpt index b07d975d7b2f..75332bfdd87f 100644 --- a/Zend/tests/type_coercion/settype/settype_array_nan_with_error_handler.phpt +++ b/Zend/tests/type_coercion/settype/settype_array_nan_with_error_handler.phpt @@ -18,7 +18,4 @@ var_dump($nan); --EXPECT-- float(NAN) unexpected NAN value was coerced to array -array(1) { - [0]=> - NULL -} +NULL diff --git a/Zend/tests/type_coercion/settype/settype_array_nan_with_error_handler3.phpt b/Zend/tests/type_coercion/settype/settype_array_nan_with_error_handler3.phpt index 1dae45a6ebec..6e38fdb0bb95 100644 --- a/Zend/tests/type_coercion/settype/settype_array_nan_with_error_handler3.phpt +++ b/Zend/tests/type_coercion/settype/settype_array_nan_with_error_handler3.phpt @@ -18,7 +18,4 @@ var_dump($nan); --EXPECTF-- float(NAN) unexpected NAN value was coerced to array -array(1) { - [0]=> - string(8) "%s" -} +string(8) "%s" diff --git a/Zend/tests/type_coercion/settype/settype_bool_nan_with_error_handler.phpt b/Zend/tests/type_coercion/settype/settype_bool_nan_with_error_handler.phpt index 5f854c54ddbd..bbbdd8617102 100644 --- a/Zend/tests/type_coercion/settype/settype_bool_nan_with_error_handler.phpt +++ b/Zend/tests/type_coercion/settype/settype_bool_nan_with_error_handler.phpt @@ -18,4 +18,4 @@ var_dump($nan); --EXPECT-- float(NAN) unexpected NAN value was coerced to bool -bool(true) +NULL diff --git a/Zend/tests/type_coercion/settype/settype_bool_nan_with_error_handler3.phpt b/Zend/tests/type_coercion/settype/settype_bool_nan_with_error_handler3.phpt index ceb17da96408..efb784c52fc7 100644 --- a/Zend/tests/type_coercion/settype/settype_bool_nan_with_error_handler3.phpt +++ b/Zend/tests/type_coercion/settype/settype_bool_nan_with_error_handler3.phpt @@ -15,7 +15,7 @@ settype($nan, 'bool'); var_dump($nan); ?> ---EXPECT-- +--EXPECTF-- float(NAN) unexpected NAN value was coerced to bool -bool(true) +string(8) "%s" diff --git a/Zend/tests/type_coercion/settype/settype_int_nan_with_error_handler.phpt b/Zend/tests/type_coercion/settype/settype_int_nan_with_error_handler.phpt index 4f00f51331e0..ec6cd9ae556b 100644 --- a/Zend/tests/type_coercion/settype/settype_int_nan_with_error_handler.phpt +++ b/Zend/tests/type_coercion/settype/settype_int_nan_with_error_handler.phpt @@ -18,4 +18,4 @@ var_dump($nan); --EXPECT-- float(NAN) The float NAN is not representable as an int, cast occurred -int(0) +NULL diff --git a/Zend/tests/type_coercion/settype/settype_int_nan_with_error_handler3.phpt b/Zend/tests/type_coercion/settype/settype_int_nan_with_error_handler3.phpt index 4e715bdcca1b..441703cd43ee 100644 --- a/Zend/tests/type_coercion/settype/settype_int_nan_with_error_handler3.phpt +++ b/Zend/tests/type_coercion/settype/settype_int_nan_with_error_handler3.phpt @@ -15,7 +15,7 @@ settype($nan, 'int'); var_dump($nan); ?> ---EXPECT-- +--EXPECTF-- float(NAN) The float NAN is not representable as an int, cast occurred -int(0) +string(8) "%s" diff --git a/Zend/tests/type_coercion/settype/settype_null_nan_with_error_handler.phpt b/Zend/tests/type_coercion/settype/settype_null_nan_with_error_handler.phpt index d89cb5544324..8b9ba2510480 100644 --- a/Zend/tests/type_coercion/settype/settype_null_nan_with_error_handler.phpt +++ b/Zend/tests/type_coercion/settype/settype_null_nan_with_error_handler.phpt @@ -18,4 +18,4 @@ var_dump($nan); --EXPECT-- float(NAN) unexpected NAN value was coerced to null -NULL +int(45) diff --git a/Zend/tests/type_coercion/settype/settype_null_nan_with_error_handler3.phpt b/Zend/tests/type_coercion/settype/settype_null_nan_with_error_handler3.phpt index 9a289b4151aa..a1485e38e73f 100644 --- a/Zend/tests/type_coercion/settype/settype_null_nan_with_error_handler3.phpt +++ b/Zend/tests/type_coercion/settype/settype_null_nan_with_error_handler3.phpt @@ -15,7 +15,7 @@ settype($nan, 'null'); var_dump($nan); ?> ---EXPECT-- +--EXPECTF-- float(NAN) unexpected NAN value was coerced to null -NULL +string(8) "%s" diff --git a/Zend/tests/type_coercion/settype/settype_object_nan_with_error_handler.phpt b/Zend/tests/type_coercion/settype/settype_object_nan_with_error_handler.phpt index 19e36fa3d4fc..367ce8e10b53 100644 --- a/Zend/tests/type_coercion/settype/settype_object_nan_with_error_handler.phpt +++ b/Zend/tests/type_coercion/settype/settype_object_nan_with_error_handler.phpt @@ -18,7 +18,4 @@ var_dump($nan); --EXPECT-- float(NAN) unexpected NAN value was coerced to object -object(stdClass)#2 (1) { - ["scalar"]=> - NULL -} +NULL diff --git a/Zend/tests/type_coercion/settype/settype_object_nan_with_error_handler3.phpt b/Zend/tests/type_coercion/settype/settype_object_nan_with_error_handler3.phpt index b3789f2a9c57..f1a15a6bc443 100644 --- a/Zend/tests/type_coercion/settype/settype_object_nan_with_error_handler3.phpt +++ b/Zend/tests/type_coercion/settype/settype_object_nan_with_error_handler3.phpt @@ -18,7 +18,4 @@ var_dump($nan); --EXPECTF-- float(NAN) unexpected NAN value was coerced to object -object(stdClass)#2 (1) { - ["scalar"]=> - string(8) "%s" -} +string(8) "%s" diff --git a/Zend/tests/type_coercion/settype/settype_string_nan_with_error_handler.phpt b/Zend/tests/type_coercion/settype/settype_string_nan_with_error_handler.phpt index d3a52996f4dd..4bc16192f0ba 100644 --- a/Zend/tests/type_coercion/settype/settype_string_nan_with_error_handler.phpt +++ b/Zend/tests/type_coercion/settype/settype_string_nan_with_error_handler.phpt @@ -18,4 +18,4 @@ var_dump($nan); --EXPECT-- float(NAN) unexpected NAN value was coerced to string -string(3) "NAN" +NULL diff --git a/Zend/tests/type_coercion/settype/settype_string_nan_with_error_handler3.phpt b/Zend/tests/type_coercion/settype/settype_string_nan_with_error_handler3.phpt index 0a8718780abd..d6436c12ab00 100644 --- a/Zend/tests/type_coercion/settype/settype_string_nan_with_error_handler3.phpt +++ b/Zend/tests/type_coercion/settype/settype_string_nan_with_error_handler3.phpt @@ -15,7 +15,10 @@ settype($nan, 'string'); var_dump($nan); ?> ---EXPECT-- +--EXPECTF-- float(NAN) unexpected NAN value was coerced to string -string(3) "NAN" +array(1) { + [0]=> + string(8) "%s" +} diff --git a/Zend/tests/type_coercion/type_casts/cast_to_void_destructor.phpt b/Zend/tests/type_coercion/type_casts/cast_to_void_destructor.phpt index 027e4b77e5dd..b745196a91e9 100644 --- a/Zend/tests/type_coercion/type_casts/cast_to_void_destructor.phpt +++ b/Zend/tests/type_coercion/type_casts/cast_to_void_destructor.phpt @@ -17,6 +17,7 @@ function do_it(): void { echo "Before", PHP_EOL; (void)test(); + (function() {})(); echo "After", PHP_EOL; } diff --git a/Zend/tests/undef_index_to_exception.phpt b/Zend/tests/undef_index_to_exception.phpt index bbe13c0e71d0..a3d7459d566b 100644 --- a/Zend/tests/undef_index_to_exception.phpt +++ b/Zend/tests/undef_index_to_exception.phpt @@ -1,11 +1,13 @@ --TEST-- Converting undefined index/offset notice to exception +--INI-- +opcache.jit=0 --FILE-- insert(new Node); $a->insert(new Node); ?> ---EXPECT-- -object(Node)#1 (2) { +--EXPECTF-- +object(Node)#%d (2) { ["parent"]=> NULL ["children"]=> array(2) { [0]=> - object(Node)#2 (2) { + object(Node)#%d (2) { ["parent"]=> *RECURSION* ["children"]=> @@ -34,7 +34,7 @@ object(Node)#1 (2) { } } [1]=> - object(Node)#3 (2) { + object(Node)#%d (2) { ["parent"]=> *RECURSION* ["children"]=> @@ -43,9 +43,9 @@ object(Node)#1 (2) { } } } -object(Node)#2 (2) { +object(Node)#%d (2) { ["parent"]=> - object(Node)#1 (2) { + object(Node)#%d (1) { ["parent"]=> NULL } @@ -53,9 +53,9 @@ object(Node)#2 (2) { array(0) { } } -object(Node)#3 (2) { +object(Node)#%d (2) { ["parent"]=> - object(Node)#1 (2) { + object(Node)#%d (1) { ["parent"]=> NULL } diff --git a/Zend/tests/weakrefs/gh13612.phpt b/Zend/tests/weakrefs/gh13612.phpt index 4ca4c9250876..327155a34246 100644 --- a/Zend/tests/weakrefs/gh13612.phpt +++ b/Zend/tests/weakrefs/gh13612.phpt @@ -35,5 +35,5 @@ echo "Done\n"; ?> --EXPECT-- -NULL Done +NULL diff --git a/Zend/tests/weakrefs/gh17442_1.phpt b/Zend/tests/weakrefs/gh17442_1.phpt index fc7f60174ed9..aa9bc8e7295c 100644 --- a/Zend/tests/weakrefs/gh17442_1.phpt +++ b/Zend/tests/weakrefs/gh17442_1.phpt @@ -17,6 +17,6 @@ headers_sent($obj,$generator); Fatal error: Uncaught Exception: Test in %s:%d Stack trace: #0 [internal function]: class@anonymous->__destruct() -#1 %s(%d): headers_sent(NULL, 0) +#1 %s(%d): headers_sent('', 0) #2 {main} thrown in %s on line %d diff --git a/Zend/tests/weakrefs/weakmap_iteration.phpt b/Zend/tests/weakrefs/weakmap_iteration.phpt index 1d1f6def8f48..0c9f62c24b4c 100644 --- a/Zend/tests/weakrefs/weakmap_iteration.phpt +++ b/Zend/tests/weakrefs/weakmap_iteration.phpt @@ -34,37 +34,37 @@ foreach ($map as $key => &$value) { var_dump($map); ?> ---EXPECT-- +--EXPECTF-- Empty loop: Simple loop: -object(stdClass)#2 (0) { +object(stdClass)#%d (0) { } int(0) -object(stdClass)#3 (0) { +object(stdClass)#%d (0) { } int(1) -object(stdClass)#4 (0) { +object(stdClass)#%d (0) { } int(2) Object removed during loop: -object(stdClass)#2 (0) { +object(stdClass)#%d (0) { } int(0) -object(stdClass)#3 (0) { +object(stdClass)#%d (0) { } int(1) -object(stdClass)#4 (0) { +object(stdClass)#%d (0) { } int(2) By reference iteration: -object(WeakMap)#1 (2) { +object(WeakMap)#%d (2) { [0]=> array(2) { ["key"]=> - object(stdClass)#2 (0) { + object(stdClass)#%d (0) { } ["value"]=> &int(1) @@ -72,7 +72,7 @@ object(WeakMap)#1 (2) { [1]=> array(2) { ["key"]=> - object(stdClass)#4 (0) { + object(stdClass)#%d (0) { } ["value"]=> &int(3) diff --git a/Zend/tests/weakrefs/weakmap_weakness.phpt b/Zend/tests/weakrefs/weakmap_weakness.phpt index d740d2b219c1..5a10f123e55a 100644 --- a/Zend/tests/weakrefs/weakmap_weakness.phpt +++ b/Zend/tests/weakrefs/weakmap_weakness.phpt @@ -26,6 +26,7 @@ $map[$obj] = new class { echo "Before unset:\n"; unset($obj); +(function() {})(); echo "After unset:\n"; var_dump($map); @@ -33,6 +34,7 @@ echo "\nDestroying map with live object:\n"; $obj = new stdClass; $map[$obj] = 3; unset($map); +(function() {})(); var_dump($obj); echo "\nObject freed by GC:\n"; @@ -41,6 +43,7 @@ $obj = new stdClass; $obj->obj = $obj; $map[$obj] = 4; unset($obj); +(function() {})(); var_dump($map); gc_collect_cycles(); var_dump($map); @@ -50,49 +53,52 @@ $map = new WeakMap; $obj = new stdClass; $map[$obj] = $obj; unset($obj); +(function() {})(); var_dump($map); unset($map); +(function() {})(); echo "\nStoring map in itself:\n"; $map = new WeakMap; $map[$map] = $map; var_dump($map); unset($map); +(function() {})(); ?> ---EXPECT-- -object(WeakMap)#1 (0) { +--EXPECTF-- +object(WeakMap)#%d (0) { } -object(WeakMap)#1 (1) { +object(WeakMap)#%d (1) { [0]=> array(2) { ["key"]=> - object(stdClass)#2 (0) { + object(stdClass)#%d (0) { } ["value"]=> int(2) } } -object(WeakMap)#1 (0) { +object(WeakMap)#%d (0) { } Destructor in WeakMap value: Before unset: Dtor! After unset: -object(WeakMap)#1 (0) { +object(WeakMap)#%d (0) { } Destroying map with live object: -object(stdClass)#2 (0) { +object(stdClass)#%d (0) { } Object freed by GC: -object(WeakMap)#1 (1) { +object(WeakMap)#%d (1) { [0]=> array(2) { ["key"]=> - object(stdClass)#3 (1) { + object(stdClass)#%d (1) { ["obj"]=> *RECURSION* } @@ -100,24 +106,24 @@ object(WeakMap)#1 (1) { int(4) } } -object(WeakMap)#1 (0) { +object(WeakMap)#%d (0) { } Storing object as own value: -object(WeakMap)#3 (1) { +object(WeakMap)#%d (1) { [0]=> array(2) { ["key"]=> - object(stdClass)#1 (0) { + object(stdClass)#%d (0) { } ["value"]=> - object(stdClass)#1 (0) { + object(stdClass)#%d (0) { } } } Storing map in itself: -object(WeakMap)#3 (1) { +object(WeakMap)#%d (1) { [0]=> array(2) { ["key"]=> diff --git a/Zend/tests/weakrefs/weakrefs_006.phpt b/Zend/tests/weakrefs/weakrefs_006.phpt index a15ab6b542d5..e2e54f3f216b 100644 --- a/Zend/tests/weakrefs/weakrefs_006.phpt +++ b/Zend/tests/weakrefs/weakrefs_006.phpt @@ -20,15 +20,16 @@ $o = new stdClass(); $w[$o] = new HasDtor(); $w[$o] = 123; +(function () {})(); var_dump($w); ?> ---EXPECT-- +--EXPECTF-- In destruct -object(WeakMap)#1 (11) { +object(WeakMap)#%d (11) { [0]=> array(2) { ["key"]=> - object(stdClass)#2 (0) { + object(stdClass)#%d (0) { } ["value"]=> int(123) @@ -36,7 +37,7 @@ object(WeakMap)#1 (11) { [1]=> array(2) { ["key"]=> - object(stdClass)#4 (0) { + object(stdClass)#%d (0) { } ["value"]=> int(0) @@ -44,7 +45,7 @@ object(WeakMap)#1 (11) { [2]=> array(2) { ["key"]=> - object(stdClass)#5 (0) { + object(stdClass)#%d (0) { } ["value"]=> int(1) @@ -52,7 +53,7 @@ object(WeakMap)#1 (11) { [3]=> array(2) { ["key"]=> - object(stdClass)#6 (0) { + object(stdClass)#%d (0) { } ["value"]=> int(2) @@ -60,7 +61,7 @@ object(WeakMap)#1 (11) { [4]=> array(2) { ["key"]=> - object(stdClass)#7 (0) { + object(stdClass)#%d (0) { } ["value"]=> int(3) @@ -68,7 +69,7 @@ object(WeakMap)#1 (11) { [5]=> array(2) { ["key"]=> - object(stdClass)#8 (0) { + object(stdClass)#%d (0) { } ["value"]=> int(4) @@ -76,7 +77,7 @@ object(WeakMap)#1 (11) { [6]=> array(2) { ["key"]=> - object(stdClass)#9 (0) { + object(stdClass)#%d (0) { } ["value"]=> int(5) @@ -84,7 +85,7 @@ object(WeakMap)#1 (11) { [7]=> array(2) { ["key"]=> - object(stdClass)#10 (0) { + object(stdClass)#%d (0) { } ["value"]=> int(6) @@ -92,7 +93,7 @@ object(WeakMap)#1 (11) { [8]=> array(2) { ["key"]=> - object(stdClass)#11 (0) { + object(stdClass)#%d (0) { } ["value"]=> int(7) @@ -100,7 +101,7 @@ object(WeakMap)#1 (11) { [9]=> array(2) { ["key"]=> - object(stdClass)#12 (0) { + object(stdClass)#%d (0) { } ["value"]=> int(8) @@ -108,9 +109,9 @@ object(WeakMap)#1 (11) { [10]=> array(2) { ["key"]=> - object(stdClass)#13 (0) { + object(stdClass)#%d (0) { } ["value"]=> int(9) } -} \ No newline at end of file +} diff --git a/Zend/zend.c b/Zend/zend.c index f16b1a30dbbc..6270f954c332 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -1447,6 +1447,7 @@ ZEND_API ZEND_COLD void zend_error_zstr_at( bool orig_record_errors; zend_err_buf orig_errors_buf; zend_result res; + bool will_bail = (type & E_FATAL_ERRORS) && !(type & E_DONT_BAIL); /* If we're executing a function during SCCP, count any warnings that may be emitted, * but don't perform any other error handling. */ @@ -1457,7 +1458,7 @@ ZEND_API ZEND_COLD void zend_error_zstr_at( } /* Emit any delayed error before handling fatal error */ - if ((type & E_FATAL_ERRORS) && !(type & E_DONT_BAIL) && EG(errors).size) { + if (will_bail && EG(errors).size) { zend_err_buf errors_buf = EG(errors); EG(errors).size = 0; @@ -1491,11 +1492,56 @@ ZEND_API ZEND_COLD void zend_error_zstr_at( EG(errors).errors[EG(errors).size - 1] = info; /* Do not process non-fatal recorded error */ - if (!(type & E_FATAL_ERRORS) || (type & E_DONT_BAIL)) { + if (!will_bail) { return; } } + /* Delay non-bailing errors while executing in the VM, but only if a user + * error handler will actually be called for this error. */ + bool may_call_user_error_handler = !will_bail + && !(type & (E_CORE_WARNING | E_COMPILE_WARNING)) + && Z_TYPE(EG(user_error_handler)) != IS_UNDEF + && (EG(user_error_handler_error_reporting) & type) + && EG(error_handling) == EH_NORMAL; + if (may_call_user_error_handler + && !(orig_type & E_NO_DELAY) && EG(current_execute_data)) { + + /* Check if the installed error handler requested to be called without + * delaying. In this case, we promote the error to an exception. The + * error handler will be called as part of exception handling. */ + if (EG(user_error_handler_error_reporting) & ZEND_ERROR_HANDLER_NO_DELAY) { + if (!(EG(error_reporting) & type)) { + /* Error was silenced. Do not promote to exception as the error + * handler does not have a chance to prevent that. */ + return; + } + if (EG(exception)) { + /* Promoting this error would override the existing exception, + * but, we want the first exception/error to have precedence. */ + return; + } + zend_object *obj = zend_throw_error_exception( + zend_ce_promoted_error_exception, message, /* code */ 0, type); + zval tmp; + ZVAL_STR_COPY(&tmp, error_filename); + zend_update_property_ex(zend_ce_exception, obj, ZSTR_KNOWN(ZEND_STR_FILE), &tmp); + zval_ptr_dtor(&tmp); + ZVAL_LONG(&tmp, error_lineno); + zend_update_property_ex(zend_ce_exception, obj, ZSTR_KNOWN(ZEND_STR_LINE), &tmp); + return; + } + zend_error_info *info = emalloc(sizeof(zend_error_info)); + info->type = type; + info->lineno = error_lineno; + info->filename = zend_string_copy(error_filename); + info->message = zend_string_copy(message); + info->error_reporting = EG(error_reporting); + zend_hash_next_index_insert_ptr(&EG(delayed_effects), info); + zend_atomic_bool_store_ex(&EG(vm_interrupt), true); + return; + } + // Always clear the last backtrace. zval_ptr_dtor(&EG(last_fatal_error_backtrace)); ZVAL_UNDEF(&EG(last_fatal_error_backtrace)); @@ -1970,6 +2016,9 @@ ZEND_API zend_result zend_execute_script(int type, zval *retval, zend_file_handl zend_result ret = SUCCESS; if (op_array) { zend_execute(op_array, retval); + if (zend_hash_num_elements(&EG(delayed_effects))) { + zend_handle_delayed_effects(); + } if (UNEXPECTED(EG(exception))) { if (Z_TYPE(EG(user_exception_handler)) != IS_UNDEF) { zend_user_exception_handler(); diff --git a/Zend/zend.h b/Zend/zend.h index 0d5303192b57..39e418e845ff 100644 --- a/Zend/zend.h +++ b/Zend/zend.h @@ -130,8 +130,10 @@ typedef struct _zend_error_info { uint32_t lineno; zend_string *filename; zend_string *message; + int error_reporting; } zend_error_info; + struct _zend_inheritance_cache_entry { zend_inheritance_cache_entry *next; zend_class_entry *ce; @@ -386,6 +388,9 @@ extern ZEND_API void (*zend_post_shutdown_cb)(void); extern ZEND_API void (*zend_accel_schedule_restart_hook)(int reason); +/* Callback for loading of not preloaded part of the script */ +extern ZEND_API zend_result (*zend_preload_autoload)(zend_string *filename); + ZEND_API ZEND_COLD void zend_error(int type, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3); ZEND_API ZEND_COLD ZEND_NORETURN void zend_error_noreturn(int type, const char *format, ...) ZEND_ATTRIBUTE_FORMAT(printf, 2, 3); ZEND_API ZEND_COLD ZEND_NORETURN void zend_error_noreturn_unchecked(int type, const char *format, ...); diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index c19bf2779fbf..a4b9abf36184 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -1283,11 +1283,13 @@ ZEND_FUNCTION(set_error_handler) zend_fcall_info fci; zend_fcall_info_cache fcc; zend_long error_type = E_ALL; + bool delay = true; - ZEND_PARSE_PARAMETERS_START(1, 2) + ZEND_PARSE_PARAMETERS_START(1, 3) Z_PARAM_FUNC_OR_NULL(fci, fcc) Z_PARAM_OPTIONAL Z_PARAM_LONG(error_type) + Z_PARAM_BOOL(delay) ZEND_PARSE_PARAMETERS_END(); if (Z_TYPE(EG(user_error_handler)) != IS_UNDEF) { @@ -1303,7 +1305,10 @@ ZEND_FUNCTION(set_error_handler) } ZVAL_COPY(&EG(user_error_handler), &(fci.function_name)); - EG(user_error_handler_error_reporting) = (int)error_type; + EG(user_error_handler_error_reporting) = (int)error_type & E_ALL; + if (!delay) { + EG(user_error_handler_error_reporting) |= ZEND_ERROR_HANDLER_NO_DELAY; + } } /* }}} */ diff --git a/Zend/zend_builtin_functions.stub.php b/Zend/zend_builtin_functions.stub.php index 1d405587145d..f4d4bd6cb4c2 100644 --- a/Zend/zend_builtin_functions.stub.php +++ b/Zend/zend_builtin_functions.stub.php @@ -121,7 +121,7 @@ function trigger_error(string $message, int $error_level = E_USER_NOTICE): true function user_error(string $message, int $error_level = E_USER_NOTICE): true {} /** @return callable|null */ -function set_error_handler(?callable $callback, int $error_levels = E_ALL) {} +function set_error_handler(?callable $callback, int $error_levels = E_ALL, bool $delay = true) {} function restore_error_handler(): true {} diff --git a/Zend/zend_builtin_functions_arginfo.h b/Zend/zend_builtin_functions_arginfo.h index b3af43fef340..24510d925f9d 100644 --- a/Zend/zend_builtin_functions_arginfo.h +++ b/Zend/zend_builtin_functions_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit zend_builtin_functions.stub.php instead. - * Stub hash: 64c61862de86d9968930893bf21b516119724064 */ + * Stub hash: 7b23af1724df954be54583a7662d679dd95bc8b4 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_clone, 0, 1, IS_OBJECT, 0) ZEND_ARG_TYPE_INFO(0, object, IS_OBJECT, 0) @@ -148,6 +148,7 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_set_error_handler, 0, 0, 1) ZEND_ARG_TYPE_INFO(0, callback, IS_CALLABLE, 1) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, error_levels, IS_LONG, 0, "E_ALL") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, delay, _IS_BOOL, 0, "true") ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_restore_error_handler, 0, 0, IS_TRUE, 0) diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 0e31332c97f0..33c750ffe066 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -1015,6 +1015,7 @@ ZEND_API void zend_initialize_class_data(zend_class_entry *ce, bool nullify_hand uint32_t zend_get_class_fetch_type(const zend_string *name); ZEND_API uint8_t zend_get_call_op(const zend_op *init_op, const zend_function *fbc, bool result_used); ZEND_API bool zend_is_smart_branch(const zend_op *opline); +bool zend_keeps_op1_alive(const zend_op *opline); typedef bool (*zend_auto_global_callback)(zend_string *name); typedef struct _zend_auto_global { diff --git a/Zend/zend_errors.h b/Zend/zend_errors.h index 831e4a9b912a..f3efd50c302d 100644 --- a/Zend/zend_errors.h +++ b/Zend/zend_errors.h @@ -39,6 +39,12 @@ /* Indicates that this usually fatal error should not result in a bailout */ #define E_DONT_BAIL (1<<15L) +/* Indicates that this error should not be delayed */ +#define E_NO_DELAY (1<<16L) + +/* Flag for EG(user_error_handler_error_reporting): Matching errors are promoted to exceptions, and the error handler is called during excepiton handling. */ +#define ZEND_ERROR_HANDLER_NO_DELAY (1<<30) + #define E_ALL (E_ERROR | E_WARNING | E_PARSE | E_NOTICE | E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_COMPILE_WARNING | E_USER_ERROR | E_USER_WARNING | E_USER_NOTICE | E_RECOVERABLE_ERROR | E_DEPRECATED | E_USER_DEPRECATED) #define E_CORE (E_CORE_ERROR | E_CORE_WARNING) diff --git a/Zend/zend_exceptions.c b/Zend/zend_exceptions.c index d23fb647af9d..66e65bb1aa36 100644 --- a/Zend/zend_exceptions.c +++ b/Zend/zend_exceptions.c @@ -49,6 +49,7 @@ ZEND_API zend_class_entry *zend_ce_arithmetic_error; ZEND_API zend_class_entry *zend_ce_division_by_zero_error; ZEND_API zend_class_entry *zend_ce_unhandled_match_error; ZEND_API zend_class_entry *zend_ce_request_parse_body_exception; +ZEND_API zend_class_entry *zend_ce_promoted_error_exception; /* Internal pseudo-exception that is not exposed to userland. Throwing this exception *does not* execute finally blocks. */ static zend_class_entry zend_ce_unwind_exit; @@ -166,7 +167,7 @@ ZEND_API ZEND_COLD void zend_throw_exception_internal(zend_object *exception) /* if (exception != NULL) { const zend_object *previous = EG(exception); - if (previous && zend_is_unwind_exit(previous)) { + if (previous && (zend_is_unwind_exit(previous) || zend_is_promoted_error_exception(previous))) { /* Don't replace unwinding exception with different exception. */ OBJ_RELEASE(exception); return; @@ -827,6 +828,9 @@ void zend_register_default_exception(void) /* {{{ */ zend_ce_request_parse_body_exception = register_class_RequestParseBodyException(zend_ce_exception); zend_init_exception_class_entry(zend_ce_request_parse_body_exception); + zend_ce_promoted_error_exception = register_class_PromotedErrorException(zend_ce_error_exception); + zend_init_exception_class_entry(zend_ce_promoted_error_exception); + INIT_CLASS_ENTRY(zend_ce_unwind_exit, "UnwindExit", NULL); INIT_CLASS_ENTRY(zend_ce_graceful_exit, "GracefulExit", NULL); @@ -1063,3 +1067,9 @@ ZEND_API bool zend_is_graceful_exit(const zend_object *ex) { return ex->ce == &zend_ce_graceful_exit; } + +ZEND_API bool zend_is_promoted_error_exception(const zend_object *ex) +{ + return ex->ce == zend_ce_promoted_error_exception; +} + diff --git a/Zend/zend_exceptions.h b/Zend/zend_exceptions.h index f9b472598012..b6dbed4f81f1 100644 --- a/Zend/zend_exceptions.h +++ b/Zend/zend_exceptions.h @@ -38,6 +38,7 @@ extern ZEND_API zend_class_entry *zend_ce_arithmetic_error; extern ZEND_API zend_class_entry *zend_ce_division_by_zero_error; extern ZEND_API zend_class_entry *zend_ce_unhandled_match_error; extern ZEND_API zend_class_entry *zend_ce_request_parse_body_exception; +extern ZEND_API zend_class_entry *zend_ce_promoted_error_exception; ZEND_API void zend_exception_set_previous(zend_object *exception, zend_object *add_previous); @@ -73,6 +74,7 @@ ZEND_API ZEND_COLD void zend_throw_unwind_exit(void); ZEND_API ZEND_COLD void zend_throw_graceful_exit(void); ZEND_API bool zend_is_unwind_exit(const zend_object *ex); ZEND_API bool zend_is_graceful_exit(const zend_object *ex); +ZEND_API bool zend_is_promoted_error_exception(const zend_object *ex); #include "zend_globals.h" diff --git a/Zend/zend_exceptions.stub.php b/Zend/zend_exceptions.stub.php index 86f2838ee912..1dd513665705 100644 --- a/Zend/zend_exceptions.stub.php +++ b/Zend/zend_exceptions.stub.php @@ -81,6 +81,10 @@ public function __construct( final public function getSeverity(): int {} } +class PromotedErrorException extends ErrorException +{ +} + class Error implements Throwable { /** diff --git a/Zend/zend_exceptions_arginfo.h b/Zend/zend_exceptions_arginfo.h index 4706161a09af..7366eb2b2d7f 100644 --- a/Zend/zend_exceptions_arginfo.h +++ b/Zend/zend_exceptions_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit zend_exceptions.stub.php instead. - * Stub hash: ba1562ca8fe2fe48c40bc52d10545aa989afd86c */ + * Stub hash: 29f62b734a504e14599e240910b01fd5f44fad60 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Throwable_getMessage, 0, 0, IS_STRING, 0) ZEND_END_ARG_INFO() @@ -207,6 +207,16 @@ static zend_class_entry *register_class_ErrorException(zend_class_entry *class_e return class_entry; } +static zend_class_entry *register_class_PromotedErrorException(zend_class_entry *class_entry_ErrorException) +{ + zend_class_entry ce, *class_entry; + + INIT_CLASS_ENTRY(ce, "PromotedErrorException", NULL); + class_entry = zend_register_internal_class_with_flags(&ce, class_entry_ErrorException, 0); + + return class_entry; +} + static zend_class_entry *register_class_Error(zend_class_entry *class_entry_Throwable) { zend_class_entry ce, *class_entry; diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 4253037fda52..181b9347a6c7 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -2525,6 +2525,83 @@ ZEND_API ZEND_COLD zval* ZEND_FASTCALL zend_undefined_offset_write(HashTable *ht return zend_hash_index_add_new(ht, lval, &EG(uninitialized_zval)); } +ZEND_API zend_never_inline void ZEND_FASTCALL zend_handle_delayed_effects(void) +{ + HashPosition start = EG(delayed_effects).nInternalPointer; + HashPosition pos = start; + HashPosition end = EG(delayed_effects).nNumUsed; + /* Nested calls handle new items */ + EG(delayed_effects).nInternalPointer = end; + +restart:; + + ZEND_ASSERT(HT_IS_PACKED(&EG(delayed_effects))); + + for (; pos < end; pos++) { + zval *val = &EG(delayed_effects).arPacked[pos]; + switch (Z_TYPE_P(val)) { + case IS_PTR: { + zend_error_info *info = Z_PTR_P(val); + ZVAL_NULL(val); + int orig_error_reporting = EG(error_reporting); + EG(error_reporting) = info->error_reporting; + zend_error_zstr_at(info->type | E_NO_DELAY, info->filename, info->lineno, info->message); + EG(error_reporting) = orig_error_reporting; + zend_string_release(info->filename); + zend_string_release(info->message); + efree(info); + break; + } + case IS_OBJECT: { + zend_object *obj = Z_OBJ_P(val); + ZEND_ASSERT(GC_REFCOUNT(obj) == 1); + obj->handlers->dtor_obj(obj); + GC_DELREF(obj); + if (GC_REFCOUNT(obj) == 0) { + zend_objects_store_del(obj); + } + break; + } + default: + ZEND_UNREACHABLE(); + } + } + + if (EG(delayed_effects).nInternalPointer < EG(delayed_effects).nNumUsed) { + /* New items were added during iteration and were not handled */ + pos = EG(delayed_effects).nInternalPointer; + end = EG(delayed_effects).nNumUsed; + EG(delayed_effects).nInternalPointer = end; + goto restart; + } + + if (start == 0) { + zend_hash_clean(&EG(delayed_effects)); + } +} + +ZEND_API void ZEND_FASTCALL zend_discard_delayed_effects(void) +{ + zval *val; + ZEND_HASH_FOREACH_VAL(&EG(delayed_effects), val) { + switch (Z_TYPE_P(val)) { + case IS_PTR: { + zend_error_info *info = Z_PTR_P(val); + zend_string_release(info->filename); + zend_string_release(info->message); + efree(info); + break; + } + case IS_OBJECT: + case IS_NULL: + break; + default: + ZEND_UNREACHABLE(); + } + } ZEND_HASH_FOREACH_END(); + zend_hash_clean(&EG(delayed_effects)); +} + ZEND_API ZEND_COLD zval* ZEND_FASTCALL zend_undefined_index_write(HashTable *ht, zend_string *offset) { zval *retval; @@ -4314,6 +4391,9 @@ ZEND_API void ZEND_FASTCALL zend_free_compiled_variables(zend_execute_data *exec ZEND_API ZEND_COLD void ZEND_FASTCALL zend_fcall_interrupt(zend_execute_data *call) { zend_atomic_bool_store_ex(&EG(vm_interrupt), false); + if (zend_hash_num_elements(&EG(delayed_effects))) { + zend_handle_delayed_effects(); + } if (zend_atomic_bool_load_ex(&EG(timed_out))) { zend_timeout(); } else if (zend_interrupt_function) { @@ -5720,13 +5800,19 @@ static zend_always_inline zend_execute_data *_zend_vm_stack_push_call_frame_ex(u if (UNEXPECTED(used_stack > (size_t)(((char*)EG(vm_stack_end)) - (char*)call))) { EX(opline) = opline; /* this is the only difference */ + ZEND_VM_FCALL_INTERRUPT_CHECK(EG(current_execute_data)); + if (UNEXPECTED(EG(exception))) { + return NULL; + } call = (zend_execute_data*)zend_vm_stack_extend(used_stack); ZEND_ASSERT_VM_STACK_GLOBAL; zend_vm_init_call_frame(call, call_info | ZEND_CALL_ALLOCATED, func, num_args, object_or_called_scope); + ZEND_ASSERT(call); return call; } else { EG(vm_stack_top) = (zval*)((char*)call + used_stack); zend_vm_init_call_frame(call, call_info, func, num_args, object_or_called_scope); + ZEND_ASSERT(call); return call; } } /* }}} */ @@ -5736,7 +5822,7 @@ static zend_always_inline zend_execute_data *_zend_vm_stack_push_call_frame(uint uint32_t used_stack = zend_vm_calc_used_stack(num_args, func); return _zend_vm_stack_push_call_frame_ex(used_stack, call_info, - func, num_args, object_or_called_scope); + func, num_args, object_or_called_scope EXECUTE_DATA_CC); } /* }}} */ #else # define _zend_vm_stack_push_call_frame_ex zend_vm_stack_push_call_frame_ex @@ -5792,6 +5878,15 @@ static zend_always_inline zend_execute_data *_zend_vm_stack_push_call_frame(uint ZEND_VM_CONTINUE(); \ } while (0) +/* Same but indicate that we are jumping forward, so not interrupt check is performed */ +#define ZEND_VM_JMP_FWD_EX(new_op, check_exception) do { \ + if (check_exception && UNEXPECTED(EG(exception))) { \ + HANDLE_EXCEPTION(); \ + } \ + ZEND_VM_SET_OPCODE_NO_INTERRUPT(new_op); \ + ZEND_VM_CONTINUE(); \ + } while (0) + #define ZEND_VM_JMP(new_op) \ ZEND_VM_JMP_EX(new_op, 1) @@ -5913,6 +6008,58 @@ static zend_always_inline zend_execute_data *_zend_vm_stack_push_call_frame(uint /* This callback disables optimization of "vm_stack_data" variable in VM */ ZEND_API void (ZEND_FASTCALL *zend_touch_vm_stack_data)(void *vm_stack_data) = NULL; +void zend_interrupt_consume(zend_execute_data *execute_data, const zend_op *opline) +{ + /* Interrupts are handled before executing opline, but exception handling + * assumes that a throwing opline was executed. + * If an exception was thrown by the interrupt handler, we need to consume + * inputs and and initialize outputs. */ + + if (EG(opline_before_exception) != opline) { + return; + } + + if (opline + && opline->result_type & (IS_TMP_VAR|IS_VAR) + && opline->opcode != ZEND_ADD_ARRAY_ELEMENT + && opline->opcode != ZEND_ADD_ARRAY_UNPACK + && opline->opcode != ZEND_ROPE_INIT + && opline->opcode != ZEND_ROPE_ADD) { + ZVAL_UNDEF(ZEND_CALL_VAR(EG(current_execute_data), opline->result.var)); + } + + if (opline->opcode == ZEND_SEPARATE) { + ZEND_ASSERT(opline->op1.var == opline->result.var); + return; + } + + if ((opline->op1_type & (IS_TMP_VAR|IS_VAR))) { + if (EXPECTED(!zend_keeps_op1_alive(opline))) { + zval_ptr_dtor(EX_VAR(opline->op1.var)); + } + } + + if ((opline->op2_type & (IS_TMP_VAR|IS_VAR))) { + if (UNEXPECTED(opline->opcode == ZEND_FE_FETCH_R + || opline->opcode == ZEND_FE_FETCH_RW)) { + /* OP2 of FE_FETCH is actually a def, not a use. */ + } else { + zval_ptr_dtor(EX_VAR(opline->op2.var)); + } + } + + const zend_op_array *op_array = &EX(func)->op_array; + + if (opline >= op_array->opcodes + && opline - op_array->opcodes < op_array->last) { + const zend_op *next_op = opline + 1; + if (next_op->opcode == ZEND_OP_DATA + && next_op->op1_type & (IS_TMP_VAR|IS_VAR)) { + zval_ptr_dtor(EX_VAR(opline->op1.var)); + } + } +} + #include "zend_vm_execute.h" ZEND_API zend_result zend_set_user_opcode_handler(zend_uchar opcode, user_opcode_handler_t handler) diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index ba48b19bcfe1..fc68e7da5270 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -99,6 +99,9 @@ ZEND_API zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_cannot_add_element( ZEND_API bool ZEND_FASTCALL zend_asymmetric_property_has_set_access(const zend_property_info *prop_info); ZEND_API zend_never_inline ZEND_COLD void ZEND_FASTCALL zend_asymmetric_visibility_property_modification_error(const zend_property_info *prop_info, const char *operation); +ZEND_API void ZEND_FASTCALL zend_handle_delayed_effects(void); +ZEND_API void ZEND_FASTCALL zend_discard_delayed_effects(void); + ZEND_API bool zend_verify_scalar_type_hint(uint32_t type_mask, zval *arg, bool strict, bool is_internal_arg); ZEND_API zend_never_inline ZEND_COLD void zend_verify_arg_error( const zend_function *zf, const zend_arg_info *arg_info, uint32_t arg_num, const zval *value); @@ -285,6 +288,13 @@ ZEND_API zend_result ZEND_FASTCALL zval_update_constant(zval *pp); ZEND_API zend_result ZEND_FASTCALL zval_update_constant_ex(zval *pp, zend_class_entry *scope); ZEND_API zend_result ZEND_FASTCALL zval_update_constant_with_ctx(zval *pp, zend_class_entry *scope, zend_ast_evaluate_ctx *ctx); +/* Call this to handle the timeout or the interrupt function. It will set + * EG(vm_interrupt) to false. + */ +ZEND_API ZEND_COLD void ZEND_FASTCALL zend_fcall_interrupt(zend_execute_data *call); + +void zend_interrupt_consume(zend_execute_data *execute_data, const zend_op *opline); + /* dedicated Zend executor functions - do not use! */ struct _zend_vm_stack { zval *top; @@ -347,13 +357,21 @@ static zend_always_inline zend_execute_data *zend_vm_stack_push_call_frame_ex(ui ZEND_ASSERT_VM_STACK_GLOBAL; if (UNEXPECTED(used_stack > (size_t)(((char*)EG(vm_stack_end)) - (char*)call))) { + if (UNEXPECTED(zend_atomic_bool_load_ex(&EG(vm_interrupt)))) { + zend_fcall_interrupt(EG(current_execute_data)); + if (UNEXPECTED(EG(exception))) { + return NULL; + } + } call = (zend_execute_data*)zend_vm_stack_extend(used_stack); ZEND_ASSERT_VM_STACK_GLOBAL; zend_vm_init_call_frame(call, call_info | ZEND_CALL_ALLOCATED, func, num_args, object_or_called_scope); + ZEND_ASSERT(call); return call; } else { EG(vm_stack_top) = (zval*)((char*)call + used_stack); zend_vm_init_call_frame(call, call_info, func, num_args, object_or_called_scope); + ZEND_ASSERT(call); return call; } } @@ -617,11 +635,6 @@ ZEND_API bool zend_verify_property_type(const zend_property_info *info, zval *pr zend_never_inline ZEND_COLD void zend_match_unhandled_error(const zval *value); -/* Call this to handle the timeout or the interrupt function. It will set - * EG(vm_interrupt) to false. - */ -ZEND_API ZEND_COLD void ZEND_FASTCALL zend_fcall_interrupt(zend_execute_data *call); - static zend_always_inline void *zend_get_bad_ptr(void) { ZEND_UNREACHABLE(); diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 71e0c56a51c8..00c99d3fb0c5 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -198,6 +198,9 @@ void init_executor(void) /* {{{ */ zend_max_execution_timer_init(); zend_fiber_init(); + + zend_hash_init(&EG(delayed_effects), 0, NULL, NULL, 0); + zend_weakrefs_init(); zend_hash_init(&EG(callable_convert_cache), 8, NULL, ZVAL_PTR_DTOR, 0); @@ -528,6 +531,9 @@ void shutdown_executor(void) /* {{{ */ EG(ht_iterators_used) = 0; zend_shutdown_fpu(); + + zend_discard_delayed_effects(); + zend_hash_destroy(&EG(delayed_effects)); } /* }}} */ diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index 8257df32e831..088c541b8bf1 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -264,7 +264,6 @@ struct _zend_executor_globals { zend_object *exception; const zend_op *opline_before_exception; zend_op exception_op[3]; - struct _zend_module_entry *current_module; bool active; @@ -321,6 +320,7 @@ struct _zend_executor_globals { pid_t pid; struct sigaction oldact; #endif + HashTable delayed_effects; zend_strtod_state strtod_state; diff --git a/Zend/zend_objects_API.c b/Zend/zend_objects_API.c index 537cad8a3644..2ef326d63335 100644 --- a/Zend/zend_objects_API.c +++ b/Zend/zend_objects_API.c @@ -174,6 +174,16 @@ ZEND_API void ZEND_FASTCALL zend_objects_store_del(zend_object *object) /* {{{ * if (object->handlers->dtor_obj != zend_objects_destroy_object || object->ce->destructor) { + /* If we are inside the VM, delay the destructor call to a safe point. */ + if (EG(current_execute_data)) { + /* Keep object alive until the delayed destructor runs. */ + GC_SET_REFCOUNT(object, 1); + zval zv; + ZVAL_OBJ(&zv, object); + zend_hash_next_index_insert(&EG(delayed_effects), &zv); + zend_atomic_bool_store_ex(&EG(vm_interrupt), true); + return; + } GC_SET_REFCOUNT(object, 1); object->handlers->dtor_obj(object); GC_DELREF(object); diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 0c6b22473514..82fd8e0cde5d 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -901,7 +901,7 @@ static bool is_fake_def(zend_op *opline) { || opline->opcode == ZEND_ADD_ARRAY_UNPACK; } -static bool keeps_op1_alive(zend_op *opline) { +bool zend_keeps_op1_alive(const zend_op *opline) { /* These opcodes don't consume their OP1 operand, * it is later freed by something else. */ if (opline->opcode == ZEND_CASE @@ -992,7 +992,7 @@ static void zend_calc_live_ranges( if ((opline->op1_type & (IS_TMP_VAR|IS_VAR))) { uint32_t var_num = EX_VAR_TO_NUM(opline->op1.var) - var_offset; if (EXPECTED(last_use[var_num] == (uint32_t) -1)) { - if (EXPECTED(!keeps_op1_alive(opline))) { + if (EXPECTED(!zend_keeps_op1_alive(opline))) { /* OP_DATA is really part of the previous opcode. */ last_use[var_num] = opnum - (opline->opcode == ZEND_OP_DATA); } diff --git a/Zend/zend_vm.h b/Zend/zend_vm.h index ebb542eb35bc..c0bd4b01e775 100644 --- a/Zend/zend_vm.h +++ b/Zend/zend_vm.h @@ -43,6 +43,7 @@ void zend_vm_dtor(void); const struct _zend_op *zend_vm_handle_interrupt(struct _zend_execute_data *execute_data, const struct _zend_op *opline); #endif + END_EXTERN_C() #define ZEND_VM_SET_OPCODE_HANDLER(opline) zend_vm_set_opcode_handler(opline) diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 1de7a7cd4195..9680f3ea33d5 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2150,6 +2150,10 @@ ZEND_VM_C_LABEL(fetch_obj_r_fast_copy): call_info |= ZEND_CALL_RELEASE_THIS; } zend_execute_data *call = zend_vm_stack_push_call_frame(call_info, hook, 0, zobj); + if (UNEXPECTED(!call)) { + ZVAL_NULL(EX_VAR(opline->result.var)); + ZEND_VM_C_GOTO(fetch_obj_r_finish); + } call->prev_execute_data = execute_data; call->call = NULL; call->return_value = EX_VAR(opline->result.var); @@ -3004,9 +3008,14 @@ ZEND_VM_HOT_HELPER(zend_leave_helper, ANY, ANY) } else if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) { OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func))); } + EG(vm_stack_top) = (zval*)execute_data; execute_data = EX(prev_execute_data); + if (UNEXPECTED(zend_atomic_bool_load_ex(&EG(vm_interrupt)))) { + zend_fcall_interrupt(execute_data); + } + if (UNEXPECTED(EG(exception) != NULL)) { zend_rethrow_exception(execute_data); HANDLE_EXCEPTION_LEAVE(); @@ -3043,6 +3052,10 @@ ZEND_VM_HOT_HELPER(zend_leave_helper, ANY, ANY) execute_data = EX(prev_execute_data); zend_vm_stack_free_call_frame_ex(call_info, old_execute_data); + if (UNEXPECTED(zend_atomic_bool_load_ex(&EG(vm_interrupt)))) { + zend_fcall_interrupt(execute_data); + } + if (UNEXPECTED(EG(exception) != NULL)) { zend_rethrow_exception(execute_data); HANDLE_EXCEPTION_LEAVE(); @@ -3069,6 +3082,11 @@ ZEND_VM_HOT_HELPER(zend_leave_helper, ANY, ANY) ZEND_ADD_CALL_FLAG(execute_data, ZEND_CALL_NEEDS_REATTACH); } } + + if (UNEXPECTED(zend_atomic_bool_load_ex(&EG(vm_interrupt)))) { + zend_fcall_interrupt(execute_data); + } + if (UNEXPECTED(EG(exception) != NULL)) { zend_rethrow_exception(execute_data); HANDLE_EXCEPTION_LEAVE(); @@ -3095,6 +3113,11 @@ ZEND_VM_HOT_HELPER(zend_leave_helper, ANY, ANY) if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) { OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func))); } + + if (UNEXPECTED(zend_atomic_bool_load_ex(&EG(vm_interrupt)))) { + zend_fcall_interrupt(EG(current_execute_data)); + } + ZEND_VM_RETURN(); } else /* if (call_kind == ZEND_CALL_TOP_CODE) */ { zend_array *symbol_table = EX(symbol_table); @@ -3120,6 +3143,11 @@ ZEND_VM_HOT_HELPER(zend_leave_helper, ANY, ANY) } } EG(current_execute_data) = EX(prev_execute_data); + + if (UNEXPECTED(zend_atomic_bool_load_ex(&EG(vm_interrupt)))) { + zend_fcall_interrupt(EG(current_execute_data)); + } + ZEND_VM_RETURN(); } } @@ -3752,6 +3780,10 @@ ZEND_VM_HOT_OBJ_HANDLER(112, ZEND_INIT_METHOD_CALL, CONST|TMP|UNUSED|THIS|CV, CO call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, obj); + if (UNEXPECTED(!call)) { + FREE_OP1(); + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -3885,6 +3917,9 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, UNUSED|CLASS_FETCH|CONST|VAR, call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, ce); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -3913,6 +3948,9 @@ ZEND_VM_HOT_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST, NUM|CACHE_SLOT) } call = _zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION, fbc, opline->extended_value, NULL); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -4038,6 +4076,9 @@ ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMP|CV, NUM) call = zend_vm_stack_push_call_frame(call_info, func, opline->extended_value, object_or_called_scope); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -4071,6 +4112,9 @@ ZEND_VM_HOT_HANDLER(69, ZEND_INIT_NS_FCALL_BY_NAME, ANY, CONST, NUM|CACHE_SLOT) call = _zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION, fbc, opline->extended_value, NULL); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -4100,6 +4144,9 @@ ZEND_VM_HOT_HANDLER(61, ZEND_INIT_FCALL, NUM, CONST, NUM|CACHE_SLOT) call = _zend_vm_stack_push_call_frame_ex( opline->op1.num, ZEND_CALL_NESTED_FUNCTION, fbc, opline->extended_value, NULL); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -4119,6 +4166,9 @@ ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_INIT_FCALL, Z_EXTRA_P(RT_CONSTANT(op, op->op2 call = _zend_vm_stack_push_call_frame_ex( opline->op1.num, ZEND_CALL_NESTED_FUNCTION, fbc, opline->extended_value, NULL); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; ZEND_VM_NEXT_OPCODE(); @@ -4611,9 +4661,24 @@ ZEND_VM_INLINE_HANDLER(62, ZEND_RETURN, CONST|TMP|CV, ANY, SPEC(OBSERVER)) } } } + +#if 0 + if (UNEXPECTED(zend_atomic_bool_load_ex(&EG(vm_interrupt)))) { + if (zend_hash_num_elements(&EG(delayed_effects))) { + zend_handle_delayed_effects(); + if (EG(exception)) { + ZEND_VM_ENTER(); + } + } + /* Do not reset EG(vm_interrupt) as it may have been set for other + * reasons */ + } +#endif + ZEND_OBSERVER_SAVE_OPLINE(); ZEND_OBSERVER_FCALL_END(execute_data, return_value); ZEND_OBSERVER_FREE_RETVAL(); + ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper); } @@ -6023,6 +6088,9 @@ ZEND_VM_HANDLER(68, ZEND_NEW, UNUSED|CLASS_FETCH|CONST|VAR, UNUSED|CACHE_SLOT, N call = zend_vm_stack_push_call_frame( ZEND_CALL_FUNCTION, (zend_function *) &zend_pass_function, opline->extended_value, NULL); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } } else { if (EXPECTED(constructor->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&constructor->op_array))) { init_func_run_time_cache(&constructor->op_array); @@ -6033,6 +6101,9 @@ ZEND_VM_HANDLER(68, ZEND_NEW, UNUSED|CLASS_FETCH|CONST|VAR, UNUSED|CACHE_SLOT, N constructor, opline->extended_value, Z_OBJ_P(result)); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } Z_ADDREF_P(result); } @@ -6585,6 +6656,7 @@ ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL, CONST|TMP|CV, ANY, EVAL, SPEC(OBSERVER inc_filename = GET_OP1_ZVAL_PTR(BP_VAR_R); new_op_array = zend_include_or_eval(inc_filename, opline->extended_value); if (UNEXPECTED(EG(exception) != NULL)) { +ZEND_VM_C_LABEL(handle_exception): FREE_OP1(); if (new_op_array != ZEND_FAKE_OP_ARRAY && new_op_array != NULL) { destroy_op_array(new_op_array); @@ -6625,6 +6697,9 @@ ZEND_VM_HANDLER(73, ZEND_INCLUDE_OR_EVAL, CONST|TMP|CV, ANY, EVAL, SPEC(OBSERVER (Z_TYPE_INFO(EX(This)) & ZEND_CALL_HAS_THIS) | ZEND_CALL_NESTED_CODE | ZEND_CALL_HAS_SYMBOL_TABLE, (zend_function*)new_op_array, 0, Z_PTR(EX(This))); + if (UNEXPECTED(!call)) { + ZEND_VM_C_GOTO(handle_exception); + } if (EX_CALL_INFO() & ZEND_CALL_HAS_SYMBOL_TABLE) { call->symbol_table = EX(symbol_table); @@ -8152,7 +8227,7 @@ ZEND_VM_HELPER(zend_dispatch_try_catch_finally_helper, ANY, ANY, uint32_t try_ca if (op_num < try_catch->catch_op && ex) { /* Go to catch block */ cleanup_live_vars(execute_data, op_num, try_catch->catch_op); - ZEND_VM_JMP_EX(&EX(func)->op_array.opcodes[try_catch->catch_op], 0); + ZEND_VM_JMP_FWD_EX(&EX(func)->op_array.opcodes[try_catch->catch_op], 0); } else if (op_num < try_catch->finally_op) { if (ex && zend_is_unwind_exit(ex)) { @@ -8166,7 +8241,7 @@ ZEND_VM_HELPER(zend_dispatch_try_catch_finally_helper, ANY, ANY, uint32_t try_ca Z_OBJ_P(fast_call) = EG(exception); EG(exception) = NULL; Z_OPLINE_NUM_P(fast_call) = (uint32_t)-1; - ZEND_VM_JMP_EX(&EX(func)->op_array.opcodes[try_catch->finally_op], 0); + ZEND_VM_JMP_FWD_EX(&EX(func)->op_array.opcodes[try_catch->finally_op], 0); } else if (op_num < try_catch->finally_end) { zval *fast_call = EX_VAR(EX(func)->op_array.opcodes[try_catch->finally_end].op1.var); @@ -8220,11 +8295,69 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY) { const zend_op *throw_op = EG(opline_before_exception); + if (zend_hash_num_elements(&EG(delayed_effects))) { + zend_object *orig_exception = EG(exception); + EX(opline) = EG(opline_before_exception); + EG(exception) = NULL; + + zend_handle_delayed_effects(); + + if (EG(exception)) { + zend_exception_set_previous(EG(exception), orig_exception); + } else { + EG(exception) = orig_exception; + EX(opline) = EG(exception_op); + } + } + + if (throw_op && EG(exception)->ce == zend_ce_promoted_error_exception) { + zend_object *promoted = EG(exception); + + zval *severity_zv = zend_read_property_ex( + zend_ce_error_exception, promoted, ZSTR_KNOWN(ZEND_STR_SEVERITY), /* silent */ 1, NULL); + zval *message_zv = zend_read_property_ex( + zend_ce_exception, promoted, ZSTR_KNOWN(ZEND_STR_MESSAGE), 1, NULL); + zval *file_zv = zend_read_property_ex( + zend_ce_exception, promoted, ZSTR_KNOWN(ZEND_STR_FILE), 1, NULL); + zval *line_zv = zend_read_property_ex( + zend_ce_exception, promoted, ZSTR_KNOWN(ZEND_STR_LINE), 1, NULL); + + int error_type = (int) Z_LVAL_P(severity_zv) & E_ALL; + if (!error_type) { + error_type = E_ERROR; + } + zend_string *error_message = zend_string_copy(Z_STR_P(message_zv)); + zend_string *error_file = zend_string_copy(Z_STR_P(file_zv)); + zend_long error_line = Z_LVAL_P(line_zv); + + EG(exception) = NULL; + EX(opline) = throw_op; + zend_error_zstr_at(error_type | E_NO_DELAY, error_file, error_line, error_message); + + zend_string_release(error_file); + zend_string_release(error_message); + + if (!EG(exception)) { + EG(exception) = promoted; + } else { + OBJ_RELEASE(promoted); + } + } + /* Exception was thrown before executing any op */ if (UNEXPECTED(!throw_op)) { ZEND_VM_DISPATCH_TO_HELPER(zend_dispatch_try_catch_finally_helper, try_catch_offset, -1, op_num, 0); } + /* Exception was thrown from the ZEND_DO_FCALL interrupt handler just + * before entering EG(call_trampoline_op). */ + if (UNEXPECTED(throw_op == &EG(call_trampoline_op))) { + ZEND_ASSERT(EX(func)->op_array.opcodes == &EG(call_trampoline_op)); + zend_string_release_ex(EX(func)->op_array.function_name, 0); + zend_free_trampoline(EX(func)); + ZEND_VM_DISPATCH_TO_HELPER(zend_dispatch_try_catch_finally_helper, try_catch_offset, -1, op_num, 0); + } + uint32_t throw_op_num = throw_op - EX(func)->op_array.opcodes; uint32_t current_try_catch_offset = -1; @@ -10019,6 +10152,10 @@ ZEND_VM_HANDLER(209, ZEND_INIT_PARENT_PROPERTY_HOOK_CALL, CONST, UNUSED|NUM, NUM call = zend_vm_stack_push_call_frame( ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_HAS_THIS, hook, opline->extended_value, Z_OBJ_P(ZEND_THIS)); + if (UNEXPECTED(!call)) { + UNDEF_RESULT(); + HANDLE_EXCEPTION(); + } if (EXPECTED(hook->type == ZEND_USER_FUNCTION)) { if (UNEXPECTED(!RUN_TIME_CACHE(&hook->op_array))) { init_func_run_time_cache(&hook->op_array); @@ -10030,6 +10167,10 @@ ZEND_VM_HANDLER(209, ZEND_INIT_PARENT_PROPERTY_HOOK_CALL, CONST, UNUSED|NUM, NUM call = zend_vm_stack_push_call_frame( ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_HAS_THIS, fbc, opline->extended_value, Z_OBJ_P(ZEND_THIS)); + if (UNEXPECTED(!call)) { + UNDEF_RESULT(); + HANDLE_EXCEPTION(); + } } call->prev_execute_data = EX(call); @@ -10630,25 +10771,24 @@ ZEND_VM_HELPER(zend_interrupt_helper, ANY, ANY) #else SAVE_OPLINE(); #endif + + if (zend_hash_num_elements(&EG(delayed_effects))) { + zend_handle_delayed_effects(); + } if (zend_atomic_bool_load_ex(&EG(timed_out))) { zend_timeout(); - } else if (zend_interrupt_function) { + } + if (zend_interrupt_function) { zend_interrupt_function(execute_data); - if (EG(exception)) { - /* We have to UNDEF result, because ZEND_HANDLE_EXCEPTION is going to free it */ - const zend_op *throw_op = EG(opline_before_exception); - - if (throw_op - && throw_op->result_type & (IS_TMP_VAR|IS_VAR) - && throw_op->opcode != ZEND_ADD_ARRAY_ELEMENT - && throw_op->opcode != ZEND_ADD_ARRAY_UNPACK - && throw_op->opcode != ZEND_ROPE_INIT - && throw_op->opcode != ZEND_ROPE_ADD) { - ZVAL_UNDEF(ZEND_CALL_VAR(EG(current_execute_data), throw_op->result.var)); - - } - } + } + if (UNEXPECTED(EG(exception))) { + zend_interrupt_consume(execute_data, opline); + opline = EG(exception_op); + ZEND_VM_CONTINUE(); + } + if (zend_interrupt_function) { ZEND_VM_ENTER(); + } else { + ZEND_VM_CONTINUE(); } - ZEND_VM_CONTINUE(); } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 5b52f1941845..2688344403c4 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -431,7 +431,7 @@ static zend_vm_opcode_handler_func_t zend_vm_get_opcode_handler_func(uint8_t opc #define HANDLE_EXCEPTION() ZEND_ASSERT(EG(exception)); LOAD_OPLINE(); ZEND_VM_CONTINUE() #define HANDLE_EXCEPTION_LEAVE() ZEND_ASSERT(EG(exception)); LOAD_OPLINE(); ZEND_VM_LEAVE() #if defined(ZEND_VM_FP_GLOBAL_REG) -# define ZEND_VM_ENTER_EX() ZEND_VM_INTERRUPT_CHECK(); ZEND_VM_CONTINUE() +# define ZEND_VM_ENTER_EX() ZEND_VM_CONTINUE() # define ZEND_VM_ENTER() execute_data = EG(current_execute_data); LOAD_OPLINE(); ZEND_VM_ENTER_EX() # define ZEND_VM_LEAVE() ZEND_VM_CONTINUE() #elif defined(ZEND_VM_IP_GLOBAL_REG) @@ -444,7 +444,11 @@ static zend_vm_opcode_handler_func_t zend_vm_get_opcode_handler_func(uint8_t opc # define ZEND_VM_ENTER() execute_data = EG(current_execute_data); LOAD_OPLINE(); ZEND_VM_ENTER_EX() # define ZEND_VM_LEAVE() return (zend_op*)((uintptr_t)opline | ZEND_VM_ENTER_BIT) #endif -#define ZEND_VM_INTERRUPT() ZEND_VM_TAIL_CALL(zend_interrupt_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)); +#if ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL +# define ZEND_VM_INTERRUPT() return zend_interrupt(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU) +#else +# define ZEND_VM_INTERRUPT() ZEND_VM_TAIL_CALL(zend_interrupt_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)); +#endif #ifdef ZEND_VM_FP_GLOBAL_REG #define ZEND_VM_LOOP_INTERRUPT() zend_interrupt_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); #else @@ -455,6 +459,12 @@ static zend_vm_opcode_handler_func_t zend_vm_get_opcode_handler_func(uint8_t opc static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV zend_interrupt_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS); static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_NULL_HANDLER(ZEND_OPCODE_HANDLER_ARGS); +#if ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL +static ZEND_COLD zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV zend_interrupt(ZEND_OPCODE_HANDLER_ARGS) { + SAVE_OPLINE(); + return &call_interrupt_op; +} +#endif static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV_EX zend_add_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_EX zval *op_1, zval *op_2) { USE_OPLINE @@ -1169,9 +1179,14 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV } else if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) { OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func))); } + EG(vm_stack_top) = (zval*)execute_data; execute_data = EX(prev_execute_data); + if (UNEXPECTED(zend_atomic_bool_load_ex(&EG(vm_interrupt)))) { + zend_fcall_interrupt(execute_data); + } + if (UNEXPECTED(EG(exception) != NULL)) { zend_rethrow_exception(execute_data); HANDLE_EXCEPTION_LEAVE(); @@ -1208,6 +1223,10 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV execute_data = EX(prev_execute_data); zend_vm_stack_free_call_frame_ex(call_info, old_execute_data); + if (UNEXPECTED(zend_atomic_bool_load_ex(&EG(vm_interrupt)))) { + zend_fcall_interrupt(execute_data); + } + if (UNEXPECTED(EG(exception) != NULL)) { zend_rethrow_exception(execute_data); HANDLE_EXCEPTION_LEAVE(); @@ -1234,6 +1253,11 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ADD_CALL_FLAG(execute_data, ZEND_CALL_NEEDS_REATTACH); } } + + if (UNEXPECTED(zend_atomic_bool_load_ex(&EG(vm_interrupt)))) { + zend_fcall_interrupt(execute_data); + } + if (UNEXPECTED(EG(exception) != NULL)) { zend_rethrow_exception(execute_data); HANDLE_EXCEPTION_LEAVE(); @@ -1260,6 +1284,11 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) { OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func))); } + + if (UNEXPECTED(zend_atomic_bool_load_ex(&EG(vm_interrupt)))) { + zend_fcall_interrupt(EG(current_execute_data)); + } + ZEND_VM_RETURN(); } else /* if (call_kind == ZEND_CALL_TOP_CODE) */ { zend_array *symbol_table = EX(symbol_table); @@ -1285,6 +1314,11 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV } } EG(current_execute_data) = EX(prev_execute_data); + + if (UNEXPECTED(zend_atomic_bool_load_ex(&EG(vm_interrupt)))) { + zend_fcall_interrupt(EG(current_execute_data)); + } + ZEND_VM_RETURN(); } } @@ -3331,7 +3365,7 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV_ if (op_num < try_catch->catch_op && ex) { /* Go to catch block */ cleanup_live_vars(execute_data, op_num, try_catch->catch_op); - ZEND_VM_JMP_EX(&EX(func)->op_array.opcodes[try_catch->catch_op], 0); + ZEND_VM_JMP_FWD_EX(&EX(func)->op_array.opcodes[try_catch->catch_op], 0); } else if (op_num < try_catch->finally_op) { if (ex && zend_is_unwind_exit(ex)) { @@ -3345,7 +3379,7 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV_ Z_OBJ_P(fast_call) = EG(exception); EG(exception) = NULL; Z_OPLINE_NUM_P(fast_call) = (uint32_t)-1; - ZEND_VM_JMP_EX(&EX(func)->op_array.opcodes[try_catch->finally_op], 0); + ZEND_VM_JMP_FWD_EX(&EX(func)->op_array.opcodes[try_catch->finally_op], 0); } else if (op_num < try_catch->finally_end) { zval *fast_call = EX_VAR(EX(func)->op_array.opcodes[try_catch->finally_end].op1.var); @@ -3399,11 +3433,69 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_HANDLE_EXCEPT { const zend_op *throw_op = EG(opline_before_exception); + if (zend_hash_num_elements(&EG(delayed_effects))) { + zend_object *orig_exception = EG(exception); + EX(opline) = EG(opline_before_exception); + EG(exception) = NULL; + + zend_handle_delayed_effects(); + + if (EG(exception)) { + zend_exception_set_previous(EG(exception), orig_exception); + } else { + EG(exception) = orig_exception; + EX(opline) = EG(exception_op); + } + } + + if (throw_op && EG(exception)->ce == zend_ce_promoted_error_exception) { + zend_object *promoted = EG(exception); + + zval *severity_zv = zend_read_property_ex( + zend_ce_error_exception, promoted, ZSTR_KNOWN(ZEND_STR_SEVERITY), /* silent */ 1, NULL); + zval *message_zv = zend_read_property_ex( + zend_ce_exception, promoted, ZSTR_KNOWN(ZEND_STR_MESSAGE), 1, NULL); + zval *file_zv = zend_read_property_ex( + zend_ce_exception, promoted, ZSTR_KNOWN(ZEND_STR_FILE), 1, NULL); + zval *line_zv = zend_read_property_ex( + zend_ce_exception, promoted, ZSTR_KNOWN(ZEND_STR_LINE), 1, NULL); + + int error_type = (int) Z_LVAL_P(severity_zv) & E_ALL; + if (!error_type) { + error_type = E_ERROR; + } + zend_string *error_message = zend_string_copy(Z_STR_P(message_zv)); + zend_string *error_file = zend_string_copy(Z_STR_P(file_zv)); + zend_long error_line = Z_LVAL_P(line_zv); + + EG(exception) = NULL; + EX(opline) = throw_op; + zend_error_zstr_at(error_type | E_NO_DELAY, error_file, error_line, error_message); + + zend_string_release(error_file); + zend_string_release(error_message); + + if (!EG(exception)) { + EG(exception) = promoted; + } else { + OBJ_RELEASE(promoted); + } + } + /* Exception was thrown before executing any op */ if (UNEXPECTED(!throw_op)) { ZEND_VM_DISPATCH_TO_HELPER(zend_dispatch_try_catch_finally_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX -1, 0)); } + /* Exception was thrown from the ZEND_DO_FCALL interrupt handler just + * before entering EG(call_trampoline_op). */ + if (UNEXPECTED(throw_op == &EG(call_trampoline_op))) { + ZEND_ASSERT(EX(func)->op_array.opcodes == &EG(call_trampoline_op)); + zend_string_release_ex(EX(func)->op_array.function_name, 0); + zend_free_trampoline(EX(func)); + ZEND_VM_DISPATCH_TO_HELPER(zend_dispatch_try_catch_finally_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX -1, 0)); + } + uint32_t throw_op_num = throw_op - EX(func)->op_array.opcodes; uint32_t current_try_catch_offset = -1; @@ -4038,27 +4130,26 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV #else SAVE_OPLINE(); #endif + + if (zend_hash_num_elements(&EG(delayed_effects))) { + zend_handle_delayed_effects(); + } if (zend_atomic_bool_load_ex(&EG(timed_out))) { zend_timeout(); - } else if (zend_interrupt_function) { + } + if (zend_interrupt_function) { zend_interrupt_function(execute_data); - if (EG(exception)) { - /* We have to UNDEF result, because ZEND_HANDLE_EXCEPTION is going to free it */ - const zend_op *throw_op = EG(opline_before_exception); - - if (throw_op - && throw_op->result_type & (IS_TMP_VAR|IS_VAR) - && throw_op->opcode != ZEND_ADD_ARRAY_ELEMENT - && throw_op->opcode != ZEND_ADD_ARRAY_UNPACK - && throw_op->opcode != ZEND_ROPE_INIT - && throw_op->opcode != ZEND_ROPE_ADD) { - ZVAL_UNDEF(ZEND_CALL_VAR(EG(current_execute_data), throw_op->result.var)); - - } - } + } + if (UNEXPECTED(EG(exception))) { + zend_interrupt_consume(execute_data, opline); + opline = EG(exception_op); + ZEND_VM_CONTINUE(); + } + if (zend_interrupt_function) { ZEND_VM_ENTER(); + } else { + ZEND_VM_CONTINUE(); } - ZEND_VM_CONTINUE(); } static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { @@ -4082,6 +4173,9 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_I } call = _zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION, fbc, opline->extended_value, NULL); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -4169,6 +4263,9 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_I call = _zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION, fbc, opline->extended_value, NULL); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -4198,6 +4295,9 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_I call = _zend_vm_stack_push_call_frame_ex( opline->op1.num, ZEND_CALL_NESTED_FUNCTION, fbc, opline->extended_value, NULL); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -4217,6 +4317,9 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_I call = _zend_vm_stack_push_call_frame_ex( opline->op1.num, ZEND_CALL_NESTED_FUNCTION, fbc, opline->extended_value, NULL); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; ZEND_VM_NEXT_OPCODE(); @@ -4807,6 +4910,19 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_R } } +#if 0 + if (UNEXPECTED(zend_atomic_bool_load_ex(&EG(vm_interrupt)))) { + if (zend_hash_num_elements(&EG(delayed_effects))) { + zend_handle_delayed_effects(); + if (EG(exception)) { + ZEND_VM_ENTER(); + } + } + /* Do not reset EG(vm_interrupt) as it may have been set for other + * reasons */ + } +#endif + @@ -4887,9 +5003,24 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ } } } + +#if 0 + if (UNEXPECTED(zend_atomic_bool_load_ex(&EG(vm_interrupt)))) { + if (zend_hash_num_elements(&EG(delayed_effects))) { + zend_handle_delayed_effects(); + if (EG(exception)) { + ZEND_VM_ENTER(); + } + } + /* Do not reset EG(vm_interrupt) as it may have been set for other + * reasons */ + } +#endif + SAVE_OPLINE(); zend_observer_fcall_end(execute_data, return_value); if (return_value == &observer_retval) { zval_ptr_dtor_nogc(&observer_retval); }; + ZEND_VM_TAIL_CALL(zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)); } @@ -5388,6 +5519,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_INCLUDE_OR_EV inc_filename = RT_CONSTANT(opline, opline->op1); new_op_array = zend_include_or_eval(inc_filename, opline->extended_value); if (UNEXPECTED(EG(exception) != NULL)) { +handle_exception: if (new_op_array != ZEND_FAKE_OP_ARRAY && new_op_array != NULL) { @@ -5429,6 +5561,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_INCLUDE_OR_EV (Z_TYPE_INFO(EX(This)) & ZEND_CALL_HAS_THIS) | ZEND_CALL_NESTED_CODE | ZEND_CALL_HAS_SYMBOL_TABLE, (zend_function*)new_op_array, 0, Z_PTR(EX(This))); + if (UNEXPECTED(!call)) { + goto handle_exception; + } if (EX_CALL_INFO() & ZEND_CALL_HAS_SYMBOL_TABLE) { call->symbol_table = EX(symbol_table); @@ -5476,6 +5611,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_INCLUDE_OR_EV inc_filename = get_zval_ptr(opline->op1_type, opline->op1, BP_VAR_R); new_op_array = zend_include_or_eval(inc_filename, opline->extended_value); if (UNEXPECTED(EG(exception) != NULL)) { +handle_exception: FREE_OP(opline->op1_type, opline->op1.var); if (new_op_array != ZEND_FAKE_OP_ARRAY && new_op_array != NULL) { destroy_op_array(new_op_array); @@ -5516,6 +5652,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_INCLUDE_OR_EV (Z_TYPE_INFO(EX(This)) & ZEND_CALL_HAS_THIS) | ZEND_CALL_NESTED_CODE | ZEND_CALL_HAS_SYMBOL_TABLE, (zend_function*)new_op_array, 0, Z_PTR(EX(This))); + if (UNEXPECTED(!call)) { + goto handle_exception; + } if (EX_CALL_INFO() & ZEND_CALL_HAS_SYMBOL_TABLE) { call->symbol_table = EX(symbol_table); @@ -6980,6 +7119,10 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ call_info |= ZEND_CALL_RELEASE_THIS; } zend_execute_data *call = zend_vm_stack_push_call_frame(call_info, hook, 0, zobj); + if (UNEXPECTED(!call)) { + ZVAL_NULL(EX_VAR(opline->result.var)); + goto fetch_obj_r_finish; + } call->prev_execute_data = execute_data; call->call = NULL; call->return_value = EX_VAR(opline->result.var); @@ -7528,6 +7671,11 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, obj); + if (UNEXPECTED(!call)) { + + + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -7666,6 +7814,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_INIT_STATIC_M call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, ce); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -7740,6 +7891,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_INIT_USER_CAL call = zend_vm_stack_push_call_frame(call_info, func, opline->extended_value, object_or_called_scope); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -9723,6 +9877,10 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ call_info |= ZEND_CALL_RELEASE_THIS; } zend_execute_data *call = zend_vm_stack_push_call_frame(call_info, hook, 0, zobj); + if (UNEXPECTED(!call)) { + ZVAL_NULL(EX_VAR(opline->result.var)); + goto fetch_obj_r_finish; + } call->prev_execute_data = execute_data; call->call = NULL; call->return_value = EX_VAR(opline->result.var); @@ -10262,6 +10420,11 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, obj); + if (UNEXPECTED(!call)) { + + + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -10395,6 +10558,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_INIT_STATIC_M call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, ce); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -10467,6 +10633,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_INIT_USER_CAL call = zend_vm_stack_push_call_frame(call_info, func, opline->extended_value, object_or_called_scope); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -11187,6 +11356,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_INIT_STATIC_M call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, ce); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -11416,6 +11588,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_NEW_SPEC_CONS call = zend_vm_stack_push_call_frame( ZEND_CALL_FUNCTION, (zend_function *) &zend_pass_function, opline->extended_value, NULL); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } } else { if (EXPECTED(constructor->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&constructor->op_array))) { init_func_run_time_cache(&constructor->op_array); @@ -11426,6 +11601,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_NEW_SPEC_CONS constructor, opline->extended_value, Z_OBJ_P(result)); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } Z_ADDREF_P(result); } @@ -12022,6 +12200,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_INIT_PARENT_P call = zend_vm_stack_push_call_frame( ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_HAS_THIS, hook, opline->extended_value, Z_OBJ_P(ZEND_THIS)); + if (UNEXPECTED(!call)) { + UNDEF_RESULT(); + HANDLE_EXCEPTION(); + } if (EXPECTED(hook->type == ZEND_USER_FUNCTION)) { if (UNEXPECTED(!RUN_TIME_CACHE(&hook->op_array))) { init_func_run_time_cache(&hook->op_array); @@ -12033,6 +12215,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_INIT_PARENT_P call = zend_vm_stack_push_call_frame( ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_HAS_THIS, fbc, opline->extended_value, Z_OBJ_P(ZEND_THIS)); + if (UNEXPECTED(!call)) { + UNDEF_RESULT(); + HANDLE_EXCEPTION(); + } } call->prev_execute_data = EX(call); @@ -12323,6 +12509,10 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ call_info |= ZEND_CALL_RELEASE_THIS; } zend_execute_data *call = zend_vm_stack_push_call_frame(call_info, hook, 0, zobj); + if (UNEXPECTED(!call)) { + ZVAL_NULL(EX_VAR(opline->result.var)); + goto fetch_obj_r_finish; + } call->prev_execute_data = execute_data; call->call = NULL; call->return_value = EX_VAR(opline->result.var); @@ -12871,6 +13061,11 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_ call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, obj); + if (UNEXPECTED(!call)) { + + + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -13009,6 +13204,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_INIT_STATIC_M call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, ce); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -13083,6 +13281,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_INIT_USER_CAL call = zend_vm_stack_push_call_frame(call_info, func, opline->extended_value, object_or_called_scope); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -15767,6 +15968,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_FETCH_OBJ_R_S call_info |= ZEND_CALL_RELEASE_THIS; } zend_execute_data *call = zend_vm_stack_push_call_frame(call_info, hook, 0, zobj); + if (UNEXPECTED(!call)) { + ZVAL_NULL(EX_VAR(opline->result.var)); + goto fetch_obj_r_finish; + } call->prev_execute_data = execute_data; call->call = NULL; call->return_value = EX_VAR(opline->result.var); @@ -16258,6 +16463,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_FETCH_OBJ_R_S call_info |= ZEND_CALL_RELEASE_THIS; } zend_execute_data *call = zend_vm_stack_push_call_frame(call_info, hook, 0, zobj); + if (UNEXPECTED(!call)) { + ZVAL_NULL(EX_VAR(opline->result.var)); + goto fetch_obj_r_finish; + } call->prev_execute_data = execute_data; call->call = NULL; call->return_value = EX_VAR(opline->result.var); @@ -16686,6 +16895,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_FETCH_OBJ_R_S call_info |= ZEND_CALL_RELEASE_THIS; } zend_execute_data *call = zend_vm_stack_push_call_frame(call_info, hook, 0, zobj); + if (UNEXPECTED(!call)) { + ZVAL_NULL(EX_VAR(opline->result.var)); + goto fetch_obj_r_finish; + } call->prev_execute_data = execute_data; call->call = NULL; call->return_value = EX_VAR(opline->result.var); @@ -17180,6 +17393,19 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_R } } +#if 0 + if (UNEXPECTED(zend_atomic_bool_load_ex(&EG(vm_interrupt)))) { + if (zend_hash_num_elements(&EG(delayed_effects))) { + zend_handle_delayed_effects(); + if (EG(exception)) { + ZEND_VM_ENTER(); + } + } + /* Do not reset EG(vm_interrupt) as it may have been set for other + * reasons */ + } +#endif + @@ -17509,6 +17735,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_INCLUDE_OR_EV inc_filename = _get_zval_ptr_tmp(opline->op1.var EXECUTE_DATA_CC); new_op_array = zend_include_or_eval(inc_filename, opline->extended_value); if (UNEXPECTED(EG(exception) != NULL)) { +handle_exception: zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); if (new_op_array != ZEND_FAKE_OP_ARRAY && new_op_array != NULL) { destroy_op_array(new_op_array); @@ -17549,6 +17776,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_INCLUDE_OR_EV (Z_TYPE_INFO(EX(This)) & ZEND_CALL_HAS_THIS) | ZEND_CALL_NESTED_CODE | ZEND_CALL_HAS_SYMBOL_TABLE, (zend_function*)new_op_array, 0, Z_PTR(EX(This))); + if (UNEXPECTED(!call)) { + goto handle_exception; + } if (EX_CALL_INFO() & ZEND_CALL_HAS_SYMBOL_TABLE) { call->symbol_table = EX(symbol_table); @@ -19250,6 +19480,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_INIT_METHOD_C call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, obj); + if (UNEXPECTED(!call)) { + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -20824,6 +21058,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_INIT_METHOD_C call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, obj); + if (UNEXPECTED(!call)) { + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -22684,6 +22922,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_INIT_METHOD_C call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, obj); + if (UNEXPECTED(!call)) { + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -25641,6 +25883,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_INIT_STATIC_M call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, ce); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -28336,6 +28581,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_INIT_STATIC_M call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, ce); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -29541,6 +29789,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_INIT_STATIC_M call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, ce); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -30092,6 +30343,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_NEW_SPEC_VAR_ call = zend_vm_stack_push_call_frame( ZEND_CALL_FUNCTION, (zend_function *) &zend_pass_function, opline->extended_value, NULL); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } } else { if (EXPECTED(constructor->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&constructor->op_array))) { init_func_run_time_cache(&constructor->op_array); @@ -30102,6 +30356,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_NEW_SPEC_VAR_ constructor, opline->extended_value, Z_OBJ_P(result)); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } Z_ADDREF_P(result); } @@ -32212,6 +32469,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_INIT_STATIC_M call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, ce); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -33187,6 +33447,10 @@ static zend_always_inline ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV call_info |= ZEND_CALL_RELEASE_THIS; } zend_execute_data *call = zend_vm_stack_push_call_frame(call_info, hook, 0, zobj); + if (UNEXPECTED(!call)) { + ZVAL_NULL(EX_VAR(opline->result.var)); + goto fetch_obj_r_finish; + } call->prev_execute_data = execute_data; call->call = NULL; call->return_value = EX_VAR(opline->result.var); @@ -34286,6 +34550,11 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_I call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, obj); + if (UNEXPECTED(!call)) { + + + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -34424,6 +34693,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_INIT_STATIC_M call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, ce); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -35295,6 +35567,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_FETCH_OBJ_R_S call_info |= ZEND_CALL_RELEASE_THIS; } zend_execute_data *call = zend_vm_stack_push_call_frame(call_info, hook, 0, zobj); + if (UNEXPECTED(!call)) { + ZVAL_NULL(EX_VAR(opline->result.var)); + goto fetch_obj_r_finish; + } call->prev_execute_data = execute_data; call->call = NULL; call->return_value = EX_VAR(opline->result.var); @@ -36373,6 +36649,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_INIT_METHOD_C call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, obj); + if (UNEXPECTED(!call)) { + + + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -36506,6 +36787,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_INIT_STATIC_M call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, ce); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -36928,6 +37212,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_INIT_STATIC_M call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, ce); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -37137,6 +37424,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_NEW_SPEC_UNUS call = zend_vm_stack_push_call_frame( ZEND_CALL_FUNCTION, (zend_function *) &zend_pass_function, opline->extended_value, NULL); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } } else { if (EXPECTED(constructor->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&constructor->op_array))) { init_func_run_time_cache(&constructor->op_array); @@ -37147,6 +37437,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_NEW_SPEC_UNUS constructor, opline->extended_value, Z_OBJ_P(result)); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } Z_ADDREF_P(result); } @@ -37859,6 +38152,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_FETCH_OBJ_R_S call_info |= ZEND_CALL_RELEASE_THIS; } zend_execute_data *call = zend_vm_stack_push_call_frame(call_info, hook, 0, zobj); + if (UNEXPECTED(!call)) { + ZVAL_NULL(EX_VAR(opline->result.var)); + goto fetch_obj_r_finish; + } call->prev_execute_data = execute_data; call->call = NULL; call->return_value = EX_VAR(opline->result.var); @@ -38953,6 +39250,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_INIT_METHOD_C call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, obj); + if (UNEXPECTED(!call)) { + + + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -39091,6 +39393,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_INIT_STATIC_M call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, ce); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -39845,6 +40150,19 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_R } } +#if 0 + if (UNEXPECTED(zend_atomic_bool_load_ex(&EG(vm_interrupt)))) { + if (zend_hash_num_elements(&EG(delayed_effects))) { + zend_handle_delayed_effects(); + if (EG(exception)) { + ZEND_VM_ENTER(); + } + } + /* Do not reset EG(vm_interrupt) as it may have been set for other + * reasons */ + } +#endif + @@ -40182,6 +40500,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_INCLUDE_OR_EV inc_filename = _get_zval_ptr_cv_BP_VAR_R(opline->op1.var EXECUTE_DATA_CC); new_op_array = zend_include_or_eval(inc_filename, opline->extended_value); if (UNEXPECTED(EG(exception) != NULL)) { +handle_exception: if (new_op_array != ZEND_FAKE_OP_ARRAY && new_op_array != NULL) { @@ -40223,6 +40542,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_INCLUDE_OR_EV (Z_TYPE_INFO(EX(This)) & ZEND_CALL_HAS_THIS) | ZEND_CALL_NESTED_CODE | ZEND_CALL_HAS_SYMBOL_TABLE, (zend_function*)new_op_array, 0, Z_PTR(EX(This))); + if (UNEXPECTED(!call)) { + goto handle_exception; + } if (EX_CALL_INFO() & ZEND_CALL_HAS_SYMBOL_TABLE) { call->symbol_table = EX(symbol_table); @@ -42223,6 +42545,10 @@ static zend_always_inline ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV call_info |= ZEND_CALL_RELEASE_THIS; } zend_execute_data *call = zend_vm_stack_push_call_frame(call_info, hook, 0, zobj); + if (UNEXPECTED(!call)) { + ZVAL_NULL(EX_VAR(opline->result.var)); + goto fetch_obj_r_finish; + } call->prev_execute_data = execute_data; call->call = NULL; call->return_value = EX_VAR(opline->result.var); @@ -43903,6 +44229,11 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_I call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, obj); + if (UNEXPECTED(!call)) { + + + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -46056,6 +46387,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_FETCH_OBJ_R_S call_info |= ZEND_CALL_RELEASE_THIS; } zend_execute_data *call = zend_vm_stack_push_call_frame(call_info, hook, 0, zobj); + if (UNEXPECTED(!call)) { + ZVAL_NULL(EX_VAR(opline->result.var)); + goto fetch_obj_r_finish; + } call->prev_execute_data = execute_data; call->call = NULL; call->return_value = EX_VAR(opline->result.var); @@ -47712,6 +48047,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_INIT_METHOD_C call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, obj); + if (UNEXPECTED(!call)) { + + + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -51167,6 +51507,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_FETCH_OBJ_R_S call_info |= ZEND_CALL_RELEASE_THIS; } zend_execute_data *call = zend_vm_stack_push_call_frame(call_info, hook, 0, zobj); + if (UNEXPECTED(!call)) { + ZVAL_NULL(EX_VAR(opline->result.var)); + goto fetch_obj_r_finish; + } call->prev_execute_data = execute_data; call->call = NULL; call->return_value = EX_VAR(opline->result.var); @@ -52882,6 +53226,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_INIT_METHOD_C call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, obj); + if (UNEXPECTED(!call)) { + + + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -53498,12 +53847,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV ZEND_NULL_HANDLER( zend_error_noreturn(E_ERROR, "Invalid opcode %d/%d/%d.", OPLINE->opcode, OPLINE->op1_type, OPLINE->op2_type); } -#if ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL -static ZEND_COLD zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_FUNC_CCONV zend_interrupt(ZEND_OPCODE_HANDLER_ARGS) { - SAVE_OPLINE(); - return &call_interrupt_op; -} -#endif #if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) # undef ZEND_VM_TAIL_CALL @@ -53535,7 +53878,7 @@ static ZEND_COLD zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_F } while (0) # define ZEND_VM_DISPATCH_TO_LEAVE_HELPER(helper) opline = &call_leave_op; SAVE_OPLINE(); ZEND_VM_CONTINUE() # define ZEND_VM_INTERRUPT() ZEND_VM_TAIL_CALL(zend_interrupt_TAILCALL(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)) -# define ZEND_VM_ENTER_EX() ZEND_VM_INTERRUPT_CHECK(); ZEND_VM_CONTINUE() +# define ZEND_VM_ENTER_EX() ZEND_VM_CONTINUE() # define ZEND_VM_LEAVE() ZEND_VM_CONTINUE() static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV zend_interrupt_helper_SPEC_TAILCALL(ZEND_OPCODE_HANDLER_ARGS); @@ -53555,6 +53898,10 @@ static const zend_op call_interrupt_op = { .handler = zend_interrupt_helper_SPEC_TAILCALL, }; +static ZEND_COLD zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV zend_interrupt_TAILCALL(ZEND_OPCODE_HANDLER_ARGS) { + SAVE_OPLINE(); + ZEND_VM_TAIL_CALL(zend_interrupt_helper_SPEC_TAILCALL(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)); +} static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV_EX zend_add_helper_SPEC_TAILCALL(ZEND_OPCODE_HANDLER_ARGS_EX zval *op_1, zval *op_2); static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV_EX zend_sub_helper_SPEC_TAILCALL(ZEND_OPCODE_HANDLER_ARGS_EX zval *op_1, zval *op_2); static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV_EX zend_mul_helper_SPEC_TAILCALL(ZEND_OPCODE_HANDLER_ARGS_EX zval *op_1, zval *op_2); @@ -53959,9 +54306,14 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV zend } else if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) { OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func))); } + EG(vm_stack_top) = (zval*)execute_data; execute_data = EX(prev_execute_data); + if (UNEXPECTED(zend_atomic_bool_load_ex(&EG(vm_interrupt)))) { + zend_fcall_interrupt(execute_data); + } + if (UNEXPECTED(EG(exception) != NULL)) { zend_rethrow_exception(execute_data); HANDLE_EXCEPTION_LEAVE(); @@ -53998,6 +54350,10 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV zend execute_data = EX(prev_execute_data); zend_vm_stack_free_call_frame_ex(call_info, old_execute_data); + if (UNEXPECTED(zend_atomic_bool_load_ex(&EG(vm_interrupt)))) { + zend_fcall_interrupt(execute_data); + } + if (UNEXPECTED(EG(exception) != NULL)) { zend_rethrow_exception(execute_data); HANDLE_EXCEPTION_LEAVE(); @@ -54024,6 +54380,11 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV zend ZEND_ADD_CALL_FLAG(execute_data, ZEND_CALL_NEEDS_REATTACH); } } + + if (UNEXPECTED(zend_atomic_bool_load_ex(&EG(vm_interrupt)))) { + zend_fcall_interrupt(execute_data); + } + if (UNEXPECTED(EG(exception) != NULL)) { zend_rethrow_exception(execute_data); HANDLE_EXCEPTION_LEAVE(); @@ -54050,6 +54411,11 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV zend if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) { OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func))); } + + if (UNEXPECTED(zend_atomic_bool_load_ex(&EG(vm_interrupt)))) { + zend_fcall_interrupt(EG(current_execute_data)); + } + ZEND_VM_RETURN(); } else /* if (call_kind == ZEND_CALL_TOP_CODE) */ { zend_array *symbol_table = EX(symbol_table); @@ -54075,6 +54441,11 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV zend } } EG(current_execute_data) = EX(prev_execute_data); + + if (UNEXPECTED(zend_atomic_bool_load_ex(&EG(vm_interrupt)))) { + zend_fcall_interrupt(EG(current_execute_data)); + } + ZEND_VM_RETURN(); } } @@ -56073,11 +56444,69 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_HANDLE_EXCEPTION_S { const zend_op *throw_op = EG(opline_before_exception); + if (zend_hash_num_elements(&EG(delayed_effects))) { + zend_object *orig_exception = EG(exception); + EX(opline) = EG(opline_before_exception); + EG(exception) = NULL; + + zend_handle_delayed_effects(); + + if (EG(exception)) { + zend_exception_set_previous(EG(exception), orig_exception); + } else { + EG(exception) = orig_exception; + EX(opline) = EG(exception_op); + } + } + + if (throw_op && EG(exception)->ce == zend_ce_promoted_error_exception) { + zend_object *promoted = EG(exception); + + zval *severity_zv = zend_read_property_ex( + zend_ce_error_exception, promoted, ZSTR_KNOWN(ZEND_STR_SEVERITY), /* silent */ 1, NULL); + zval *message_zv = zend_read_property_ex( + zend_ce_exception, promoted, ZSTR_KNOWN(ZEND_STR_MESSAGE), 1, NULL); + zval *file_zv = zend_read_property_ex( + zend_ce_exception, promoted, ZSTR_KNOWN(ZEND_STR_FILE), 1, NULL); + zval *line_zv = zend_read_property_ex( + zend_ce_exception, promoted, ZSTR_KNOWN(ZEND_STR_LINE), 1, NULL); + + int error_type = (int) Z_LVAL_P(severity_zv) & E_ALL; + if (!error_type) { + error_type = E_ERROR; + } + zend_string *error_message = zend_string_copy(Z_STR_P(message_zv)); + zend_string *error_file = zend_string_copy(Z_STR_P(file_zv)); + zend_long error_line = Z_LVAL_P(line_zv); + + EG(exception) = NULL; + EX(opline) = throw_op; + zend_error_zstr_at(error_type | E_NO_DELAY, error_file, error_line, error_message); + + zend_string_release(error_file); + zend_string_release(error_message); + + if (!EG(exception)) { + EG(exception) = promoted; + } else { + OBJ_RELEASE(promoted); + } + } + /* Exception was thrown before executing any op */ if (UNEXPECTED(!throw_op)) { ZEND_VM_DISPATCH_TO_HELPER(zend_dispatch_try_catch_finally_helper_SPEC_TAILCALL(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX -1, 0)); } + /* Exception was thrown from the ZEND_DO_FCALL interrupt handler just + * before entering EG(call_trampoline_op). */ + if (UNEXPECTED(throw_op == &EG(call_trampoline_op))) { + ZEND_ASSERT(EX(func)->op_array.opcodes == &EG(call_trampoline_op)); + zend_string_release_ex(EX(func)->op_array.function_name, 0); + zend_free_trampoline(EX(func)); + ZEND_VM_DISPATCH_TO_HELPER(zend_dispatch_try_catch_finally_helper_SPEC_TAILCALL(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_EX -1, 0)); + } + uint32_t throw_op_num = throw_op - EX(func)->op_array.opcodes; uint32_t current_try_catch_offset = -1; @@ -56712,27 +57141,26 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV zend #else SAVE_OPLINE(); #endif + + if (zend_hash_num_elements(&EG(delayed_effects))) { + zend_handle_delayed_effects(); + } if (zend_atomic_bool_load_ex(&EG(timed_out))) { zend_timeout(); - } else if (zend_interrupt_function) { + } + if (zend_interrupt_function) { zend_interrupt_function(execute_data); - if (EG(exception)) { - /* We have to UNDEF result, because ZEND_HANDLE_EXCEPTION is going to free it */ - const zend_op *throw_op = EG(opline_before_exception); - - if (throw_op - && throw_op->result_type & (IS_TMP_VAR|IS_VAR) - && throw_op->opcode != ZEND_ADD_ARRAY_ELEMENT - && throw_op->opcode != ZEND_ADD_ARRAY_UNPACK - && throw_op->opcode != ZEND_ROPE_INIT - && throw_op->opcode != ZEND_ROPE_ADD) { - ZVAL_UNDEF(ZEND_CALL_VAR(EG(current_execute_data), throw_op->result.var)); - - } - } + } + if (UNEXPECTED(EG(exception))) { + zend_interrupt_consume(execute_data, opline); + opline = EG(exception_op); + ZEND_VM_CONTINUE(); + } + if (zend_interrupt_function) { ZEND_VM_ENTER(); + } else { + ZEND_VM_CONTINUE(); } - ZEND_VM_CONTINUE(); } static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_TAILCALL_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { @@ -56756,6 +57184,9 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_INIT_F } call = _zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION, fbc, opline->extended_value, NULL); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -56843,6 +57274,9 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_INIT_N call = _zend_vm_stack_push_call_frame(ZEND_CALL_NESTED_FUNCTION, fbc, opline->extended_value, NULL); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -56872,6 +57306,9 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_INIT_F call = _zend_vm_stack_push_call_frame_ex( opline->op1.num, ZEND_CALL_NESTED_FUNCTION, fbc, opline->extended_value, NULL); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -56891,6 +57328,9 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_INIT_F call = _zend_vm_stack_push_call_frame_ex( opline->op1.num, ZEND_CALL_NESTED_FUNCTION, fbc, opline->extended_value, NULL); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; ZEND_VM_NEXT_OPCODE(); @@ -57481,6 +57921,19 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_RETURN } } +#if 0 + if (UNEXPECTED(zend_atomic_bool_load_ex(&EG(vm_interrupt)))) { + if (zend_hash_num_elements(&EG(delayed_effects))) { + zend_handle_delayed_effects(); + if (EG(exception)) { + ZEND_VM_ENTER(); + } + } + /* Do not reset EG(vm_interrupt) as it may have been set for other + * reasons */ + } +#endif + @@ -57561,9 +58014,24 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_RETUR } } } + +#if 0 + if (UNEXPECTED(zend_atomic_bool_load_ex(&EG(vm_interrupt)))) { + if (zend_hash_num_elements(&EG(delayed_effects))) { + zend_handle_delayed_effects(); + if (EG(exception)) { + ZEND_VM_ENTER(); + } + } + /* Do not reset EG(vm_interrupt) as it may have been set for other + * reasons */ + } +#endif + SAVE_OPLINE(); zend_observer_fcall_end(execute_data, return_value); if (return_value == &observer_retval) { zval_ptr_dtor_nogc(&observer_retval); }; + ZEND_VM_DISPATCH_TO_LEAVE_HELPER(zend_leave_helper_SPEC_TAILCALL); } @@ -58062,6 +58530,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_INCLUDE_OR_EVAL_SP inc_filename = RT_CONSTANT(opline, opline->op1); new_op_array = zend_include_or_eval(inc_filename, opline->extended_value); if (UNEXPECTED(EG(exception) != NULL)) { +handle_exception: if (new_op_array != ZEND_FAKE_OP_ARRAY && new_op_array != NULL) { @@ -58103,6 +58572,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_INCLUDE_OR_EVAL_SP (Z_TYPE_INFO(EX(This)) & ZEND_CALL_HAS_THIS) | ZEND_CALL_NESTED_CODE | ZEND_CALL_HAS_SYMBOL_TABLE, (zend_function*)new_op_array, 0, Z_PTR(EX(This))); + if (UNEXPECTED(!call)) { + goto handle_exception; + } if (EX_CALL_INFO() & ZEND_CALL_HAS_SYMBOL_TABLE) { call->symbol_table = EX(symbol_table); @@ -58150,6 +58622,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_INCLUDE_OR_EVAL_SP inc_filename = get_zval_ptr(opline->op1_type, opline->op1, BP_VAR_R); new_op_array = zend_include_or_eval(inc_filename, opline->extended_value); if (UNEXPECTED(EG(exception) != NULL)) { +handle_exception: FREE_OP(opline->op1_type, opline->op1.var); if (new_op_array != ZEND_FAKE_OP_ARRAY && new_op_array != NULL) { destroy_op_array(new_op_array); @@ -58190,6 +58663,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_INCLUDE_OR_EVAL_SP (Z_TYPE_INFO(EX(This)) & ZEND_CALL_HAS_THIS) | ZEND_CALL_NESTED_CODE | ZEND_CALL_HAS_SYMBOL_TABLE, (zend_function*)new_op_array, 0, Z_PTR(EX(This))); + if (UNEXPECTED(!call)) { + goto handle_exception; + } if (EX_CALL_INFO() & ZEND_CALL_HAS_SYMBOL_TABLE) { call->symbol_table = EX(symbol_table); @@ -59654,6 +60130,10 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_FETCH call_info |= ZEND_CALL_RELEASE_THIS; } zend_execute_data *call = zend_vm_stack_push_call_frame(call_info, hook, 0, zobj); + if (UNEXPECTED(!call)) { + ZVAL_NULL(EX_VAR(opline->result.var)); + goto fetch_obj_r_finish; + } call->prev_execute_data = execute_data; call->call = NULL; call->return_value = EX_VAR(opline->result.var); @@ -60202,6 +60682,11 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_INIT_ call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, obj); + if (UNEXPECTED(!call)) { + + + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -60340,6 +60825,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_INIT_STATIC_METHOD call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, ce); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -60414,6 +60902,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_INIT_USER_CALL_SPE call = zend_vm_stack_push_call_frame(call_info, func, opline->extended_value, object_or_called_scope); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -62397,6 +62888,10 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_FETCH call_info |= ZEND_CALL_RELEASE_THIS; } zend_execute_data *call = zend_vm_stack_push_call_frame(call_info, hook, 0, zobj); + if (UNEXPECTED(!call)) { + ZVAL_NULL(EX_VAR(opline->result.var)); + goto fetch_obj_r_finish; + } call->prev_execute_data = execute_data; call->call = NULL; call->return_value = EX_VAR(opline->result.var); @@ -62936,6 +63431,11 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_INIT_ call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, obj); + if (UNEXPECTED(!call)) { + + + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -63069,6 +63569,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_INIT_STATIC_METHOD call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, ce); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -63141,6 +63644,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_INIT_USER_CALL_SPE call = zend_vm_stack_push_call_frame(call_info, func, opline->extended_value, object_or_called_scope); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -63759,6 +64265,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_INIT_STATIC_METHOD call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, ce); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -63988,6 +64497,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_NEW_SPEC_CONST_UNU call = zend_vm_stack_push_call_frame( ZEND_CALL_FUNCTION, (zend_function *) &zend_pass_function, opline->extended_value, NULL); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } } else { if (EXPECTED(constructor->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&constructor->op_array))) { init_func_run_time_cache(&constructor->op_array); @@ -63998,6 +64510,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_NEW_SPEC_CONST_UNU constructor, opline->extended_value, Z_OBJ_P(result)); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } Z_ADDREF_P(result); } @@ -64594,6 +65109,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_INIT_PARENT_PROPER call = zend_vm_stack_push_call_frame( ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_HAS_THIS, hook, opline->extended_value, Z_OBJ_P(ZEND_THIS)); + if (UNEXPECTED(!call)) { + UNDEF_RESULT(); + HANDLE_EXCEPTION(); + } if (EXPECTED(hook->type == ZEND_USER_FUNCTION)) { if (UNEXPECTED(!RUN_TIME_CACHE(&hook->op_array))) { init_func_run_time_cache(&hook->op_array); @@ -64605,6 +65124,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_INIT_PARENT_PROPER call = zend_vm_stack_push_call_frame( ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_HAS_THIS, fbc, opline->extended_value, Z_OBJ_P(ZEND_THIS)); + if (UNEXPECTED(!call)) { + UNDEF_RESULT(); + HANDLE_EXCEPTION(); + } } call->prev_execute_data = EX(call); @@ -64895,6 +65418,10 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_FETCH call_info |= ZEND_CALL_RELEASE_THIS; } zend_execute_data *call = zend_vm_stack_push_call_frame(call_info, hook, 0, zobj); + if (UNEXPECTED(!call)) { + ZVAL_NULL(EX_VAR(opline->result.var)); + goto fetch_obj_r_finish; + } call->prev_execute_data = execute_data; call->call = NULL; call->return_value = EX_VAR(opline->result.var); @@ -65443,6 +65970,11 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_INIT_ call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, obj); + if (UNEXPECTED(!call)) { + + + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -65581,6 +66113,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_INIT_STATIC_METHOD call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, ce); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -65655,6 +66190,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_INIT_USER_CALL_SPE call = zend_vm_stack_push_call_frame(call_info, func, opline->extended_value, object_or_called_scope); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -68339,6 +68877,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_FETCH_OBJ_R_SPEC_T call_info |= ZEND_CALL_RELEASE_THIS; } zend_execute_data *call = zend_vm_stack_push_call_frame(call_info, hook, 0, zobj); + if (UNEXPECTED(!call)) { + ZVAL_NULL(EX_VAR(opline->result.var)); + goto fetch_obj_r_finish; + } call->prev_execute_data = execute_data; call->call = NULL; call->return_value = EX_VAR(opline->result.var); @@ -68830,6 +69372,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_FETCH_OBJ_R_SPEC_T call_info |= ZEND_CALL_RELEASE_THIS; } zend_execute_data *call = zend_vm_stack_push_call_frame(call_info, hook, 0, zobj); + if (UNEXPECTED(!call)) { + ZVAL_NULL(EX_VAR(opline->result.var)); + goto fetch_obj_r_finish; + } call->prev_execute_data = execute_data; call->call = NULL; call->return_value = EX_VAR(opline->result.var); @@ -69258,6 +69804,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_FETCH_OBJ_R_SPEC_T call_info |= ZEND_CALL_RELEASE_THIS; } zend_execute_data *call = zend_vm_stack_push_call_frame(call_info, hook, 0, zobj); + if (UNEXPECTED(!call)) { + ZVAL_NULL(EX_VAR(opline->result.var)); + goto fetch_obj_r_finish; + } call->prev_execute_data = execute_data; call->call = NULL; call->return_value = EX_VAR(opline->result.var); @@ -69752,6 +70302,19 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_RETURN } } +#if 0 + if (UNEXPECTED(zend_atomic_bool_load_ex(&EG(vm_interrupt)))) { + if (zend_hash_num_elements(&EG(delayed_effects))) { + zend_handle_delayed_effects(); + if (EG(exception)) { + ZEND_VM_ENTER(); + } + } + /* Do not reset EG(vm_interrupt) as it may have been set for other + * reasons */ + } +#endif + @@ -70081,6 +70644,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_INCLUDE_OR_EVAL_SP inc_filename = _get_zval_ptr_tmp(opline->op1.var EXECUTE_DATA_CC); new_op_array = zend_include_or_eval(inc_filename, opline->extended_value); if (UNEXPECTED(EG(exception) != NULL)) { +handle_exception: zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); if (new_op_array != ZEND_FAKE_OP_ARRAY && new_op_array != NULL) { destroy_op_array(new_op_array); @@ -70121,6 +70685,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_INCLUDE_OR_EVAL_SP (Z_TYPE_INFO(EX(This)) & ZEND_CALL_HAS_THIS) | ZEND_CALL_NESTED_CODE | ZEND_CALL_HAS_SYMBOL_TABLE, (zend_function*)new_op_array, 0, Z_PTR(EX(This))); + if (UNEXPECTED(!call)) { + goto handle_exception; + } if (EX_CALL_INFO() & ZEND_CALL_HAS_SYMBOL_TABLE) { call->symbol_table = EX(symbol_table); @@ -71822,6 +72389,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_INIT_METHOD_CALL_S call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, obj); + if (UNEXPECTED(!call)) { + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -73396,6 +73967,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_INIT_METHOD_CALL_S call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, obj); + if (UNEXPECTED(!call)) { + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -75156,6 +75731,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_INIT_METHOD_CALL_S call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, obj); + if (UNEXPECTED(!call)) { + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -78113,6 +78692,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_INIT_STATIC_METHOD call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, ce); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -80808,6 +81390,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_INIT_STATIC_METHOD call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, ce); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -82013,6 +82598,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_INIT_STATIC_METHOD call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, ce); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -82564,6 +83152,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_NEW_SPEC_VAR_UNUSE call = zend_vm_stack_push_call_frame( ZEND_CALL_FUNCTION, (zend_function *) &zend_pass_function, opline->extended_value, NULL); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } } else { if (EXPECTED(constructor->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&constructor->op_array))) { init_func_run_time_cache(&constructor->op_array); @@ -82574,6 +83165,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_NEW_SPEC_VAR_UNUSE constructor, opline->extended_value, Z_OBJ_P(result)); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } Z_ADDREF_P(result); } @@ -84684,6 +85278,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_INIT_STATIC_METHOD call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, ce); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -85659,6 +86256,10 @@ static zend_always_inline ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND call_info |= ZEND_CALL_RELEASE_THIS; } zend_execute_data *call = zend_vm_stack_push_call_frame(call_info, hook, 0, zobj); + if (UNEXPECTED(!call)) { + ZVAL_NULL(EX_VAR(opline->result.var)); + goto fetch_obj_r_finish; + } call->prev_execute_data = execute_data; call->call = NULL; call->return_value = EX_VAR(opline->result.var); @@ -86758,6 +87359,11 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_INIT_M call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, obj); + if (UNEXPECTED(!call)) { + + + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -86896,6 +87502,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_INIT_STATIC_METHOD call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, ce); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -87767,6 +88376,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_FETCH_OBJ_R_SPEC_U call_info |= ZEND_CALL_RELEASE_THIS; } zend_execute_data *call = zend_vm_stack_push_call_frame(call_info, hook, 0, zobj); + if (UNEXPECTED(!call)) { + ZVAL_NULL(EX_VAR(opline->result.var)); + goto fetch_obj_r_finish; + } call->prev_execute_data = execute_data; call->call = NULL; call->return_value = EX_VAR(opline->result.var); @@ -88845,6 +89458,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_INIT_METHOD_CALL_S call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, obj); + if (UNEXPECTED(!call)) { + + + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -88978,6 +89596,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_INIT_STATIC_METHOD call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, ce); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -89400,6 +90021,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_INIT_STATIC_METHOD call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, ce); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -89609,6 +90233,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_NEW_SPEC_UNUSED_UN call = zend_vm_stack_push_call_frame( ZEND_CALL_FUNCTION, (zend_function *) &zend_pass_function, opline->extended_value, NULL); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } } else { if (EXPECTED(constructor->type == ZEND_USER_FUNCTION) && UNEXPECTED(!RUN_TIME_CACHE(&constructor->op_array))) { init_func_run_time_cache(&constructor->op_array); @@ -89619,6 +90246,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_NEW_SPEC_UNUSED_UN constructor, opline->extended_value, Z_OBJ_P(result)); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } Z_ADDREF_P(result); } @@ -90331,6 +90961,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_FETCH_OBJ_R_SPEC_U call_info |= ZEND_CALL_RELEASE_THIS; } zend_execute_data *call = zend_vm_stack_push_call_frame(call_info, hook, 0, zobj); + if (UNEXPECTED(!call)) { + ZVAL_NULL(EX_VAR(opline->result.var)); + goto fetch_obj_r_finish; + } call->prev_execute_data = execute_data; call->call = NULL; call->return_value = EX_VAR(opline->result.var); @@ -91425,6 +92059,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_INIT_METHOD_CALL_S call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, obj); + if (UNEXPECTED(!call)) { + + + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -91563,6 +92202,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_INIT_STATIC_METHOD call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, ce); + if (UNEXPECTED(!call)) { + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -92317,6 +92959,19 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_RETURN } } +#if 0 + if (UNEXPECTED(zend_atomic_bool_load_ex(&EG(vm_interrupt)))) { + if (zend_hash_num_elements(&EG(delayed_effects))) { + zend_handle_delayed_effects(); + if (EG(exception)) { + ZEND_VM_ENTER(); + } + } + /* Do not reset EG(vm_interrupt) as it may have been set for other + * reasons */ + } +#endif + @@ -92654,6 +93309,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_INCLUDE_OR_EVAL_SP inc_filename = _get_zval_ptr_cv_BP_VAR_R(opline->op1.var EXECUTE_DATA_CC); new_op_array = zend_include_or_eval(inc_filename, opline->extended_value); if (UNEXPECTED(EG(exception) != NULL)) { +handle_exception: if (new_op_array != ZEND_FAKE_OP_ARRAY && new_op_array != NULL) { @@ -92695,6 +93351,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_INCLUDE_OR_EVAL_SP (Z_TYPE_INFO(EX(This)) & ZEND_CALL_HAS_THIS) | ZEND_CALL_NESTED_CODE | ZEND_CALL_HAS_SYMBOL_TABLE, (zend_function*)new_op_array, 0, Z_PTR(EX(This))); + if (UNEXPECTED(!call)) { + goto handle_exception; + } if (EX_CALL_INFO() & ZEND_CALL_HAS_SYMBOL_TABLE) { call->symbol_table = EX(symbol_table); @@ -94695,6 +95354,10 @@ static zend_always_inline ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND call_info |= ZEND_CALL_RELEASE_THIS; } zend_execute_data *call = zend_vm_stack_push_call_frame(call_info, hook, 0, zobj); + if (UNEXPECTED(!call)) { + ZVAL_NULL(EX_VAR(opline->result.var)); + goto fetch_obj_r_finish; + } call->prev_execute_data = execute_data; call->call = NULL; call->return_value = EX_VAR(opline->result.var); @@ -96375,6 +97038,11 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_INIT_M call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, obj); + if (UNEXPECTED(!call)) { + + + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -98528,6 +99196,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_FETCH_OBJ_R_SPEC_C call_info |= ZEND_CALL_RELEASE_THIS; } zend_execute_data *call = zend_vm_stack_push_call_frame(call_info, hook, 0, zobj); + if (UNEXPECTED(!call)) { + ZVAL_NULL(EX_VAR(opline->result.var)); + goto fetch_obj_r_finish; + } call->prev_execute_data = execute_data; call->call = NULL; call->return_value = EX_VAR(opline->result.var); @@ -100184,6 +100856,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_INIT_METHOD_CALL_S call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, obj); + if (UNEXPECTED(!call)) { + + + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -103537,6 +104214,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_FETCH_OBJ_R_SPEC_C call_info |= ZEND_CALL_RELEASE_THIS; } zend_execute_data *call = zend_vm_stack_push_call_frame(call_info, hook, 0, zobj); + if (UNEXPECTED(!call)) { + ZVAL_NULL(EX_VAR(opline->result.var)); + goto fetch_obj_r_finish; + } call->prev_execute_data = execute_data; call->call = NULL; call->return_value = EX_VAR(opline->result.var); @@ -105252,6 +105933,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_INIT_METHOD_CALL_S call = zend_vm_stack_push_call_frame(call_info, fbc, opline->extended_value, obj); + if (UNEXPECTED(!call)) { + + + HANDLE_EXCEPTION(); + } call->prev_execute_data = EX(call); EX(call) = call; @@ -105873,10 +106559,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV ZEND_HALT_TAILCALL_HAND return (zend_op*) ZEND_VM_ENTER_BIT; } -static ZEND_COLD zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV zend_interrupt_TAILCALL(ZEND_OPCODE_HANDLER_ARGS) { - SAVE_OPLINE(); - ZEND_VM_TAIL_CALL(zend_interrupt_helper_SPEC_TAILCALL(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)); -} /* The following helpers can not tailcall due to signature mismatch. Redefine some macros so they do not enforce tailcall. */ #pragma push_macro("ZEND_VM_CONTINUE") #undef ZEND_VM_CONTINUE @@ -106265,7 +106947,7 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV_EX z if (op_num < try_catch->catch_op && ex) { /* Go to catch block */ cleanup_live_vars(execute_data, op_num, try_catch->catch_op); - ZEND_VM_JMP_EX(&EX(func)->op_array.opcodes[try_catch->catch_op], 0); + ZEND_VM_JMP_FWD_EX(&EX(func)->op_array.opcodes[try_catch->catch_op], 0); } else if (op_num < try_catch->finally_op) { if (ex && zend_is_unwind_exit(ex)) { @@ -106279,7 +106961,7 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV_EX z Z_OBJ_P(fast_call) = EG(exception); EG(exception) = NULL; Z_OPLINE_NUM_P(fast_call) = (uint32_t)-1; - ZEND_VM_JMP_EX(&EX(func)->op_array.opcodes[try_catch->finally_op], 0); + ZEND_VM_JMP_FWD_EX(&EX(func)->op_array.opcodes[try_catch->finally_op], 0); } else if (op_num < try_catch->finally_end) { zval *fast_call = EX_VAR(EX(func)->op_array.opcodes[try_catch->finally_end].op1.var); @@ -110286,9 +110968,14 @@ ZEND_API void execute_ex(zend_execute_data *ex) } else if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) { OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func))); } + EG(vm_stack_top) = (zval*)execute_data; execute_data = EX(prev_execute_data); + if (UNEXPECTED(zend_atomic_bool_load_ex(&EG(vm_interrupt)))) { + zend_fcall_interrupt(execute_data); + } + if (UNEXPECTED(EG(exception) != NULL)) { zend_rethrow_exception(execute_data); HANDLE_EXCEPTION_LEAVE(); @@ -110325,6 +111012,10 @@ ZEND_API void execute_ex(zend_execute_data *ex) execute_data = EX(prev_execute_data); zend_vm_stack_free_call_frame_ex(call_info, old_execute_data); + if (UNEXPECTED(zend_atomic_bool_load_ex(&EG(vm_interrupt)))) { + zend_fcall_interrupt(execute_data); + } + if (UNEXPECTED(EG(exception) != NULL)) { zend_rethrow_exception(execute_data); HANDLE_EXCEPTION_LEAVE(); @@ -110351,6 +111042,11 @@ ZEND_API void execute_ex(zend_execute_data *ex) ZEND_ADD_CALL_FLAG(execute_data, ZEND_CALL_NEEDS_REATTACH); } } + + if (UNEXPECTED(zend_atomic_bool_load_ex(&EG(vm_interrupt)))) { + zend_fcall_interrupt(execute_data); + } + if (UNEXPECTED(EG(exception) != NULL)) { zend_rethrow_exception(execute_data); HANDLE_EXCEPTION_LEAVE(); @@ -110377,6 +111073,11 @@ ZEND_API void execute_ex(zend_execute_data *ex) if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) { OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func))); } + + if (UNEXPECTED(zend_atomic_bool_load_ex(&EG(vm_interrupt)))) { + zend_fcall_interrupt(EG(current_execute_data)); + } + ZEND_VM_RETURN(); } else /* if (call_kind == ZEND_CALL_TOP_CODE) */ { zend_array *symbol_table = EX(symbol_table); @@ -110402,6 +111103,11 @@ ZEND_API void execute_ex(zend_execute_data *ex) } } EG(current_execute_data) = EX(prev_execute_data); + + if (UNEXPECTED(zend_atomic_bool_load_ex(&EG(vm_interrupt)))) { + zend_fcall_interrupt(EG(current_execute_data)); + } + ZEND_VM_RETURN(); } } @@ -110787,6 +111493,19 @@ ZEND_API void execute_ex(zend_execute_data *ex) } } +#if 0 + if (UNEXPECTED(zend_atomic_bool_load_ex(&EG(vm_interrupt)))) { + if (zend_hash_num_elements(&EG(delayed_effects))) { + zend_handle_delayed_effects(); + if (EG(exception)) { + ZEND_VM_ENTER(); + } + } + /* Do not reset EG(vm_interrupt) as it may have been set for other + * reasons */ + } +#endif + @@ -110869,9 +111588,24 @@ ZEND_API void execute_ex(zend_execute_data *ex) } } } + +#if 0 + if (UNEXPECTED(zend_atomic_bool_load_ex(&EG(vm_interrupt)))) { + if (zend_hash_num_elements(&EG(delayed_effects))) { + zend_handle_delayed_effects(); + if (EG(exception)) { + ZEND_VM_ENTER(); + } + } + /* Do not reset EG(vm_interrupt) as it may have been set for other + * reasons */ + } +#endif + SAVE_OPLINE(); zend_observer_fcall_end(execute_data, return_value); if (return_value == &observer_retval) { zval_ptr_dtor_nogc(&observer_retval); }; + goto zend_leave_helper_SPEC_LABEL; } @@ -112501,6 +113235,19 @@ ZEND_API void execute_ex(zend_execute_data *ex) } } +#if 0 + if (UNEXPECTED(zend_atomic_bool_load_ex(&EG(vm_interrupt)))) { + if (zend_hash_num_elements(&EG(delayed_effects))) { + zend_handle_delayed_effects(); + if (EG(exception)) { + ZEND_VM_ENTER(); + } + } + /* Do not reset EG(vm_interrupt) as it may have been set for other + * reasons */ + } +#endif + @@ -114375,6 +115122,19 @@ ZEND_API void execute_ex(zend_execute_data *ex) } } +#if 0 + if (UNEXPECTED(zend_atomic_bool_load_ex(&EG(vm_interrupt)))) { + if (zend_hash_num_elements(&EG(delayed_effects))) { + zend_handle_delayed_effects(); + if (EG(exception)) { + ZEND_VM_ENTER(); + } + } + /* Do not reset EG(vm_interrupt) as it may have been set for other + * reasons */ + } +#endif + diff --git a/Zend/zend_vm_gen.php b/Zend/zend_vm_gen.php index 8e65bc0a28ea..ab8a6f5a897f 100755 --- a/Zend/zend_vm_gen.php +++ b/Zend/zend_vm_gen.php @@ -1726,6 +1726,17 @@ function gen_executor_code($f, $spec, $kind, $prolog, &$switch_labels = array()) $delayed_helpers = fopen("php://memory", "w+"); + switch ($kind) { + case ZEND_VM_KIND_CALL: + out($f, "#if ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL\n"); + gen_interrupt_func($f, $kind, $spec); + out($f, "#endif\n"); + break; + case ZEND_VM_KIND_TAILCALL: + gen_interrupt_func($f, $kind, $spec); + break; + } + if ($spec) { // Produce specialized executor $op1t = $op_types_ex; @@ -1814,14 +1825,10 @@ function gen_executor_code($f, $spec, $kind, $prolog, &$switch_labels = array()) switch ($kind) { case ZEND_VM_KIND_CALL: gen_null_handler($f, $kind); - out($f, "#if ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL\n"); - gen_interrupt_func($f, $kind, $spec); - out($f, "#endif\n"); break; case ZEND_VM_KIND_TAILCALL: gen_null_handler($f, $kind); gen_halt_handler($f, $kind); - gen_interrupt_func($f, $kind, $spec); break; case ZEND_VM_KIND_SWITCH: out($f,"default: ZEND_NULL_LABEL:\n"); @@ -2027,7 +2034,7 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) out($f,"#define HANDLE_EXCEPTION() ZEND_ASSERT(EG(exception)); LOAD_OPLINE(); ZEND_VM_CONTINUE()\n"); out($f,"#define HANDLE_EXCEPTION_LEAVE() ZEND_ASSERT(EG(exception)); LOAD_OPLINE(); ZEND_VM_LEAVE()\n"); out($f,"#if defined(ZEND_VM_FP_GLOBAL_REG)\n"); - out($f,"# define ZEND_VM_ENTER_EX() ZEND_VM_INTERRUPT_CHECK(); ZEND_VM_CONTINUE()\n"); + out($f,"# define ZEND_VM_ENTER_EX() ZEND_VM_CONTINUE()\n"); out($f,"# define ZEND_VM_ENTER() execute_data = EG(current_execute_data); LOAD_OPLINE(); ZEND_VM_ENTER_EX()\n"); out($f,"# define ZEND_VM_LEAVE() ZEND_VM_CONTINUE()\n"); out($f,"#elif defined(ZEND_VM_IP_GLOBAL_REG)\n"); @@ -2040,7 +2047,11 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) out($f,"# define ZEND_VM_ENTER() execute_data = EG(current_execute_data); LOAD_OPLINE(); ZEND_VM_ENTER_EX()\n"); out($f,"# define ZEND_VM_LEAVE() return (zend_op*)((uintptr_t)opline | ZEND_VM_ENTER_BIT)\n"); out($f,"#endif\n"); - out($f,"#define ZEND_VM_INTERRUPT() ZEND_VM_TAIL_CALL(zend_interrupt_helper".($spec?"_SPEC":"")."(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU));\n"); + out($f,"#if ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL\n"); + out($f,"# define ZEND_VM_INTERRUPT() return zend_interrupt(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)\n"); + out($f,"#else\n"); + out($f,"# define ZEND_VM_INTERRUPT() ZEND_VM_TAIL_CALL(zend_interrupt_helper".($spec?"_SPEC":"")."(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU));\n"); + out($f,"#endif\n"); out($f,"#ifdef ZEND_VM_FP_GLOBAL_REG\n"); out($f,"#define ZEND_VM_LOOP_INTERRUPT() zend_interrupt_helper".($spec?"_SPEC":"")."(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n"); out($f,"#else\n"); @@ -2074,7 +2085,7 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) out($f,"#define HANDLE_EXCEPTION_LEAVE() ZEND_ASSERT(EG(exception)); LOAD_OPLINE(); ZEND_VM_LEAVE()\n"); out($f,"#define ZEND_VM_CONTINUE() goto zend_vm_continue\n"); out($f,"#define ZEND_VM_RETURN() return\n"); - out($f,"#define ZEND_VM_ENTER_EX() ZEND_VM_INTERRUPT_CHECK(); ZEND_VM_CONTINUE()\n"); + out($f,"#define ZEND_VM_ENTER_EX() ZEND_VM_CONTINUE()\n"); out($f,"#define ZEND_VM_ENTER() execute_data = EG(current_execute_data); LOAD_OPLINE(); ZEND_VM_ENTER_EX()\n"); out($f,"#define ZEND_VM_LEAVE() ZEND_VM_CONTINUE()\n"); out($f,"#define ZEND_VM_INTERRUPT() goto zend_interrupt_helper".($spec?"_SPEC":"").";\n"); @@ -2105,7 +2116,7 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) } out($f,"#define ZEND_VM_CONTINUE() goto *(void**)(OPLINE->handler)\n"); out($f,"#define ZEND_VM_RETURN() return\n"); - out($f,"#define ZEND_VM_ENTER_EX() ZEND_VM_INTERRUPT_CHECK(); ZEND_VM_CONTINUE()\n"); + out($f,"#define ZEND_VM_ENTER_EX() ZEND_VM_CONTINUE()\n"); out($f,"#define ZEND_VM_ENTER() execute_data = EG(current_execute_data); LOAD_OPLINE(); ZEND_VM_ENTER_EX()\n"); out($f,"#define ZEND_VM_LEAVE() ZEND_VM_CONTINUE()\n"); out($f,"#define ZEND_VM_INTERRUPT() goto zend_interrupt_helper".($spec?"_SPEC":"").";\n"); @@ -2157,7 +2168,7 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) out($f," } while (0)\n"); out($f,"# define ZEND_VM_DISPATCH_TO_LEAVE_HELPER(helper) opline = &call_leave_op; SAVE_OPLINE(); ZEND_VM_CONTINUE()\n"); out($f,"# define ZEND_VM_INTERRUPT() ZEND_VM_TAIL_CALL(zend_interrupt_TAILCALL(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU))\n"); - out($f,"# define ZEND_VM_ENTER_EX() ZEND_VM_INTERRUPT_CHECK(); ZEND_VM_CONTINUE()\n"); + out($f,"# define ZEND_VM_ENTER_EX() ZEND_VM_CONTINUE()\n"); out($f,"# define ZEND_VM_LEAVE() ZEND_VM_CONTINUE()\n"); out($f,"\n"); out($f,"static ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV zend_interrupt_helper".($spec?"_SPEC":"")."_TAILCALL(ZEND_OPCODE_HANDLER_ARGS);\n"); diff --git a/ext/opcache/jit/zend_jit.c b/ext/opcache/jit/zend_jit.c index fbbfab6b243c..d8d9afa23189 100644 --- a/ext/opcache/jit/zend_jit.c +++ b/ext/opcache/jit/zend_jit.c @@ -2041,7 +2041,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op if (Z_MODE(res_addr) != IS_REG && (i + 1) <= end && zend_jit_next_is_send_result(opline) - && (!(op1_info & MAY_HAVE_DTOR) || !(op1_info & MAY_BE_RC1))) { + && (!(op1_info & MAY_HAVE_UNDELAYED_DTOR) || !(op1_info & MAY_BE_RC1))) { i++; res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, (opline+1)->result.var); if (!zend_jit_reuse_ip(&ctx)) { diff --git a/ext/opcache/jit/zend_jit_ir.c b/ext/opcache/jit/zend_jit_ir.c index cf43d3ad840f..3c87ca4bf819 100644 --- a/ext/opcache/jit/zend_jit_ir.c +++ b/ext/opcache/jit/zend_jit_ir.c @@ -1792,7 +1792,7 @@ static void jit_ZVAL_DTOR(zend_jit_ctx *jit, ir_ref ref, uint32_t op_info, const return; } else if (type == IS_ARRAY) { if ((op_info) & (MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_STRING|MAY_BE_ARRAY_OF_ARRAY|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_REF)) { - if (opline && ((op_info) & (MAY_BE_ARRAY_OF_ARRAY|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_REF))) { + if (opline && ((op_info) & (MAY_BE_ARRAY_OF_ARRAY|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_REF))) { jit_SET_EX_OPLINE(jit, opline); } ir_CALL_1(IR_VOID, ir_CONST_FC_FUNC(zend_array_destroy), ref); @@ -2068,6 +2068,16 @@ static int zend_jit_interrupt_handler_stub(zend_jit_ctx *jit) ir_STORE(jit_EX(opline), jit_IP(jit)); ir_STORE(jit_EG(vm_interrupt), ir_CONST_U8(0)); + + // if (zend_hash_num_elements(&EG(delayed_effects))) { + // zend_handle_delayed_effects(); + // } + ir_ref num_delayed_effects = ir_LOAD_U32(ir_ADD_OFFSET(jit_EG(delayed_effects), offsetof(HashTable, nNumOfElements))); + ir_ref if_delayed_effects = ir_IF(ir_NE(num_delayed_effects, ir_CONST_U32(0))); + ir_IF_TRUE(if_delayed_effects); + ir_CALL(IR_VOID, ir_CONST_FUNC(zend_handle_delayed_effects)); + ir_MERGE_WITH_EMPTY_FALSE(if_delayed_effects); + if_timeout = ir_IF(ir_EQ(ir_LOAD_U8(jit_EG(timed_out)), ir_CONST_U8(0))); ir_IF_FALSE(if_timeout); ir_CALL(IR_VOID, ir_CONST_FUNC(zend_timeout)); @@ -2075,11 +2085,21 @@ static int zend_jit_interrupt_handler_stub(zend_jit_ctx *jit) if (zend_interrupt_function) { ir_CALL_1(IR_VOID, ir_CONST_FUNC(zend_interrupt_function), jit_FP(jit)); - if_exception = ir_IF(ir_LOAD_A(jit_EG(exception))); - ir_IF_TRUE(if_exception); - ir_CALL(IR_VOID, ir_CONST_FUNC(zend_jit_exception_in_interrupt_handler_helper)); - ir_MERGE_WITH_EMPTY_FALSE(if_exception); + } + + if_exception = ir_IF(ir_LOAD_A(jit_EG(exception))); + ir_IF_TRUE(if_exception); + ir_CALL_2(IR_VOID, ir_CONST_FUNC(zend_interrupt_consume), jit_FP(jit), jit_IP(jit)); + jit_STORE_IP(jit, jit_EG(exception_op)); + if (GCC_GLOBAL_REGS || ZEND_VM_KIND == ZEND_VM_KIND_TAILCALL) { + zend_jit_tailcall_handler(jit, ir_LOAD_A(jit_IP(jit))); + } else { + zend_jit_vm_enter(jit, jit_IP(jit)); + } + ZEND_ASSERT(!jit->ctx.control); + ir_IF_FALSE(if_exception); + if (zend_interrupt_function) { jit_STORE_FP(jit, ir_LOAD_A(jit_EG(current_execute_data))); jit_STORE_IP(jit, ir_LOAD_A(jit_EX(opline))); } @@ -3203,6 +3223,7 @@ static void zend_jit_setup_disasm(void) REGISTER_DATA(EG(exception)); REGISTER_DATA(EG(opline_before_exception)); REGISTER_DATA(EG(vm_interrupt)); + REGISTER_DATA(EG(delayed_effects)); REGISTER_DATA(EG(timed_out)); REGISTER_DATA(EG(uninitialized_zval)); REGISTER_DATA(EG(zend_constants)); @@ -10442,20 +10463,16 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen if (ZEND_OBSERVER_ENABLED && (!func || (func->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)) == 0)) { ir_ref observer_handler; ir_ref rx = jit_FP(jit); - const zend_op *observer_opline = NULL; struct jit_observer_fcall_is_unobserved_data unobserved_data = jit_observer_fcall_is_unobserved_start(jit, func, &observer_handler, rx, func_ref); if (trace && (trace->op != ZEND_JIT_TRACE_END || trace->stop < ZEND_JIT_TRACE_STOP_INTERPRETER)) { ZEND_ASSERT(trace[1].op == ZEND_JIT_TRACE_VM || trace[1].op == ZEND_JIT_TRACE_END); - observer_opline = trace[1].opline; - jit_SET_EX_OPLINE(jit, observer_opline); + jit_SET_EX_OPLINE(jit, trace[1].opline); } else { // EX(opline) = opline ir_STORE(jit_EX(opline), jit_IP(jit)); } jit_observer_fcall_begin(jit, rx, observer_handler); - zend_jit_check_timeout(jit, observer_opline, NULL); - jit_observer_fcall_is_unobserved_end(jit, &unobserved_data); } @@ -10714,10 +10731,6 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen } } - // JIT: if (UNEXPECTED(EG(exception) != NULL)) { - ir_GUARD_NOT(ir_LOAD_A(jit_EG_exception(jit)), - jit_STUB_ADDR(jit, jit_stub_icall_throw)); - /* If there isn't a zend_interrupt_function, the timeout is * handled here because it's more efficient. */ @@ -10737,6 +10750,10 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen zend_jit_check_timeout(jit, opline + 1, exit_addr); } + // JIT: if (UNEXPECTED(EG(exception) != NULL)) { + ir_GUARD_NOT(ir_LOAD_A(jit_EG_exception(jit)), + jit_STUB_ADDR(jit, jit_stub_icall_throw)); + if ((!trace || !func) && opline->opcode != ZEND_DO_ICALL) { jit_LOAD_IP_ADDR(jit, opline + 1); } else if (trace @@ -11210,17 +11227,23 @@ static int zend_jit_leave_func(zend_jit_ctx *jit, ir_MERGE_WITH(cold_path); } + /* exception might be thrown during destruction of unused return value */ + may_throw = may_throw || ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) + && (op1_info & MAY_BE_RC1) + && (op1_info & (MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY))); + + ir_ref if_interrupt = ir_IF(ir_LOAD_U8(jit_EG(vm_interrupt))); + ir_IF_TRUE_cold(if_interrupt); + ir_CALL_1(IR_VOID, ir_CONST_FUNC(zend_fcall_interrupt), jit_FP(jit)); + ir_MERGE_WITH_EMPTY_FALSE(if_interrupt); + ir_ref may_throw_ref = ir_PHI_2(IR_ADDR, ir_CONST_ADDR(1), ir_CONST_ADDR(may_throw)); + if (trace->op == ZEND_JIT_TRACE_BACK && (!JIT_G(current_frame) || TRACE_FRAME_IS_UNKNOWN_RETURN(JIT_G(current_frame)))) { const zend_op *next_opline = trace->opline; - if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) - && (op1_info & MAY_BE_RC1) - && (op1_info & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY))) { - /* exception might be thrown during destruction of unused return value */ - // JIT: if (EG(exception)) - ir_GUARD_NOT(ir_LOAD_A(jit_EG(exception)), jit_STUB_ADDR(jit, jit_stub_leave_throw)); - } + ir_GUARD_NOT(ir_AND_A(may_throw_ref, ir_LOAD_A(jit_EG(exception))), jit_STUB_ADDR(jit, jit_stub_leave_throw)); + do { trace++; } while (trace->op == ZEND_JIT_TRACE_INIT_CALL); @@ -11252,13 +11275,9 @@ static int zend_jit_leave_func(zend_jit_ctx *jit, zend_jit_set_last_valid_opline(jit, trace->opline); return 1; - } else if (may_throw || - (((opline->op1_type & (IS_VAR|IS_TMP_VAR)) - && (op1_info & MAY_BE_RC1) - && (op1_info & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY))) - && (!JIT_G(current_frame) || TRACE_FRAME_IS_RETURN_VALUE_UNUSED(JIT_G(current_frame))))) { + } else { // JIT: if (EG(exception)) - ir_GUARD_NOT(ir_LOAD_A(jit_EG(exception)), jit_STUB_ADDR(jit, jit_stub_leave_throw)); + ir_GUARD_NOT(ir_AND_A(may_throw_ref, ir_LOAD_A(jit_EG(exception))), jit_STUB_ADDR(jit, jit_stub_leave_throw)); } return 1; @@ -12865,14 +12884,14 @@ static int zend_jit_fetch_dim_read(zend_jit_ctx *jit, #endif if (opline->op2_type & (IS_TMP_VAR|IS_VAR)) { - if ((op2_info & MAY_HAVE_DTOR) && (op2_info & MAY_BE_RC1)) { + if ((op2_info & MAY_HAVE_UNDELAYED_DTOR) && (op2_info & MAY_BE_RC1)) { may_throw = 1; } jit_FREE_OP(jit, opline->op2_type, opline->op2, op2_info, opline); } if (opline->opcode != ZEND_FETCH_LIST_R && !op1_avoid_refcounting) { if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) { - if ((op1_info & MAY_HAVE_DTOR) && (op1_info & MAY_BE_RC1)) { + if ((op1_info & MAY_HAVE_UNDELAYED_DTOR) && (op1_info & MAY_BE_RC1)) { may_throw = 1; } jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline); @@ -13163,7 +13182,7 @@ static int zend_jit_fetch_dim(zend_jit_ctx *jit, #endif if ((opline->op2_type & (IS_TMP_VAR|IS_VAR)) - && (op2_info & MAY_HAVE_DTOR) + && (op2_info & MAY_HAVE_UNDELAYED_DTOR) && (op2_info & MAY_BE_RC1)) { may_throw = 1; } @@ -15551,7 +15570,7 @@ static int zend_jit_assign_obj_op(zend_jit_ctx *jit, jit_FREE_OP(jit, (opline+1)->op1_type, (opline+1)->op1, val_info, opline); if (opline->op1_type != IS_UNUSED && !delayed_fetch_this && !op1_indirect) { - if ((op1_info & MAY_HAVE_DTOR) && (op1_info & MAY_BE_RC1)) { + if ((op1_info & MAY_HAVE_UNDELAYED_DTOR) && (op1_info & MAY_BE_RC1)) { may_throw = true; } jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline); @@ -16029,7 +16048,7 @@ static int zend_jit_incdec_obj(zend_jit_ctx *jit, } if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && !delayed_fetch_this && !op1_indirect) { - if ((op1_info & MAY_HAVE_DTOR) && (op1_info & MAY_BE_RC1)) { + if ((op1_info & MAY_HAVE_UNDELAYED_DTOR) && (op1_info & MAY_BE_RC1)) { may_throw = true; } jit_FREE_OP(jit, opline->op1_type, opline->op1, op1_info, opline); @@ -17907,7 +17926,7 @@ static void jit_frameless_icall2(zend_jit_ctx *jit, const zend_op *opline, uint3 if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) != 0 && (opline->op2_type & (IS_VAR|IS_TMP_VAR)) != 0 && (op2_info & MAY_BE_RC1) - && (op2_info & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY))) { + && (op2_info & (MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY))) { jit_set_Z_TYPE_INFO(jit, op1_addr, IS_UNDEF); if (JIT_G(current_frame)) { SET_STACK_TYPE(JIT_G(current_frame)->stack, @@ -17989,10 +18008,10 @@ static void jit_frameless_icall3(zend_jit_ctx *jit, const zend_op *opline, uint3 if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && (((opline->op2_type & (IS_VAR|IS_TMP_VAR)) && (op2_info & MAY_BE_RC1) - && (op2_info & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY))) + && (op2_info & (MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY))) || ((op_data_type & (IS_VAR|IS_TMP_VAR)) && (op1_data_info & MAY_BE_RC1) - && (op1_data_info & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY))))) { + && (op1_data_info & (MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY))))) { op1_undef = true; jit_set_Z_TYPE_INFO(jit, op1_addr, IS_UNDEF); if (JIT_G(current_frame)) { @@ -18007,7 +18026,7 @@ static void jit_frameless_icall3(zend_jit_ctx *jit, const zend_op *opline, uint3 && (opline->op2_type & (IS_VAR|IS_TMP_VAR)) != 0 && (op_data_type & (IS_VAR|IS_TMP_VAR)) != 0 && (op1_data_info & MAY_BE_RC1) - && (op1_data_info & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY))) { + && (op1_data_info & (MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY))) { jit_set_Z_TYPE_INFO(jit, op2_addr, IS_UNDEF); if (JIT_G(current_frame)) { SET_STACK_TYPE(JIT_G(current_frame)->stack, diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c index 024a5d0e194d..667a84028670 100644 --- a/ext/opcache/jit/zend_jit_trace.c +++ b/ext/opcache/jit/zend_jit_trace.c @@ -5638,7 +5638,7 @@ static zend_vm_opcode_handler_t zend_jit_trace(zend_jit_trace_rec *trace_buffer, if (!zend_jit_free_cv(&ctx, info, j)) { goto jit_failure; } - if (info & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_ARRAY|MAY_BE_ARRAY_OF_RESOURCE)) { + if (info & (MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_ARRAY|MAY_BE_ARRAY_OF_RESOURCE)) { if (info & MAY_BE_RC1) { may_throw = 1; } diff --git a/ext/opcache/jit/zend_jit_vm_helpers.c b/ext/opcache/jit/zend_jit_vm_helpers.c index 271d923598d9..56ba1692f147 100644 --- a/ext/opcache/jit/zend_jit_vm_helpers.c +++ b/ext/opcache/jit/zend_jit_vm_helpers.c @@ -69,6 +69,10 @@ ZEND_OPCODE_HANDLER_RET ZEND_OPCODE_HANDLER_CCONV zend_jit_leave_func_helper_tai execute_data = EX(prev_execute_data); zend_vm_stack_free_call_frame_ex(call_info, old_execute_data); + if (UNEXPECTED(zend_atomic_bool_load_ex(&EG(vm_interrupt)))) { + zend_fcall_interrupt(execute_data); + } + if (UNEXPECTED(EG(exception) != NULL)) { const zend_op *old_opline = EX(opline); zend_throw_exception_internal(NULL); @@ -120,6 +124,10 @@ ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_leave_nested_func_helper(ZEND_OPC execute_data = EX(prev_execute_data); zend_vm_stack_free_call_frame_ex(call_info, old_execute_data); + if (UNEXPECTED(zend_atomic_bool_load_ex(&EG(vm_interrupt)))) { + zend_fcall_interrupt(execute_data); + } + if (UNEXPECTED(EG(exception) != NULL)) { const zend_op *old_opline = EX(opline); zend_throw_exception_internal(NULL); diff --git a/ext/opcache/tests/gh17422/001.phpt b/ext/opcache/tests/gh17422/001.phpt index 04a8bc38a9ef..aea0b19970f1 100644 --- a/ext/opcache/tests/gh17422/001.phpt +++ b/ext/opcache/tests/gh17422/001.phpt @@ -13,5 +13,5 @@ warning(); ?> --EXPECT-- -set_error_handler: "continue" targeting switch is equivalent to "break" OK: warning +set_error_handler: "continue" targeting switch is equivalent to "break" diff --git a/ext/opcache/tests/gh17422/002.phpt b/ext/opcache/tests/gh17422/002.phpt index 6145f71a8e58..9a334e4a82f5 100644 --- a/ext/opcache/tests/gh17422/002.phpt +++ b/ext/opcache/tests/gh17422/002.phpt @@ -5,7 +5,7 @@ GH-17422 (OPcache bypasses the user-defined error handler for deprecations) - Th set_error_handler(static function (int $errno, string $errstr, string $errfile, int $errline) { throw new \ErrorException($errstr, 0, $errno, $errfile, $errline); -}); +}, delay: false); try { require __DIR__ . "/warning.inc"; diff --git a/ext/opcache/tests/gh17422/003.phpt b/ext/opcache/tests/gh17422/003.phpt index a1330eb88afa..240fff5f12a4 100644 --- a/ext/opcache/tests/gh17422/003.phpt +++ b/ext/opcache/tests/gh17422/003.phpt @@ -9,6 +9,7 @@ set_error_handler(static function (int $errno, string $errstr, string $errfile, }); require __DIR__ . "/warning.inc"; +(function() {})(); warning(); diff --git a/ext/opcache/tests/gh17422/004.phpt b/ext/opcache/tests/gh17422/004.phpt index 4fa659a763e8..60aca62e36fc 100644 --- a/ext/opcache/tests/gh17422/004.phpt +++ b/ext/opcache/tests/gh17422/004.phpt @@ -14,6 +14,7 @@ set_error_handler(static function (int $errno, string $errstr, string $errfile, }); require __DIR__ . "/warning.inc"; +(function() {})(); warning(); diff --git a/ext/opcache/tests/gh17422/005.phpt b/ext/opcache/tests/gh17422/005.phpt index 1b4818d91cc9..6c983e3ae2b4 100644 --- a/ext/opcache/tests/gh17422/005.phpt +++ b/ext/opcache/tests/gh17422/005.phpt @@ -8,6 +8,7 @@ set_error_handler(static function (int $errno, string $errstr, string $errfile, }); require __DIR__ . "/warning.inc"; +(function() {})(); dummy(); diff --git a/ext/opcache/tests/gh17422/006.phpt b/ext/opcache/tests/gh17422/006.phpt index 3c1303dfa844..739bca6208a3 100644 --- a/ext/opcache/tests/gh17422/006.phpt +++ b/ext/opcache/tests/gh17422/006.phpt @@ -16,6 +16,7 @@ set_error_handler(static function (int $errno, string $errstr, string $errfile, }); require __DIR__ . "/warning.inc"; +(function() {})(); warning(); diff --git a/ext/opcache/tests/jit/assign_055.phpt b/ext/opcache/tests/jit/assign_055.phpt index 38ced05b0db4..71498a31efb4 100644 --- a/ext/opcache/tests/jit/assign_055.phpt +++ b/ext/opcache/tests/jit/assign_055.phpt @@ -19,6 +19,6 @@ try { --EXPECTF-- Fatal error: Uncaught Error: Undefined constant "y" in %sassign_055.php:3 Stack trace: -#0 %s(%d): {closure:%s:%d}(2, 'Undefined varia...', '%s', 7) +#0 [internal function]: {closure:%s:%d}(2, 'Undefined varia...', '%s', 7) #1 {main} thrown in %sassign_055.php on line 3 diff --git a/ext/opcache/tests/jit/assign_dim_005.phpt b/ext/opcache/tests/jit/assign_dim_005.phpt index e7bfdabacc4f..b839739574bb 100644 --- a/ext/opcache/tests/jit/assign_dim_005.phpt +++ b/ext/opcache/tests/jit/assign_dim_005.phpt @@ -16,6 +16,11 @@ $a[$c] = 'x' ; var_dump($a); ?> --EXPECT-- +array(1) { + [""]=> + string(1) "x" +} Error: Undefined variable $c +Error: Using null as an array offset is deprecated, use an empty string instead Error: Undefined variable $c -NULL +Error: Using null as an array offset is deprecated, use an empty string instead diff --git a/ext/opcache/tests/jit/assign_dim_007.phpt b/ext/opcache/tests/jit/assign_dim_007.phpt index 0df4e291ae93..590ab14b6670 100644 --- a/ext/opcache/tests/jit/assign_dim_007.phpt +++ b/ext/opcache/tests/jit/assign_dim_007.phpt @@ -18,7 +18,9 @@ x($y); var_dump($x,$y); ?> --EXPECT-- -array(0) { +array(1) { + [0]=> + int(1) } array(1) { [0]=> diff --git a/ext/opcache/tests/jit/assign_dim_011.phpt b/ext/opcache/tests/jit/assign_dim_011.phpt index 5df415c89e6c..fca284e833fe 100644 --- a/ext/opcache/tests/jit/assign_dim_011.phpt +++ b/ext/opcache/tests/jit/assign_dim_011.phpt @@ -6,13 +6,14 @@ opcache.enable_cli=1 opcache.file_update_protection=0 --FILE-- getMessage() . "\n"; } diff --git a/ext/opcache/tests/jit/assign_dim_014.phpt b/ext/opcache/tests/jit/assign_dim_014.phpt index 574b05258421..04a794966aa5 100644 --- a/ext/opcache/tests/jit/assign_dim_014.phpt +++ b/ext/opcache/tests/jit/assign_dim_014.phpt @@ -11,8 +11,10 @@ set_error_handler(function($code, $err) { $GLOBALS['a'] = null; }); $a[$y] = function(){}; +(function() {})(); ?> DONE --EXPECT-- Error: Undefined variable $y +Error: Using null as an array offset is deprecated, use an empty string instead DONE diff --git a/ext/opcache/tests/jit/assign_dim_015.phpt b/ext/opcache/tests/jit/assign_dim_015.phpt index 2a5b6d46d37a..6e670b8ddf2f 100644 --- a/ext/opcache/tests/jit/assign_dim_015.phpt +++ b/ext/opcache/tests/jit/assign_dim_015.phpt @@ -11,6 +11,7 @@ set_error_handler(function($code, $msg) use (&$my_var) { $my_var = 0; }); $my_var[] = $y; +(function() {})(); ?> DONE --EXPECT-- diff --git a/ext/opcache/tests/jit/assign_dim_op_006.phpt b/ext/opcache/tests/jit/assign_dim_op_006.phpt index 8bfb9197177a..b2b606245be8 100644 --- a/ext/opcache/tests/jit/assign_dim_op_006.phpt +++ b/ext/opcache/tests/jit/assign_dim_op_006.phpt @@ -15,4 +15,7 @@ $my_var[000000000000000000000100000000000000000000000000000000000000000000000000 var_dump($my_var); ?> --EXPECT-- -int(0) +array(1) { + [0]=> + string(3) "xyz" +} diff --git a/ext/opcache/tests/jit/count_001.phpt b/ext/opcache/tests/jit/count_001.phpt index 2fb1c52d2855..b02f1746d486 100644 --- a/ext/opcache/tests/jit/count_001.phpt +++ b/ext/opcache/tests/jit/count_001.phpt @@ -36,6 +36,7 @@ class C { public static function count_throws(): int { $result = count([new ThrowsInDestructor()]); + (function() {})(); echo "Unreachable\n"; return $result; } @@ -65,4 +66,4 @@ Caught In destructor Caught In destructor Caught In destructor Caught In destructor -Caught In destructor \ No newline at end of file +Caught In destructor diff --git a/ext/opcache/tests/jit/fetch_dim_rw_004.phpt b/ext/opcache/tests/jit/fetch_dim_rw_004.phpt index ae639c8f56ba..aedcf6f944bd 100644 --- a/ext/opcache/tests/jit/fetch_dim_rw_004.phpt +++ b/ext/opcache/tests/jit/fetch_dim_rw_004.phpt @@ -12,12 +12,12 @@ $k=[]; $y[$k]++; ?> --EXPECTF-- -Fatal error: Uncaught TypeError: {closure:%s:%d}(): Argument #1 ($y) must be of type y, int given, called in %s on line %d and defined in %s:%d +Fatal error: Uncaught TypeError: Cannot access offset of type array on array in %s:%d Stack trace: -#0 %s(%d): {closure:%s:%d}(2, 'Undefined varia...', '%s', 5) -#1 {main} +#0 {main} -Next TypeError: Cannot access offset of type array on array in %sfetch_dim_rw_004.php:5 +Next TypeError: {closure:%s:%d}(): Argument #1 ($y) must be of type y, int given, called in %s on line %d and defined in %s:%d Stack trace: -#0 {main} - thrown in %sfetch_dim_rw_004.php on line 5 +#0 %s(%d): {closure:%s:%d}(2, 'Undefined varia...', '%s', 5) +#1 {main} + thrown in %s on line %d diff --git a/ext/opcache/tests/jit/gh18262-002.phpt b/ext/opcache/tests/jit/gh18262-002.phpt index b82723abaa29..f653919f8883 100644 --- a/ext/opcache/tests/jit/gh18262-002.phpt +++ b/ext/opcache/tests/jit/gh18262-002.phpt @@ -18,7 +18,7 @@ $tests = [ set_error_handler(function ($_, $errstr) { throw new \Exception($errstr); -}); +}, delay: false); foreach ($tests as $obj) { var_dump($obj->b); diff --git a/ext/opcache/tests/jit/gh18262-003.phpt b/ext/opcache/tests/jit/gh18262-003.phpt index a3c3e037632f..42168c25ed49 100644 --- a/ext/opcache/tests/jit/gh18262-003.phpt +++ b/ext/opcache/tests/jit/gh18262-003.phpt @@ -19,7 +19,7 @@ $tests = [ set_error_handler(function ($_, $errstr) { throw new \Exception($errstr); -}); +}, delay: false); foreach ($tests as $obj) { try { diff --git a/ext/opcache/tests/jit/gh18262-004.phpt b/ext/opcache/tests/jit/gh18262-004.phpt index c8dccd30c98a..dfe11b2d2fcb 100644 --- a/ext/opcache/tests/jit/gh18262-004.phpt +++ b/ext/opcache/tests/jit/gh18262-004.phpt @@ -28,9 +28,11 @@ foreach ($tests as $test) { ?> --EXPECTF-- int(1) +string(3) "str" Fatal error: Uncaught Exception: B::__destruct in %s:%d Stack trace: -#0 %s(%d): B->__destruct() -#1 {main} +#0 [internal function]: B->__destruct() +#1 %s(%d): var_dump('str') +#2 {main} thrown in %s on line %d diff --git a/ext/opcache/tests/jit/not_003.phpt b/ext/opcache/tests/jit/not_003.phpt index a358fc227578..43373d53eb7e 100644 --- a/ext/opcache/tests/jit/not_003.phpt +++ b/ext/opcache/tests/jit/not_003.phpt @@ -12,6 +12,6 @@ set_error_handler(function(){y;}) . !$y; --EXPECTF-- Fatal error: Uncaught Error: Undefined constant "y" in %snot_003.php:2 Stack trace: -#0 %s(%d): {closure:%s:%d}(2, 'Undefined varia...', '%s', 2) +#0 [internal function]: {closure:%s:%d}(2, 'Undefined varia...', '%s', 2) #1 {main} thrown in %snot_003.php on line 2 diff --git a/ext/reflection/tests/bug71018.phpt b/ext/reflection/tests/bug71018.phpt index cbbb7325e9f1..671e52b3f135 100644 --- a/ext/reflection/tests/bug71018.phpt +++ b/ext/reflection/tests/bug71018.phpt @@ -30,7 +30,7 @@ var_dump("T2::static = " . T2::getDataByStatic()); set_error_handler(function ($severity, $message, $file, $line) { throw new Exception($message); -}); +}, delay: false); try { $Prop2->setValue(\T2::class, 'hi'); } catch (Exception $e) { diff --git a/ext/spl/tests/ArrayObject/bug74669.phpt b/ext/spl/tests/ArrayObject/bug74669.phpt index 17f622aaaf9d..20b10f940d45 100644 --- a/ext/spl/tests/ArrayObject/bug74669.phpt +++ b/ext/spl/tests/ArrayObject/bug74669.phpt @@ -107,14 +107,14 @@ Warning: Undefined array key "foo" in %s on line %d NULL Deprecated: ArrayObject::__construct(): Using an object as a backing array for ArrayObject is deprecated, as it allows violating class constraints and invariants in %s on line %d -object(SelfArray)#9 (1) { +object(SelfArray)#10 (1) { ["foo"]=> string(3) "bar" } string(77) "O:9:"SelfArray":4:{i:0;i:16777216;i:1;N;i:2;a:1:{s:3:"foo";s:3:"bar";}i:3;N;}" Deprecated: Creation of dynamic property SelfArray::$foo is deprecated in %s on line %d -object(SelfArray)#9 (1) { +object(SelfArray)#10 (1) { ["foo"]=> string(3) "bar" } diff --git a/ext/spl/tests/ArrayObject/gh16646.phpt b/ext/spl/tests/ArrayObject/gh16646.phpt index f572346ea5df..83b9ee46c2d5 100644 --- a/ext/spl/tests/ArrayObject/gh16646.phpt +++ b/ext/spl/tests/ArrayObject/gh16646.phpt @@ -20,6 +20,7 @@ class C { $arr = new ArrayObject(new B(new C)); unset($arr["b"]); +(function() {})(); var_dump($arr); ?> diff --git a/ext/spl/tests/SplFileinfo_debugInfo_basic.phpt b/ext/spl/tests/SplFileinfo_debugInfo_basic.phpt index 75bf1d9dc161..162f69a4359a 100644 --- a/ext/spl/tests/SplFileinfo_debugInfo_basic.phpt +++ b/ext/spl/tests/SplFileinfo_debugInfo_basic.phpt @@ -17,68 +17,68 @@ var_dump(new \SplFileInfo('d.txt')); var_dump(new \SplFileInfo('e.txt')); var_dump(new \SplFileInfo('f')); ?> ---EXPECT-- -object(SplFileInfo)#1 (2) { +--EXPECTF-- +object(SplFileInfo)#%d (2) { ["pathName":"SplFileInfo":private]=> string(14) "/path/to/a.txt" ["fileName":"SplFileInfo":private]=> string(5) "a.txt" } -object(SplFileInfo)#1 (2) { +object(SplFileInfo)#%d (2) { ["pathName":"SplFileInfo":private]=> string(9) "path/to/b" ["fileName":"SplFileInfo":private]=> string(1) "b" } -object(SplFileInfo)#1 (2) { +object(SplFileInfo)#%d (2) { ["pathName":"SplFileInfo":private]=> string(5) "c.txt" ["fileName":"SplFileInfo":private]=> string(5) "c.txt" } -object(SplFileInfo)#1 (2) { +object(SplFileInfo)#%d (2) { ["pathName":"SplFileInfo":private]=> string(1) "d" ["fileName":"SplFileInfo":private]=> string(1) "d" } -object(SplFileInfo)#1 (2) { +object(SplFileInfo)#%d (2) { ["pathName":"SplFileInfo":private]=> string(12) "~/path/to//e" ["fileName":"SplFileInfo":private]=> string(1) "e" } -object(SplFileInfo)#1 (2) { +object(SplFileInfo)#%d (2) { ["pathName":"SplFileInfo":private]=> string(13) "path/to/a.txt" ["fileName":"SplFileInfo":private]=> string(5) "a.txt" } -object(SplFileInfo)#1 (2) { +object(SplFileInfo)#%d (2) { ["pathName":"SplFileInfo":private]=> string(15) "path/to/bbb.txt" ["fileName":"SplFileInfo":private]=> string(7) "bbb.txt" } -object(SplFileInfo)#1 (2) { +object(SplFileInfo)#%d (2) { ["pathName":"SplFileInfo":private]=> string(15) "path/to/ccc.txt" ["fileName":"SplFileInfo":private]=> string(7) "ccc.txt" } -object(SplFileInfo)#1 (2) { +object(SplFileInfo)#%d (2) { ["pathName":"SplFileInfo":private]=> string(5) "d.txt" ["fileName":"SplFileInfo":private]=> string(5) "d.txt" } -object(SplFileInfo)#1 (2) { +object(SplFileInfo)#%d (2) { ["pathName":"SplFileInfo":private]=> string(5) "e.txt" ["fileName":"SplFileInfo":private]=> string(5) "e.txt" } -object(SplFileInfo)#1 (2) { +object(SplFileInfo)#%d (2) { ["pathName":"SplFileInfo":private]=> string(1) "f" ["fileName":"SplFileInfo":private]=> diff --git a/ext/spl/tests/SplFixedArray_immediate_gc.phpt b/ext/spl/tests/SplFixedArray_immediate_gc.phpt index cead2238c190..19d6532eb35f 100644 --- a/ext/spl/tests/SplFixedArray_immediate_gc.phpt +++ b/ext/spl/tests/SplFixedArray_immediate_gc.phpt @@ -11,6 +11,7 @@ $array = SplFixedArray::fromArray([new HasDestructor()]); var_dump($array); echo "Replacing\n"; $array[0] = new stdClass(); +(function() {})(); // As of php 8.3, this will be freed before the var_dump call echo "Dumping again\n"; var_dump($array); diff --git a/ext/spl/tests/SplObjectStorage/SplObjectStorage_unset.phpt b/ext/spl/tests/SplObjectStorage/SplObjectStorage_unset.phpt index 2e3e58c837cb..3d7f09bc2a71 100644 --- a/ext/spl/tests/SplObjectStorage/SplObjectStorage_unset.phpt +++ b/ext/spl/tests/SplObjectStorage/SplObjectStorage_unset.phpt @@ -15,6 +15,7 @@ $s = new SplObjectStorage(); $s[$o] = new HasDestructor(); try { unset($s[$o]); + (function() {})(); } catch (Exception $e) { echo "Caught: {$e->getMessage()}\n"; } @@ -22,6 +23,7 @@ var_dump($s); $s[$o] = new HasDestructor(); try { $s->offsetUnset($o); + (function() {})(); } catch (Exception $e) { echo "Caught: {$e->getMessage()}\n"; } @@ -52,4 +54,4 @@ object(SplObjectStorage)#2 (1) { ["storage":"SplObjectStorage":private]=> array(0) { } -} \ No newline at end of file +} diff --git a/ext/spl/tests/SplObjectStorage/observer_006.phpt b/ext/spl/tests/SplObjectStorage/observer_006.phpt index afd40e9b122a..c5256f29301e 100644 --- a/ext/spl/tests/SplObjectStorage/observer_006.phpt +++ b/ext/spl/tests/SplObjectStorage/observer_006.phpt @@ -250,7 +250,7 @@ object(MyStorage)#%d (2) { } } int(2) -object(TestClass)#7 (1) { +object(TestClass)#9 (1) { ["test"]=> int(3) } diff --git a/ext/spl/tests/bug73423.phpt b/ext/spl/tests/bug73423.phpt index 2e00b328d708..9be5d8da3174 100644 --- a/ext/spl/tests/bug73423.phpt +++ b/ext/spl/tests/bug73423.phpt @@ -72,7 +72,9 @@ Fatal error: Uncaught Error: Class "NotExists" not found in %s:%d Stack trace: #0 %s(%d): eval() #1 %s(%d): fooIterator->__destruct() -#2 {main} +#2 [internal function]: foo->next() +#3 %s(%d): FilterIterator->next() +#4 {main} Next Error: Class "NotExists" not found in %s:%d Stack trace: diff --git a/ext/spl/tests/bug81992b.phpt b/ext/spl/tests/bug81992b.phpt index ba4736dfff1f..c2432608f9f8 100644 --- a/ext/spl/tests/bug81992b.phpt +++ b/ext/spl/tests/bug81992b.phpt @@ -45,9 +45,9 @@ test(10); --EXPECT-- --- Smaller size test --- In destructor -Destroyed, size is now still 2 -Destroyed the logger with id 4 Destroyed the logger with id 1 +Destroyed, size is now still 1 +Destroyed the logger with id 4 Size is now 1 Done --- Equal size test --- @@ -59,7 +59,7 @@ Done Destroyed the logger with id 1 --- Larger size test --- In destructor -Destroyed, size is now still 2 +Destroyed, size is now still 10 Destroyed the logger with id 4 Size is now 10 Done diff --git a/ext/spl/tests/gh16464.phpt b/ext/spl/tests/gh16464.phpt index 7b3b1e80e6fc..90c9397cf7f7 100644 --- a/ext/spl/tests/gh16464.phpt +++ b/ext/spl/tests/gh16464.phpt @@ -15,15 +15,18 @@ class C { $list = new SplDoublyLinkedList; $list->add(0, new C); $list[0] = 42; +(function() {})(); var_dump($list); ?> --EXPECTF-- -int(42) object(SplDoublyLinkedList)#%d (2) { ["flags":"SplDoublyLinkedList":private]=> int(0) ["dllist":"SplDoublyLinkedList":private]=> - array(0) { + array(1) { + [0]=> + int(42) } } +int(42) diff --git a/ext/spl/tests/gh16478.phpt b/ext/spl/tests/gh16478.phpt index 5a708b36fe80..c510266bb802 100644 --- a/ext/spl/tests/gh16478.phpt +++ b/ext/spl/tests/gh16478.phpt @@ -13,6 +13,7 @@ class C { $arr = new SplFixedArray(2); $arr[0] = new C; unset($arr[0]); +(function() {})(); var_dump($arr); ?> diff --git a/ext/spl/tests/iterator_041a.phpt b/ext/spl/tests/iterator_041a.phpt index d57735dc2cd0..c66660d19b04 100644 --- a/ext/spl/tests/iterator_041a.phpt +++ b/ext/spl/tests/iterator_041a.phpt @@ -92,6 +92,12 @@ MyArrayIterator::test('iterator_count', array(3 => 6)); ?> --EXPECT-- ===iterator_to_array=== +array(2) { + [0]=> + int(1) + [1]=> + int(2) +} State 7: __destruct() array(2) { [0]=> @@ -100,5 +106,6 @@ array(2) { int(2) } ===iterator_count=== +int(2) State 7: __destruct() int(2) diff --git a/ext/spl/tests/iterator_041b.phpt b/ext/spl/tests/iterator_041b.phpt index 83d9388161e3..da1cdfa2d032 100644 --- a/ext/spl/tests/iterator_041b.phpt +++ b/ext/spl/tests/iterator_041b.phpt @@ -84,6 +84,7 @@ class MyArrayIterator extends ArrayIterator } try { $e = null; + (function() {})(); } catch (Exception $e) { } } @@ -103,6 +104,12 @@ State 3: valid() State 4: current() State 5: key() State 6: next() +array(2) { + [0]=> + int(1) + [1]=> + int(2) +} State 7: __destruct() array(2) { [0]=> @@ -116,5 +123,6 @@ State 1: __construct() State 2: rewind() State 3: valid() State 6: next() +int(2) State 7: __destruct() int(2) diff --git a/ext/spl/tests/iterator_044.phpt b/ext/spl/tests/iterator_044.phpt index 74321194e098..7c205d60b938 100644 --- a/ext/spl/tests/iterator_044.phpt +++ b/ext/spl/tests/iterator_044.phpt @@ -131,7 +131,7 @@ object(stdClass)#1 (0) { CachingIterator::offsetExists(): Argument #1 ($key) must be of type string, stdClass given CachingIterator::offsetGet(): Argument #1 ($key) must be of type string, stdClass given ===2=== -object(MyFoo)#2 (0) { +object(MyFoo)#%d (0) { } bool(true) int(1) diff --git a/ext/standard/tests/array/gh16649/array_splice_uaf_array_deallocated.phpt b/ext/standard/tests/array/gh16649/array_splice_uaf_array_deallocated.phpt index 1874ddad8934..5fd64290eb03 100644 --- a/ext/standard/tests/array/gh16649/array_splice_uaf_array_deallocated.phpt +++ b/ext/standard/tests/array/gh16649/array_splice_uaf_array_deallocated.phpt @@ -11,12 +11,7 @@ class C { $arr = ["1", new C, "2"]; -try { - array_splice($arr, 1, 2); - echo "ERROR: Should have thrown exception\n"; -} catch (Error $e) { - echo "Exception caught: " . $e->getMessage() . "\n"; -} +array_splice($arr, 1, 2); ?> --EXPECT-- -Exception caught: Array was modified during array_splice operation + diff --git a/ext/standard/tests/array/gh16649/array_splice_uaf_complex_modification.phpt b/ext/standard/tests/array/gh16649/array_splice_uaf_complex_modification.phpt index 8ad4133300ec..3390803d492e 100644 --- a/ext/standard/tests/array/gh16649/array_splice_uaf_complex_modification.phpt +++ b/ext/standard/tests/array/gh16649/array_splice_uaf_complex_modification.phpt @@ -14,12 +14,6 @@ class ComplexModifier { $arr = ["first", new ComplexModifier, "last"]; -try { - array_splice($arr, 1, 1, ["replacement"]); - echo "ERROR: Should have thrown exception\n"; -} catch (Error $e) { - echo "Exception caught: " . $e->getMessage() . "\n"; -} +array_splice($arr, 1, 1, ["replacement"]); ?> --EXPECT-- -Exception caught: Array was modified during array_splice operation diff --git a/ext/standard/tests/array/gh16649/array_splice_uaf_multiple_destructors.phpt b/ext/standard/tests/array/gh16649/array_splice_uaf_multiple_destructors.phpt index 9e2c6cf8fc71..1b8492016bb5 100644 --- a/ext/standard/tests/array/gh16649/array_splice_uaf_multiple_destructors.phpt +++ b/ext/standard/tests/array/gh16649/array_splice_uaf_multiple_destructors.phpt @@ -20,14 +20,8 @@ class MultiDestructor { $arr = ["start", new MultiDestructor(1), new MultiDestructor(2), "end"]; -try { - array_splice($arr, 1, 2); - echo "ERROR: Should have thrown exception\n"; -} catch (Error $e) { - echo "Exception caught: " . $e->getMessage() . "\n"; -} +array_splice($arr, 1, 2); ?> --EXPECT-- Destructor 1 called Destructor 2 called -Exception caught: Array was modified during array_splice operation diff --git a/ext/standard/tests/array/gh16649/array_splice_uaf_original_case.phpt b/ext/standard/tests/array/gh16649/array_splice_uaf_original_case.phpt index 4a82d5893157..d67ded4b2926 100644 --- a/ext/standard/tests/array/gh16649/array_splice_uaf_original_case.phpt +++ b/ext/standard/tests/array/gh16649/array_splice_uaf_original_case.phpt @@ -18,12 +18,6 @@ class C { $arr = ["a" => "1", "3" => new C, "2" => "2"]; -try { - array_splice($arr, 1, 2); - echo "ERROR: Should have thrown exception\n"; -} catch (Error $e) { - echo "Exception caught: " . $e->getMessage() . "\n"; -} +array_splice($arr, 1, 2); ?> --EXPECT-- -Exception caught: Array was modified during array_splice operation diff --git a/ext/standard/tests/array/gh16649/array_splice_uaf_packed_to_hash.phpt b/ext/standard/tests/array/gh16649/array_splice_uaf_packed_to_hash.phpt index bd8f511b6253..86a445f41f60 100644 --- a/ext/standard/tests/array/gh16649/array_splice_uaf_packed_to_hash.phpt +++ b/ext/standard/tests/array/gh16649/array_splice_uaf_packed_to_hash.phpt @@ -12,12 +12,6 @@ class C { $arr = ["1", new C, "2"]; -try { - array_splice($arr, 1, 2); - echo "ERROR: Should have thrown exception\n"; -} catch (Error $e) { - echo "Exception caught: " . $e->getMessage() . "\n"; -} +array_splice($arr, 1, 2); ?> --EXPECT-- -Exception caught: Array was modified during array_splice operation diff --git a/ext/standard/tests/array/gh16649/array_splice_with_replacement.phpt b/ext/standard/tests/array/gh16649/array_splice_with_replacement.phpt index 8754a913a24e..bf6866253b3b 100644 --- a/ext/standard/tests/array/gh16649/array_splice_with_replacement.phpt +++ b/ext/standard/tests/array/gh16649/array_splice_with_replacement.phpt @@ -12,12 +12,6 @@ class C { $arr = ["a", new C, "b"]; $replacement = ["replacement1", "replacement2"]; -try { - array_splice($arr, 1, 1, $replacement); - echo "ERROR: Should have thrown exception\n"; -} catch (Error $e) { - echo "Exception caught: " . $e->getMessage() . "\n"; -} +array_splice($arr, 1, 1, $replacement); ?> --EXPECT-- -Exception caught: Array was modified during array_splice operation diff --git a/ext/standard/tests/class_object/method_exists_variation_001.phpt b/ext/standard/tests/class_object/method_exists_variation_001.phpt index d45d2652d11c..0d7c5755834d 100644 --- a/ext/standard/tests/class_object/method_exists_variation_001.phpt +++ b/ext/standard/tests/class_object/method_exists_variation_001.phpt @@ -19,6 +19,7 @@ $method = 'string_val'; //get an unset variable $unset_var = 10; unset ($unset_var); +(function() {})(); //array of values to iterate over $values = array( @@ -86,88 +87,88 @@ echo "Done"; Error: 2 - Undefined variable $undefined_var Error: 2 - Undefined variable $unset_var -Arg value 0 +Arg value 0 method_exists(): Argument #1 ($object_or_class) must be of type object|string, int given -Arg value 1 +Arg value 1 method_exists(): Argument #1 ($object_or_class) must be of type object|string, int given -Arg value 12345 +Arg value 12345 method_exists(): Argument #1 ($object_or_class) must be of type object|string, int given -Arg value -2345 +Arg value -2345 method_exists(): Argument #1 ($object_or_class) must be of type object|string, int given -Arg value 10.5 +Arg value 10.5 method_exists(): Argument #1 ($object_or_class) must be of type object|string, float given -Arg value -10.5 +Arg value -10.5 method_exists(): Argument #1 ($object_or_class) must be of type object|string, float given -Arg value 101234567000 +Arg value 101234567000 method_exists(): Argument #1 ($object_or_class) must be of type object|string, float given -Arg value 1.07654321E-9 +Arg value 1.07654321E-9 method_exists(): Argument #1 ($object_or_class) must be of type object|string, float given -Arg value 0.5 +Arg value 0.5 method_exists(): Argument #1 ($object_or_class) must be of type object|string, float given Error: 2 - Array to string conversion -Arg value Array +Arg value Array method_exists(): Argument #1 ($object_or_class) must be of type object|string, array given Error: 2 - Array to string conversion -Arg value Array +Arg value Array method_exists(): Argument #1 ($object_or_class) must be of type object|string, array given Error: 2 - Array to string conversion -Arg value Array +Arg value Array method_exists(): Argument #1 ($object_or_class) must be of type object|string, array given Error: 2 - Array to string conversion -Arg value Array +Arg value Array method_exists(): Argument #1 ($object_or_class) must be of type object|string, array given Error: 2 - Array to string conversion -Arg value Array +Arg value Array method_exists(): Argument #1 ($object_or_class) must be of type object|string, array given -Arg value +Arg value method_exists(): Argument #1 ($object_or_class) must be of type object|string, null given -Arg value +Arg value method_exists(): Argument #1 ($object_or_class) must be of type object|string, null given -Arg value 1 +Arg value 1 method_exists(): Argument #1 ($object_or_class) must be of type object|string, true given -Arg value +Arg value method_exists(): Argument #1 ($object_or_class) must be of type object|string, false given -Arg value 1 +Arg value 1 method_exists(): Argument #1 ($object_or_class) must be of type object|string, true given -Arg value +Arg value method_exists(): Argument #1 ($object_or_class) must be of type object|string, false given -Arg value +Arg value bool(false) -Arg value +Arg value bool(false) -Arg value string +Arg value string In autoload(string) bool(false) -Arg value String +Arg value String In autoload(String) bool(false) -Arg value +Arg value method_exists(): Argument #1 ($object_or_class) must be of type object|string, null given -Arg value +Arg value method_exists(): Argument #1 ($object_or_class) must be of type object|string, null given Done diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c index 52fe41eb18c2..300853ba3b49 100644 --- a/ext/zend_test/test.c +++ b/ext/zend_test/test.c @@ -1932,6 +1932,17 @@ static PHP_FUNCTION(zend_test_gh18756) zend_mm_shutdown(heap, true, false); } +static PHP_FUNCTION(zend_test_rc_string) +{ + zend_string *str; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_STR(str) + ZEND_PARSE_PARAMETERS_END(); + + RETURN_STR(zend_string_init(ZSTR_VAL(str), ZSTR_LEN(str), 0)); +} + static PHP_FUNCTION(zend_test_opcache_preloading) { ZEND_PARSE_PARAMETERS_NONE(); diff --git a/ext/zend_test/test.stub.php b/ext/zend_test/test.stub.php index 489d7d0a260b..da54bcac5e10 100644 --- a/ext/zend_test/test.stub.php +++ b/ext/zend_test/test.stub.php @@ -360,6 +360,9 @@ function zend_test_uri_parser(string $uri, string $parser): array { } /** @compile-time-eval */ function zend_test_gh19792(): void {} + + /* Return a non-interned copy of $str */ + function zend_test_rc_string(string $str): string {} } namespace ZendTestNS { diff --git a/ext/zend_test/test_arginfo.h b/ext/zend_test/test_arginfo.h index 94f75cdb3601..65375db7065d 100644 --- a/ext/zend_test/test_arginfo.h +++ b/ext/zend_test/test_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit test.stub.php instead. - * Stub hash: 4bb5b467b9d62c0e0c6a7c1e069e8755403a0af9 + * Stub hash: d08ac20dda53ab8eb950d0fcb15b74bb46486624 * Has decl header: yes */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_trigger_bailout, 0, 0, IS_NEVER, 0) @@ -210,6 +210,8 @@ ZEND_END_ARG_INFO() #define arginfo_zend_test_gh19792 arginfo_zend_test_void_return +#define arginfo_zend_test_rc_string arginfo_zend_create_unterminated_string + #define arginfo_ZendTestNS2_namespaced_func arginfo_zend_test_is_pcre_bundled #define arginfo_ZendTestNS2_namespaced_deprecated_func arginfo_zend_test_void_return @@ -357,6 +359,7 @@ static ZEND_FUNCTION(zend_test_gh18756); static ZEND_FUNCTION(zend_test_opcache_preloading); static ZEND_FUNCTION(zend_test_uri_parser); static ZEND_FUNCTION(zend_test_gh19792); +static ZEND_FUNCTION(zend_test_rc_string); static ZEND_FUNCTION(ZendTestNS2_namespaced_func); static ZEND_FUNCTION(ZendTestNS2_namespaced_deprecated_func); static ZEND_FUNCTION(ZendTestNS2_ZendSubNS_namespaced_func); @@ -499,6 +502,7 @@ static const zend_function_entry ext_functions[] = { ZEND_RAW_FENTRY("zend_test_gh19792", zif_zend_test_gh19792, arginfo_zend_test_gh19792, 0) #endif #endif + ZEND_FE(zend_test_rc_string, arginfo_zend_test_rc_string) #if (PHP_VERSION_ID >= 80400) ZEND_RAW_FENTRY(ZEND_NS_NAME("ZendTestNS2", "namespaced_func"), zif_ZendTestNS2_namespaced_func, arginfo_ZendTestNS2_namespaced_func, 0, NULL, NULL) #else diff --git a/ext/zend_test/test_decl.h b/ext/zend_test/test_decl.h index 4a6babbe12b9..fc1fb9f4be46 100644 --- a/ext/zend_test/test_decl.h +++ b/ext/zend_test/test_decl.h @@ -1,8 +1,8 @@ /* This is a generated file, edit test.stub.php instead. - * Stub hash: 4bb5b467b9d62c0e0c6a7c1e069e8755403a0af9 */ + * Stub hash: d08ac20dda53ab8eb950d0fcb15b74bb46486624 */ -#ifndef ZEND_TEST_DECL_4bb5b467b9d62c0e0c6a7c1e069e8755403a0af9_H -#define ZEND_TEST_DECL_4bb5b467b9d62c0e0c6a7c1e069e8755403a0af9_H +#ifndef ZEND_TEST_DECL_d08ac20dda53ab8eb950d0fcb15b74bb46486624_H +#define ZEND_TEST_DECL_d08ac20dda53ab8eb950d0fcb15b74bb46486624_H typedef enum zend_enum_ZendTestUnitEnum { ZEND_ENUM_ZendTestUnitEnum_Foo = 1, @@ -27,4 +27,4 @@ typedef enum zend_enum_ZendTestEnumWithInterface { ZEND_ENUM_ZendTestEnumWithInterface_Bar = 2, } zend_enum_ZendTestEnumWithInterface; -#endif /* ZEND_TEST_DECL_4bb5b467b9d62c0e0c6a7c1e069e8755403a0af9_H */ +#endif /* ZEND_TEST_DECL_d08ac20dda53ab8eb950d0fcb15b74bb46486624_H */ diff --git a/ext/zend_test/test_legacy_arginfo.h b/ext/zend_test/test_legacy_arginfo.h index a4c1ae3f2c96..73aa4e6472b4 100644 --- a/ext/zend_test/test_legacy_arginfo.h +++ b/ext/zend_test/test_legacy_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit test.stub.php instead. - * Stub hash: 4bb5b467b9d62c0e0c6a7c1e069e8755403a0af9 + * Stub hash: d08ac20dda53ab8eb950d0fcb15b74bb46486624 * Has decl header: yes */ ZEND_BEGIN_ARG_INFO_EX(arginfo_zend_trigger_bailout, 0, 0, 0) @@ -186,6 +186,8 @@ ZEND_END_ARG_INFO() #define arginfo_zend_test_gh19792 arginfo_zend_trigger_bailout +#define arginfo_zend_test_rc_string arginfo_zend_create_unterminated_string + #define arginfo_ZendTestNS2_namespaced_func arginfo_zend_trigger_bailout #define arginfo_ZendTestNS2_namespaced_deprecated_func arginfo_zend_trigger_bailout @@ -320,6 +322,7 @@ static ZEND_FUNCTION(zend_test_gh18756); static ZEND_FUNCTION(zend_test_opcache_preloading); static ZEND_FUNCTION(zend_test_uri_parser); static ZEND_FUNCTION(zend_test_gh19792); +static ZEND_FUNCTION(zend_test_rc_string); static ZEND_FUNCTION(ZendTestNS2_namespaced_func); static ZEND_FUNCTION(ZendTestNS2_namespaced_deprecated_func); static ZEND_FUNCTION(ZendTestNS2_ZendSubNS_namespaced_func); @@ -426,6 +429,7 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(zend_test_opcache_preloading, arginfo_zend_test_opcache_preloading) ZEND_FE(zend_test_uri_parser, arginfo_zend_test_uri_parser) ZEND_FE(zend_test_gh19792, arginfo_zend_test_gh19792) + ZEND_FE(zend_test_rc_string, arginfo_zend_test_rc_string) #if (PHP_VERSION_ID >= 80400) ZEND_RAW_FENTRY(ZEND_NS_NAME("ZendTestNS2", "namespaced_func"), zif_ZendTestNS2_namespaced_func, arginfo_ZendTestNS2_namespaced_func, 0, NULL, NULL) #else diff --git a/main/main.c b/main/main.c index cc3f1cae2586..31e80ed83b59 100644 --- a/main/main.c +++ b/main/main.c @@ -2650,6 +2650,7 @@ PHPAPI bool php_execute_script_ex(zend_file_handle *primary_file, zval *retval) } } zend_catch { result = false; + zend_discard_delayed_effects(); } zend_end_try(); if (prepend_file_p) { diff --git a/tests/classes/bug27468.phpt b/tests/classes/bug27468.phpt index d590683c82cf..50fad7d21557 100644 --- a/tests/classes/bug27468.phpt +++ b/tests/classes/bug27468.phpt @@ -8,6 +8,7 @@ class foo { } } new foo(); +(function () {})(); echo 'OK'; ?> --EXPECTF-- diff --git a/tests/classes/ctor_dtor.phpt b/tests/classes/ctor_dtor.phpt index 3a40f7f5688b..1d06ff4bfb8b 100644 --- a/tests/classes/ctor_dtor.phpt +++ b/tests/classes/ctor_dtor.phpt @@ -24,6 +24,7 @@ class late { $t = new early(); $t->__construct(); unset($t); +(function () {})(); $t = new late(); //unset($t); delay to end of script diff --git a/tests/classes/ctor_dtor_inheritance.phpt b/tests/classes/ctor_dtor_inheritance.phpt index 5dbb1747065b..d1239cec20b4 100644 --- a/tests/classes/ctor_dtor_inheritance.phpt +++ b/tests/classes/ctor_dtor_inheritance.phpt @@ -46,9 +46,11 @@ class derived extends base { echo "Testing class base\n"; $t = new base(); unset($t); +(function () {})(); echo "Testing class derived\n"; $t = new derived(); unset($t); +(function () {})(); echo "Done\n"; ?> diff --git a/tests/classes/destructor_and_exceptions.phpt b/tests/classes/destructor_and_exceptions.phpt index 0f51a21a09d0..b65fbaa38463 100644 --- a/tests/classes/destructor_and_exceptions.phpt +++ b/tests/classes/destructor_and_exceptions.phpt @@ -19,6 +19,7 @@ try { $a = new FailClass; unset($a); + (function () {})(); } catch(Exception $e) { @@ -32,6 +33,7 @@ class FatalException extends Exception echo __METHOD__ . "\n"; $o = new FailClass; unset($o); + (function () {})(); echo "Done: " . __METHOD__ . "\n"; } } diff --git a/tests/classes/destructor_inheritance.phpt b/tests/classes/destructor_inheritance.phpt index c527c04b4fc1..2a3544f87351 100644 --- a/tests/classes/destructor_inheritance.phpt +++ b/tests/classes/destructor_inheritance.phpt @@ -18,6 +18,7 @@ class derived extends base { $obj = new derived; unset($obj); +(function () {})(); echo 'Done'; ?> diff --git a/tests/classes/destructor_visibility_001.phpt b/tests/classes/destructor_visibility_001.phpt index 6fee6e3be742..1d30097b42d7 100644 --- a/tests/classes/destructor_visibility_001.phpt +++ b/tests/classes/destructor_visibility_001.phpt @@ -15,6 +15,7 @@ class Derived extends Base { $obj = new Derived; unset($obj); +(function () {})(); ?> ===DONE=== diff --git a/tests/classes/factory_and_singleton_001.phpt b/tests/classes/factory_and_singleton_001.phpt index ead7d480cd7c..59a2d4ccee4f 100644 --- a/tests/classes/factory_and_singleton_001.phpt +++ b/tests/classes/factory_and_singleton_001.phpt @@ -24,6 +24,7 @@ class test { static function destroy() { test::$test = NULL; + (function () {})(); } protected function __destruct() { @@ -61,17 +62,20 @@ var_dump($y->get()); echo "Destruct x\n"; $x = NULL; +(function () {})(); var_dump(test::getX()); var_dump(test::count()); var_dump($y->get()); echo "Destruct y\n"; $y = NULL; +(function () {})(); var_dump(test::getX()); var_dump(test::count()); echo "Destruct static\n"; test::destroy(); +(function () {})(); var_dump(test::getX()); var_dump(test::count()); diff --git a/tests/classes/factory_and_singleton_005.phpt b/tests/classes/factory_and_singleton_005.phpt index 41914bf0e087..03ca6fa3d9db 100644 --- a/tests/classes/factory_and_singleton_005.phpt +++ b/tests/classes/factory_and_singleton_005.phpt @@ -10,6 +10,7 @@ class test { $obj = new test; $obj = NULL; +(function () {})(); echo "Done\n"; ?> diff --git a/tests/classes/factory_and_singleton_006.phpt b/tests/classes/factory_and_singleton_006.phpt index 596a0792cd09..4aaa247322e9 100644 --- a/tests/classes/factory_and_singleton_006.phpt +++ b/tests/classes/factory_and_singleton_006.phpt @@ -10,6 +10,7 @@ class test { $obj = new test; $obj = NULL; +(function () {})(); echo "Done\n"; ?> diff --git a/tests/classes/iterators_002.phpt b/tests/classes/iterators_002.phpt index 71f252dc0ede..d48e784ee01d 100644 --- a/tests/classes/iterators_002.phpt +++ b/tests/classes/iterators_002.phpt @@ -65,6 +65,7 @@ foreach($t as $k => $v) { } unset($t); +(function () {})(); print "Done\n"; ?> diff --git a/tests/classes/tostring_002.phpt b/tests/classes/tostring_002.phpt index 3977ad883f25..59df4c1c5639 100644 --- a/tests/classes/tostring_002.phpt +++ b/tests/classes/tostring_002.phpt @@ -18,6 +18,7 @@ class Test $o = new Test; $o = NULL; +(function () {})(); $o = new Test; diff --git a/tests/classes/tostring_003.phpt b/tests/classes/tostring_003.phpt index 87a5fe42e1b1..2d6efc77a030 100644 --- a/tests/classes/tostring_003.phpt +++ b/tests/classes/tostring_003.phpt @@ -21,6 +21,7 @@ try { $o = new Test; $o = NULL; + (function () {})(); } catch(Exception $e) { diff --git a/tests/lang/bug22592.phpt b/tests/lang/bug22592.phpt index 24b5f50fdf5a..2505b2ff7212 100644 --- a/tests/lang/bug22592.phpt +++ b/tests/lang/bug22592.phpt @@ -39,12 +39,12 @@ var_dump($result); string(5) "* *-*" string(7) "* *-* *" string(7) "*4*-* *" -[Only the first byte will be assigned to the string offset] string(7) "*4*s* *" +[Only the first byte will be assigned to the string offset] string(8) "*4*s* *0" string(8) "*-*-* *0" -[Only the first byte will be assigned to the string offset] string(8) "*-*s*s*0" +[Only the first byte will be assigned to the string offset] string(8) "4-4s4s*0" string(9) "4-4s4s505" string(9) "454s4s505" diff --git a/tests/lang/bug25547.phpt b/tests/lang/bug25547.phpt index 53b951fd4543..49bdb5e75115 100644 --- a/tests/lang/bug25547.phpt +++ b/tests/lang/bug25547.phpt @@ -22,9 +22,9 @@ print_r($output); echo "Done"; ?> --EXPECT-- -handler(Undefined array key "foo") Array ( [foo] => 1 ) +handler(Undefined array key "foo") Done diff --git a/tests/lang/bug25922.phpt b/tests/lang/bug25922.phpt index 4927bfea776c..41aa72ae35d6 100644 --- a/tests/lang/bug25922.phpt +++ b/tests/lang/bug25922.phpt @@ -19,6 +19,6 @@ function test() test(); ?> --EXPECT-- +Undefined index here: '' Undefined variable $data Trying to access array offset on null -Undefined index here: '' diff --git a/tests/lang/bug28213.phpt b/tests/lang/bug28213.phpt index abd965cbb935..bc9ec5e46507 100644 --- a/tests/lang/bug28213.phpt +++ b/tests/lang/bug28213.phpt @@ -6,8 +6,6 @@ class FooBar { static function error() { debug_print_backtrace(); } } set_error_handler(array('FooBar', 'error')); include('foobar.php'); ?> ---EXPECTF-- -#0 %s(%d): FooBar::error(2, 'include(foobar....', '%s', 4) -#1 %s(%d): include() -#0 %s(%d): FooBar::error(2, 'include(): Fail...', '%s', 4) -#1 %s(%d): include() +--EXPECT-- +#0 [internal function]: FooBar::error(2, 'include(foobar....', '/home/arnaud/de...', 4) +#0 [internal function]: FooBar::error(2, 'include(): Fail...', '/home/arnaud/de...', 4) diff --git a/tests/output/gh20352.phpt b/tests/output/gh20352.phpt index 3074add99d36..16be0b920e80 100644 --- a/tests/output/gh20352.phpt +++ b/tests/output/gh20352.phpt @@ -21,7 +21,4 @@ ob_start(new Test, 1); echo "trigger bug"; ?> --EXPECTF-- -%r(Notice: ob_start\(\): Failed to create buffer in [^\r\n]+ on line \d+\r?\n(\r?\n)?)+%r -Notice: ob_start(): Failed to create buffer in %s on line %d - Fatal error: ob_start(): Cannot use output buffering in output buffering display handlers in %s on line %d