From 44c42a61dee3c63b9e75d3ad663cc2547259d536 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 | 3 +- Zend/tests/gc/gc_050.phpt | 3 +- .../generators/finally/return_return.phpt | 3 +- .../generators/finally/yield_return.phpt | 3 +- .../generators/get_return_and_finally.phpt | 3 +- Zend/tests/generators/gh11028_1.phpt | 3 +- Zend/tests/generators/gh11028_2.phpt | 2 + Zend/tests/generators/gh11028_3.phpt | 3 +- .../generators/yield_in_finally_cleanup.phpt | 3 +- 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 | 3 +- Zend/tests/try/bug70228_2.phpt | 3 +- Zend/tests/try/bug70228_3.phpt | 3 +- Zend/tests/try/bug70228_4.phpt | 3 +- Zend/tests/try/bug70228_6.phpt | 3 +- Zend/tests/try/catch_finally_003.phpt | 5 +- Zend/tests/try/catch_finally_005.phpt | 3 +- Zend/tests/try/catch_finally_006.phpt | 3 +- Zend/tests/try/finally_goto_005.phpt | 3 +- .../tests/try/finally_return_deprecation.phpt | 86 +++++++++++++++++++ Zend/tests/try/try_catch_finally_003.phpt | 3 +- Zend/tests/try/try_finally_013.phpt | 3 +- Zend/tests/try/try_finally_014.phpt | 3 +- Zend/tests/try/try_finally_021.phpt | 3 +- 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, 155 insertions(+), 21 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..a2ae2429b28e 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-- +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d Exit diff --git a/Zend/tests/gc/gc_050.phpt b/Zend/tests/gc/gc_050.phpt index 0bedc7220fd4..cf30776d9de9 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-- +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d OK diff --git a/Zend/tests/generators/finally/return_return.phpt b/Zend/tests/generators/finally/return_return.phpt index 194fc93de7c2..895adc37cce3 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 diff --git a/Zend/tests/generators/finally/yield_return.phpt b/Zend/tests/generators/finally/yield_return.phpt index 6191f389e53e..dbfabea50889 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-- +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d 1 diff --git a/Zend/tests/generators/get_return_and_finally.phpt b/Zend/tests/generators/get_return_and_finally.phpt index 150e5b83c4db..8ced4d0008b5 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 diff --git a/Zend/tests/generators/gh11028_1.phpt b/Zend/tests/generators/gh11028_1.phpt index e1e7aa5019e5..d1c07dc9de66 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 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..c58e00dc09b1 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-- +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d exception diff --git a/Zend/tests/generators/yield_in_finally_cleanup.phpt b/Zend/tests/generators/yield_in_finally_cleanup.phpt index 9a76261e0d5e..538c14bdb774 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-- +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d ===DONE=== 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..b69034da8a6c 100644 --- a/Zend/tests/try/bug70228.phpt +++ b/Zend/tests/try/bug70228.phpt @@ -10,5 +10,6 @@ function foo() { var_dump(foo()); ?> ---EXPECT-- +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d string(2) "bb" diff --git a/Zend/tests/try/bug70228_2.phpt b/Zend/tests/try/bug70228_2.phpt index c988e706ce47..bbb44bcd6a42 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-- +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d int(42) diff --git a/Zend/tests/try/bug70228_3.phpt b/Zend/tests/try/bug70228_3.phpt index 55dbe4f8914a..80a0f379765b 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 diff --git a/Zend/tests/try/bug70228_4.phpt b/Zend/tests/try/bug70228_4.phpt index f0ab3b0c2c11..7e0fd78707d7 100644 --- a/Zend/tests/try/bug70228_4.phpt +++ b/Zend/tests/try/bug70228_4.phpt @@ -28,5 +28,6 @@ try { } while ($e); } ?> ---EXPECT-- +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d 1 diff --git a/Zend/tests/try/bug70228_6.phpt b/Zend/tests/try/bug70228_6.phpt index fc68657f4c15..5bc3a70bdcfe 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-- +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d int(42) diff --git a/Zend/tests/try/catch_finally_003.phpt b/Zend/tests/try/catch_finally_003.phpt index 610d701872b1..3cfb4fd6c5a1 100644 --- a/Zend/tests/try/catch_finally_003.phpt +++ b/Zend/tests/try/catch_finally_003.phpt @@ -32,7 +32,10 @@ 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" diff --git a/Zend/tests/try/catch_finally_005.phpt b/Zend/tests/try/catch_finally_005.phpt index 7671d05df582..bc4a72155bf6 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-- +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d int(3) diff --git a/Zend/tests/try/catch_finally_006.phpt b/Zend/tests/try/catch_finally_006.phpt index 216219b6a5b3..463ce377f0a3 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" diff --git a/Zend/tests/try/finally_goto_005.phpt b/Zend/tests/try/finally_goto_005.phpt index ffb0e68be103..0cb38a502993 100644 --- a/Zend/tests/try/finally_goto_005.phpt +++ b/Zend/tests/try/finally_goto_005.phpt @@ -11,5 +11,6 @@ label: try { } ?> ---EXPECT-- +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d success 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..3e37256837b0 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-- +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d 1234int(4) diff --git a/Zend/tests/try/try_finally_013.phpt b/Zend/tests/try/try_finally_013.phpt index 0e82dcbb4cf4..1f0e044a1285 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 diff --git a/Zend/tests/try/try_finally_014.phpt b/Zend/tests/try/try_finally_014.phpt index a45f63f1f3d4..0cdc8ddffc8a 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 diff --git a/Zend/tests/try/try_finally_021.phpt b/Zend/tests/try/try_finally_021.phpt index d25f393be1f0..f624eeb5c6fb 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-- +--EXPECTF-- +Deprecated: Returning from a finally block is deprecated in %s on line %d ok ok 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 9c80cccb7cb9..b4eccaccdead 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -348,6 +348,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; } @@ -6150,6 +6151,10 @@ static void zend_compile_return(const zend_ast *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()) { @@ -7398,7 +7403,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 3d4e6f3c3f9f..34a91183b2a9 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--