From 8199001ef567640f609fb137561f77617593ba78 Mon Sep 17 00:00:00 2001 From: Osama Aldemeery Date: Tue, 16 Jun 2026 04:48:15 +0300 Subject: [PATCH] Deprecate returning from a finally block. --- Zend/tests/exit_finally_3.phpt | 5 +- Zend/tests/gc/gc_050.phpt | 5 +- .../generators/finally/return_return.phpt | 5 +- .../generators/finally/yield_return.phpt | 5 +- .../generators/get_return_and_finally.phpt | 5 +- Zend/tests/generators/gh11028_1.phpt | 5 +- Zend/tests/generators/gh11028_2.phpt | 2 + Zend/tests/generators/gh11028_3.phpt | 5 +- .../generators/yield_in_finally_cleanup.phpt | 5 +- Zend/tests/oss_fuzz_438780145.phpt | 2 + Zend/tests/return_types/029.phpt | 2 + .../return_types/never_finally_return.phpt | 2 + Zend/tests/try/bug70228.phpt | 5 +- Zend/tests/try/bug70228_2.phpt | 5 +- Zend/tests/try/bug70228_3.phpt | 5 +- Zend/tests/try/bug70228_4.phpt | 5 +- Zend/tests/try/bug70228_6.phpt | 5 +- Zend/tests/try/catch_finally_003.phpt | 7 +- Zend/tests/try/catch_finally_005.phpt | 5 +- Zend/tests/try/catch_finally_006.phpt | 5 +- Zend/tests/try/finally_goto_005.phpt | 5 +- .../tests/try/finally_return_deprecation.phpt | 86 +++++++++++++++++++ Zend/tests/try/try_catch_finally_003.phpt | 5 +- Zend/tests/try/try_finally_013.phpt | 5 +- Zend/tests/try/try_finally_014.phpt | 5 +- Zend/tests/try/try_finally_021.phpt | 5 +- Zend/tests/try/try_finally_023.phpt | 1 + Zend/tests/try/try_finally_027.phpt | 1 + Zend/zend_compile.c | 8 ++ Zend/zend_compile.h | 1 + sapi/phpdbg/tests/exceptions_001.phpt | 3 + sapi/phpdbg/tests/exceptions_002.phpt | 3 + 32 files changed, 176 insertions(+), 42 deletions(-) create mode 100644 Zend/tests/try/finally_return_deprecation.phpt diff --git a/Zend/tests/exit_finally_3.phpt b/Zend/tests/exit_finally_3.phpt index 12d7747adea9..322d97ab1959 100644 --- a/Zend/tests/exit_finally_3.phpt +++ b/Zend/tests/exit_finally_3.phpt @@ -15,5 +15,6 @@ function test() { var_dump(test()); ?> ---EXPECT-- -Exit +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d +Exit \ No newline at end of file diff --git a/Zend/tests/gc/gc_050.phpt b/Zend/tests/gc/gc_050.phpt index 0bedc7220fd4..10318a8abe4a 100644 --- a/Zend/tests/gc/gc_050.phpt +++ b/Zend/tests/gc/gc_050.phpt @@ -36,5 +36,6 @@ for ($i = 0; $i < 100000; $i++) { } echo "OK\n"; ?> ---EXPECT-- -OK +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d +OK \ No newline at end of file diff --git a/Zend/tests/generators/finally/return_return.phpt b/Zend/tests/generators/finally/return_return.phpt index 194fc93de7c2..92aaaa8704be 100644 --- a/Zend/tests/generators/finally/return_return.phpt +++ b/Zend/tests/generators/finally/return_return.phpt @@ -27,7 +27,8 @@ $gen = gen(); $gen->rewind(); // force run ?> ---EXPECT-- +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d before return before return in inner finally -outer finally run +outer finally run \ No newline at end of file diff --git a/Zend/tests/generators/finally/yield_return.phpt b/Zend/tests/generators/finally/yield_return.phpt index 6191f389e53e..32fc763b3c99 100644 --- a/Zend/tests/generators/finally/yield_return.phpt +++ b/Zend/tests/generators/finally/yield_return.phpt @@ -15,5 +15,6 @@ foreach (foo(1, 5) as $x) { echo $x, "\n"; } ?> ---EXPECT-- -1 +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d +1 \ No newline at end of file diff --git a/Zend/tests/generators/get_return_and_finally.phpt b/Zend/tests/generators/get_return_and_finally.phpt index 150e5b83c4db..ae42cd6c76fe 100644 --- a/Zend/tests/generators/get_return_and_finally.phpt +++ b/Zend/tests/generators/get_return_and_finally.phpt @@ -41,7 +41,8 @@ try { } ?> ---EXPECT-- +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d int(42) gen2() throw -Cannot get return value of a generator that hasn't returned +Cannot get return value of a generator that hasn't returned \ No newline at end of file diff --git a/Zend/tests/generators/gh11028_1.phpt b/Zend/tests/generators/gh11028_1.phpt index e1e7aa5019e5..8f8d371eb084 100644 --- a/Zend/tests/generators/gh11028_1.phpt +++ b/Zend/tests/generators/gh11028_1.phpt @@ -24,7 +24,8 @@ test("false", false); test("true", true); test("object", new stdClass); ?> ---EXPECT-- +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d yield null Keys must be of type int|string during array unpacking yield false @@ -32,4 +33,4 @@ Keys must be of type int|string during array unpacking yield true Keys must be of type int|string during array unpacking yield object -Keys must be of type int|string during array unpacking +Keys must be of type int|string during array unpacking \ No newline at end of file diff --git a/Zend/tests/generators/gh11028_2.phpt b/Zend/tests/generators/gh11028_2.phpt index ddc9618e8ed8..bf364329849f 100644 --- a/Zend/tests/generators/gh11028_2.phpt +++ b/Zend/tests/generators/gh11028_2.phpt @@ -15,6 +15,8 @@ $c = (function () { })()[0]; ?> --EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d + Warning: Undefined variable $a in %s on line %d Fatal error: Uncaught Error: Keys must be of type int|string during array unpacking in %s:%d diff --git a/Zend/tests/generators/gh11028_3.phpt b/Zend/tests/generators/gh11028_3.phpt index 7ea1aac6f6cf..2c4ad9f99514 100644 --- a/Zend/tests/generators/gh11028_3.phpt +++ b/Zend/tests/generators/gh11028_3.phpt @@ -17,5 +17,6 @@ try { echo $e->getMessage(), "\n"; } ?> ---EXPECT-- -exception +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d +exception \ No newline at end of file diff --git a/Zend/tests/generators/yield_in_finally_cleanup.phpt b/Zend/tests/generators/yield_in_finally_cleanup.phpt index 9a76261e0d5e..618dc711bb1a 100644 --- a/Zend/tests/generators/yield_in_finally_cleanup.phpt +++ b/Zend/tests/generators/yield_in_finally_cleanup.phpt @@ -47,5 +47,6 @@ gen4()->rewind(); ?> ===DONE=== ---EXPECT-- -===DONE=== +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d +===DONE=== \ No newline at end of file diff --git a/Zend/tests/oss_fuzz_438780145.phpt b/Zend/tests/oss_fuzz_438780145.phpt index 4c6936a69a01..11797fcce999 100644 --- a/Zend/tests/oss_fuzz_438780145.phpt +++ b/Zend/tests/oss_fuzz_438780145.phpt @@ -20,6 +20,8 @@ test(); ?> --EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d + Fatal error: Uncaught TypeError: test(): Return value must be of type int, string returned in %s:%d Stack trace: #0 %s(%d): test() diff --git a/Zend/tests/return_types/029.phpt b/Zend/tests/return_types/029.phpt index c6fb4432158c..8711df828fff 100644 --- a/Zend/tests/return_types/029.phpt +++ b/Zend/tests/return_types/029.phpt @@ -14,6 +14,8 @@ function foo() : array { foo(); ?> --EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d + Fatal error: Uncaught Exception: xxxx in %s:%d Stack trace: #0 %s(%d): foo() diff --git a/Zend/tests/return_types/never_finally_return.phpt b/Zend/tests/return_types/never_finally_return.phpt index b03859710276..2a6af6923eef 100644 --- a/Zend/tests/return_types/never_finally_return.phpt +++ b/Zend/tests/return_types/never_finally_return.phpt @@ -14,4 +14,6 @@ function foo() : never { // Note the lack of function call: function validated at compile-time ?> --EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d + Fatal error: A never-returning function must not return in %s on line %d diff --git a/Zend/tests/try/bug70228.phpt b/Zend/tests/try/bug70228.phpt index 8b812517a305..e248ee8c6305 100644 --- a/Zend/tests/try/bug70228.phpt +++ b/Zend/tests/try/bug70228.phpt @@ -10,5 +10,6 @@ function foo() { var_dump(foo()); ?> ---EXPECT-- -string(2) "bb" +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d +string(2) "bb" \ No newline at end of file diff --git a/Zend/tests/try/bug70228_2.phpt b/Zend/tests/try/bug70228_2.phpt index c988e706ce47..c3ea6c6b7c16 100644 --- a/Zend/tests/try/bug70228_2.phpt +++ b/Zend/tests/try/bug70228_2.phpt @@ -16,5 +16,6 @@ function test() { var_dump(test()); ?> ---EXPECT-- -int(42) +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d +int(42) \ No newline at end of file diff --git a/Zend/tests/try/bug70228_3.phpt b/Zend/tests/try/bug70228_3.phpt index 55dbe4f8914a..9c3475a7131d 100644 --- a/Zend/tests/try/bug70228_3.phpt +++ b/Zend/tests/try/bug70228_3.phpt @@ -26,6 +26,7 @@ try { } while ($e); } ?> ---EXPECT-- +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d 2 -1 +1 \ No newline at end of file diff --git a/Zend/tests/try/bug70228_4.phpt b/Zend/tests/try/bug70228_4.phpt index f0ab3b0c2c11..7499ee6fa5a1 100644 --- a/Zend/tests/try/bug70228_4.phpt +++ b/Zend/tests/try/bug70228_4.phpt @@ -28,5 +28,6 @@ try { } while ($e); } ?> ---EXPECT-- -1 +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d +1 \ No newline at end of file diff --git a/Zend/tests/try/bug70228_6.phpt b/Zend/tests/try/bug70228_6.phpt index fc68657f4c15..ec7877425cca 100644 --- a/Zend/tests/try/bug70228_6.phpt +++ b/Zend/tests/try/bug70228_6.phpt @@ -14,5 +14,6 @@ function test($x) { var_dump(test([1])); ?> ---EXPECT-- -int(42) +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d +int(42) \ No newline at end of file diff --git a/Zend/tests/try/catch_finally_003.phpt b/Zend/tests/try/catch_finally_003.phpt index 610d701872b1..d5f4c65119bc 100644 --- a/Zend/tests/try/catch_finally_003.phpt +++ b/Zend/tests/try/catch_finally_003.phpt @@ -32,9 +32,12 @@ function &bar($a) { var_dump(foo("para")); var_dump(bar("para")); ?> ---EXPECT-- +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d + +Deprecated: Returning from a finally block is deprecated in %s on line %d string(3) "try" string(7) "finally" string(7) "finally" try -string(4) "para" +string(4) "para" \ No newline at end of file diff --git a/Zend/tests/try/catch_finally_005.phpt b/Zend/tests/try/catch_finally_005.phpt index 7671d05df582..d12c404cb1e0 100644 --- a/Zend/tests/try/catch_finally_005.phpt +++ b/Zend/tests/try/catch_finally_005.phpt @@ -17,5 +17,6 @@ function foo ($a) { var_dump(foo("para")); ?> ---EXPECT-- -int(3) +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d +int(3) \ No newline at end of file diff --git a/Zend/tests/try/catch_finally_006.phpt b/Zend/tests/try/catch_finally_006.phpt index 216219b6a5b3..e19eed063d83 100644 --- a/Zend/tests/try/catch_finally_006.phpt +++ b/Zend/tests/try/catch_finally_006.phpt @@ -22,7 +22,8 @@ try { var_dump($e->getMessage()); } ?> ---EXPECT-- +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d string(4) "para" string(7) "finally" -string(6) "return" +string(6) "return" \ No newline at end of file diff --git a/Zend/tests/try/finally_goto_005.phpt b/Zend/tests/try/finally_goto_005.phpt index ffb0e68be103..d7a246883396 100644 --- a/Zend/tests/try/finally_goto_005.phpt +++ b/Zend/tests/try/finally_goto_005.phpt @@ -11,5 +11,6 @@ label: try { } ?> ---EXPECT-- -success +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d +success \ No newline at end of file diff --git a/Zend/tests/try/finally_return_deprecation.phpt b/Zend/tests/try/finally_return_deprecation.phpt new file mode 100644 index 000000000000..86cc07e59481 --- /dev/null +++ b/Zend/tests/try/finally_return_deprecation.phpt @@ -0,0 +1,86 @@ +--TEST-- +Returning from a finally block is deprecated +--FILE-- + +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d + +Deprecated: Returning from a finally block is deprecated in %s on line %d + +Deprecated: Returning from a finally block is deprecated in %s on line %d + +Deprecated: Returning from a finally block is deprecated in %s on line %d + +Deprecated: Returning from a finally block is deprecated in %s on line %d diff --git a/Zend/tests/try/try_catch_finally_003.phpt b/Zend/tests/try/try_catch_finally_003.phpt index 4d285eedb8da..be254a49636e 100644 --- a/Zend/tests/try/try_catch_finally_003.phpt +++ b/Zend/tests/try/try_catch_finally_003.phpt @@ -32,5 +32,6 @@ function foo () { var_dump(foo()); ?> ---EXPECT-- -1234int(4) +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d +1234int(4) \ No newline at end of file diff --git a/Zend/tests/try/try_finally_013.phpt b/Zend/tests/try/try_finally_013.phpt index 0e82dcbb4cf4..db06989476cd 100644 --- a/Zend/tests/try/try_finally_013.phpt +++ b/Zend/tests/try/try_finally_013.phpt @@ -18,6 +18,7 @@ function foo() { foo(); ?> ---EXPECT-- +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d try -finally +finally \ No newline at end of file diff --git a/Zend/tests/try/try_finally_014.phpt b/Zend/tests/try/try_finally_014.phpt index a45f63f1f3d4..6a88c01816b5 100644 --- a/Zend/tests/try/try_finally_014.phpt +++ b/Zend/tests/try/try_finally_014.phpt @@ -20,6 +20,7 @@ function foo() { foo(); ?> ---EXPECT-- +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d try -finally +finally \ No newline at end of file diff --git a/Zend/tests/try/try_finally_021.phpt b/Zend/tests/try/try_finally_021.phpt index d25f393be1f0..709e1f9b1ec2 100644 --- a/Zend/tests/try/try_finally_021.phpt +++ b/Zend/tests/try/try_finally_021.phpt @@ -15,6 +15,7 @@ foreach ([0] as $_) { } } ?> ---EXPECT-- -ok +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d ok +ok \ No newline at end of file diff --git a/Zend/tests/try/try_finally_023.phpt b/Zend/tests/try/try_finally_023.phpt index e88eddb3b236..305684e3111b 100644 --- a/Zend/tests/try/try_finally_023.phpt +++ b/Zend/tests/try/try_finally_023.phpt @@ -31,6 +31,7 @@ try { ?> --EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d Exception: 1 in %s:%d Stack trace: #0 %s(%d): test() diff --git a/Zend/tests/try/try_finally_027.phpt b/Zend/tests/try/try_finally_027.phpt index 1e66479eb09b..059a16a977f1 100644 --- a/Zend/tests/try/try_finally_027.phpt +++ b/Zend/tests/try/try_finally_027.phpt @@ -23,6 +23,7 @@ try { ?> --EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d Exception: 1 in %s:%d Stack trace: #0 %s(%d): test() diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 9f8ebad8ab29..264ec6268f5d 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -343,6 +343,7 @@ void zend_oparray_context_begin(zend_oparray_context *prev_context, zend_op_arra CG(context).brk_cont_array = NULL; CG(context).labels = NULL; CG(context).in_jmp_frameless_branch = false; + CG(context).in_finally = false; CG(context).active_property_info_name = NULL; CG(context).active_property_hook_kind = (zend_property_hook_kind)-1; } @@ -5993,6 +5994,10 @@ static void zend_compile_return(const zend_ast *ast) /* {{{ */ zend_compile_expr(&expr_node, expr_ast); } + if (CG(context).in_finally) { + zend_error(E_DEPRECATED, "Returning from a finally block is deprecated"); + } + if ((CG(active_op_array)->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK) && (expr_node.op_type == IS_CV || (by_ref && expr_node.op_type == IS_VAR)) && zend_has_finally()) { @@ -7163,7 +7168,10 @@ static void zend_compile_try(const zend_ast *ast) /* {{{ */ zend_emit_op(NULL, ZEND_JMP, NULL, NULL); + bool orig_in_finally = CG(context).in_finally; + CG(context).in_finally = true; zend_compile_stmt(finally_ast); + CG(context).in_finally = orig_in_finally; CG(active_op_array)->try_catch_array[try_catch_offset].finally_op = opnum_jmp + 1; CG(active_op_array)->try_catch_array[try_catch_offset].finally_end diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 2351882a560d..761ca8fdd991 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -207,6 +207,7 @@ typedef struct _zend_oparray_context { zend_string *active_property_info_name; zend_property_hook_kind active_property_hook_kind; bool in_jmp_frameless_branch; + bool in_finally; bool has_assigned_to_http_response_header; } zend_oparray_context; diff --git a/sapi/phpdbg/tests/exceptions_001.phpt b/sapi/phpdbg/tests/exceptions_001.phpt index 2ebdc0f664d1..799832ae6d07 100644 --- a/sapi/phpdbg/tests/exceptions_001.phpt +++ b/sapi/phpdbg/tests/exceptions_001.phpt @@ -7,6 +7,7 @@ ev 1 + 2 c q --EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d [Successful compilation of %s] prompt> handle first [Uncaught Error in %s on line 16: Call to undefined function foo()] @@ -22,6 +23,8 @@ Stack trace: #0 %s(22): {closure:%s:%d}() #1 {main} [Script ended normally] + +Deprecated: Returning from a finally block is deprecated in %s on line %d prompt> --FILE-- handle first [Uncaught Error in %s on line 16: Call to undefined function foo()] @@ -26,6 +27,8 @@ Stack trace: #0 %s(20): {closure:%s:%d}() #1 {main} [Script ended normally] + +Deprecated: Returning from a finally block is deprecated in %s on line %d prompt> [The stack contains nothing !] prompt> --FILE--