Skip to content

Commit

Permalink
Zend: make exit/die a function instead of a language construct
Browse files Browse the repository at this point in the history
  • Loading branch information
Girgias committed May 11, 2024
1 parent 6ffd120 commit 04c54f3
Show file tree
Hide file tree
Showing 51 changed files with 1,355 additions and 1,401 deletions.
4 changes: 1 addition & 3 deletions Zend/Optimizer/block_pass.c
Original file line number Diff line number Diff line change
Expand Up @@ -868,7 +868,6 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array
break;

case ZEND_RETURN:
case ZEND_EXIT:
if (opline->op1_type == IS_TMP_VAR) {
src = VAR_SOURCE(opline->op1);
if (src && src->opcode == ZEND_QM_ASSIGN) {
Expand Down Expand Up @@ -1221,8 +1220,7 @@ static void zend_jmp_optimization(zend_basic_block *block, zend_op_array *op_arr
target = op_array->opcodes + target_block->start;
if ((target->opcode == ZEND_RETURN ||
target->opcode == ZEND_RETURN_BY_REF ||
target->opcode == ZEND_GENERATOR_RETURN ||
target->opcode == ZEND_EXIT) &&
target->opcode == ZEND_GENERATOR_RETURN) &&
!(op_array->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK)) {
/* JMP L, L: RETURN to immediate RETURN */
*last_op = *target;
Expand Down
1 change: 0 additions & 1 deletion Zend/Optimizer/pass1.c
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,6 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
case ZEND_RETURN:
case ZEND_RETURN_BY_REF:
case ZEND_GENERATOR_RETURN:
case ZEND_EXIT:
case ZEND_THROW:
case ZEND_MATCH_ERROR:
case ZEND_CATCH:
Expand Down
3 changes: 1 addition & 2 deletions Zend/Optimizer/pass3.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,7 @@ void zend_optimizer_pass3(zend_op_array *op_array, zend_optimizer_ctx *ctx)
MAKE_NOP(opline);
} else if ((target->opcode == ZEND_RETURN ||
target->opcode == ZEND_RETURN_BY_REF ||
target->opcode == ZEND_GENERATOR_RETURN ||
target->opcode == ZEND_EXIT) &&
target->opcode == ZEND_GENERATOR_RETURN) &&
!(op_array->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK)) {
/* JMP L, L: RETURN to immediate RETURN */
*opline = *target;
Expand Down
4 changes: 0 additions & 4 deletions Zend/Optimizer/zend_call_graph.c
Original file line number Diff line number Diff line change
Expand Up @@ -161,10 +161,6 @@ ZEND_API void zend_analyze_calls(zend_arena **arena, zend_script *script, uint32
call_info->send_unpack = 1;
}
break;
case ZEND_EXIT:
/* In this case the DO_CALL opcode may have been dropped
* and caller_call_opline will be NULL. */
break;
}
opline++;
}
Expand Down
2 changes: 0 additions & 2 deletions Zend/Optimizer/zend_cfg.c
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,6 @@ ZEND_API void zend_build_cfg(zend_arena **arena, const zend_op_array *op_array,
}
break;
case ZEND_MATCH_ERROR:
case ZEND_EXIT:
case ZEND_THROW:
/* Don't treat THROW as terminator if it's used in expression context,
* as we may lose live ranges when eliminating unreachable code. */
Expand Down Expand Up @@ -507,7 +506,6 @@ ZEND_API void zend_build_cfg(zend_arena **arena, const zend_op_array *op_array,
case ZEND_RETURN:
case ZEND_RETURN_BY_REF:
case ZEND_GENERATOR_RETURN:
case ZEND_EXIT:
case ZEND_THROW:
case ZEND_MATCH_ERROR:
case ZEND_VERIFY_NEVER_TYPE:
Expand Down
3 changes: 3 additions & 0 deletions Zend/tests/arginfo_zpp_mismatch.inc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ function skipFunction($function): bool {
|| $function === 'readline'
|| $function === 'readline_read_history'
|| $function === 'readline_write_history'
/* terminates script */
|| $function === 'exit'
|| $function === 'die'
/* intentionally violate invariants */
|| $function === 'zend_create_unterminated_string'
|| $function === 'zend_test_array_return'
Expand Down
2 changes: 1 addition & 1 deletion Zend/tests/exit/ast_print_assert_die_const.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ try {

?>
--EXPECT--
AssertionError: assert(0 && exit)
AssertionError: assert(0 && die)
2 changes: 1 addition & 1 deletion Zend/tests/exit/ast_print_assert_die_function.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ try {

?>
--EXPECT--
AssertionError: assert(0 && exit)
AssertionError: assert(0 && die())
2 changes: 1 addition & 1 deletion Zend/tests/exit/ast_print_assert_exit_function.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ try {

?>
--EXPECT--
AssertionError: assert(0 && exit)
AssertionError: assert(0 && exit())
2 changes: 1 addition & 1 deletion Zend/tests/exit/define_die_constant.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ var_dump(die);

?>
--EXPECTF--
Parse error: syntax error, unexpected token "exit", expecting identifier in %s on line %d
Fatal error: Cannot define constant with name die in %s on line %d
2 changes: 1 addition & 1 deletion Zend/tests/exit/define_die_constant_namespace.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ var_dump(die);

?>
--EXPECTF--
Parse error: syntax error, unexpected token "exit", expecting identifier in %s on line %d
Fatal error: Cannot define constant with name die in %s on line %d
2 changes: 1 addition & 1 deletion Zend/tests/exit/define_die_function.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ function die() { }

?>
--EXPECTF--
Parse error: syntax error, unexpected token "exit", expecting "(" in %s on line %d
Fatal error: Defining a custom die() function is not allowed, as the function has special semantics in %s on line %d
2 changes: 1 addition & 1 deletion Zend/tests/exit/define_die_function_namespace.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ var_dump(die());

?>
--EXPECTF--
Parse error: syntax error, unexpected token "exit", expecting "(" in %s on line %d
Fatal error: Defining a custom die() function is not allowed, as the function has special semantics in %s on line %d
2 changes: 1 addition & 1 deletion Zend/tests/exit/define_exit_constant.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ var_dump(exit);

?>
--EXPECTF--
Parse error: syntax error, unexpected token "exit", expecting identifier in %s on line %d
Fatal error: Cannot define constant with name exit in %s on line %d
2 changes: 1 addition & 1 deletion Zend/tests/exit/define_exit_constant_namespace.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ var_dump(exit);

?>
--EXPECTF--
Parse error: syntax error, unexpected token "exit", expecting identifier in %s on line %d
Fatal error: Cannot define constant with name exit in %s on line %d
2 changes: 1 addition & 1 deletion Zend/tests/exit/define_exit_function.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ function exit() { }

?>
--EXPECTF--
Parse error: syntax error, unexpected token "exit", expecting "(" in %s on line %d
Fatal error: Defining a custom exit() function is not allowed, as the function has special semantics in %s on line %d
2 changes: 1 addition & 1 deletion Zend/tests/exit/define_exit_function_namespace.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ function exit() { }

?>
--EXPECTF--
Parse error: syntax error, unexpected token "exit", expecting "(" in %s on line %d
Fatal error: Defining a custom exit() function is not allowed, as the function has special semantics in %s on line %d
6 changes: 4 additions & 2 deletions Zend/tests/exit/define_goto_label_die.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,7 @@ die:
echo "After\n";

?>
--EXPECTF--
Parse error: syntax error, unexpected token ":" in %s on line %d
--EXPECT--
Before
In between
After
5 changes: 3 additions & 2 deletions Zend/tests/exit/define_goto_label_die_with_jump.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ die:
echo "After\n";

?>
--EXPECTF--
Parse error: syntax error, unexpected token "exit", expecting identifier in %s on line %d
--EXPECT--
Before
After
6 changes: 4 additions & 2 deletions Zend/tests/exit/define_goto_label_exit.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,7 @@ exit:
echo "After\n";

?>
--EXPECTF--
Parse error: syntax error, unexpected token ":" in %s on line %d
--EXPECT--
Before
In between
After
5 changes: 3 additions & 2 deletions Zend/tests/exit/define_goto_label_exit_with_jump.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ exit:
echo "After\n";

?>
--EXPECTF--
Parse error: syntax error, unexpected token "exit", expecting identifier in %s on line %d
--EXPECT--
Before
After
13 changes: 7 additions & 6 deletions Zend/tests/exit/die_string_cast_exception.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ Bug #79777: String cast exception during die should be handled gracefully
--FILE--
<?php

die(new stdClass);
try {
die(new stdClass);
} catch (TypeError $e) {
echo $e->getMessage(), PHP_EOL;
}

?>
--EXPECTF--
Fatal error: Uncaught Error: Object of class stdClass could not be converted to string in %s:%d
Stack trace:
#0 {main}
thrown in %s on line %d
--EXPECT--
die(): Argument #1 ($code) must be of type string|int, stdClass given
1 change: 1 addition & 0 deletions Zend/tests/exit/disabling_die.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ die();

?>
--EXPECT--
Warning: Cannot disable function die() in Unknown on line 0
1 change: 1 addition & 0 deletions Zend/tests/exit/disabling_exit.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ exit();

?>
--EXPECT--
Warning: Cannot disable function exit() in Unknown on line 0
23 changes: 21 additions & 2 deletions Zend/tests/exit/exit_as_function.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,24 @@ foreach ($values as $value) {
}

?>
--EXPECTF--
Parse error: syntax error, unexpected token "...", expecting ")" in %s on line %d
--EXPECT--
string(4) "exit"
string(3) "die"
object(Closure)#1 (2) {
["function"]=>
string(4) "exit"
["parameter"]=>
array(1) {
["$code"]=>
string(10) "<optional>"
}
}
object(Closure)#2 (2) {
["function"]=>
string(3) "die"
["parameter"]=>
array(1) {
["$code"]=>
string(10) "<optional>"
}
}
44 changes: 22 additions & 22 deletions Zend/tests/exit/exit_values.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -80,15 +80,15 @@ const FILE_PATH = __DIR__ . '/exit_values.inc';
Using NULL as value:
Exit status is: 0
Output is:

Deprecated: exit(): Passing null to parameter #1 ($code) of type string|int is deprecated in %s on line %d
Using false as value:
Exit status is: 0
Output is:

Using true as value:
Exit status is: 0
Exit status is: 1
Output is:
1

Using 0 as value:
Exit status is: 0
Output is:
Expand All @@ -102,45 +102,45 @@ Exit status is: 20
Output is:

Using 10.0 as value:
Exit status is: 0
Exit status is: 10
Output is:
10

Using 15.5 as value:
Exit status is: 0
Exit status is: 15
Output is:
15.5
Deprecated: Implicit conversion from float 15.5 to int loses precision in %s on line %d
Using 'Hello world' as value:
Exit status is: 0
Output is:
Hello world
Using [] as value:
Exit status is: 0
Output is:
Warning: Array to string conversion in %s on line 3Array
TypeError: exit(): Argument #1 ($code) must be of type string|int, array given
Using STDERR as value:
Exit status is: 0
Output is:
Resource id #3
TypeError: exit(): Argument #1 ($code) must be of type string|int, resource given
Using new stdClass() as value:
Exit status is: 0
Output is:
Error: Object of class stdClass could not be converted to string
TypeError: exit(): Argument #1 ($code) must be of type string|int, stdClass given
As a statement:
Exit status is: 0
Output is:
Error: Object of class stdClass could not be converted to string
TypeError: exit(): Argument #1 ($code) must be of type string|int, stdClass given
Using NULL as value:
Exit status is: 0
Output is:

Deprecated: die(): Passing null to parameter #1 ($code) of type string|int is deprecated in %s on line %d
Using false as value:
Exit status is: 0
Output is:

Using true as value:
Exit status is: 0
Exit status is: 1
Output is:
1

Using 0 as value:
Exit status is: 0
Output is:
Expand All @@ -154,30 +154,30 @@ Exit status is: 20
Output is:

Using 10.0 as value:
Exit status is: 0
Exit status is: 10
Output is:
10

Using 15.5 as value:
Exit status is: 0
Exit status is: 15
Output is:
15.5
Deprecated: Implicit conversion from float 15.5 to int loses precision in %s on line %d
Using 'Hello world' as value:
Exit status is: 0
Output is:
Hello world
Using [] as value:
Exit status is: 0
Output is:
Warning: Array to string conversion in %s on line 3Array
TypeError: die(): Argument #1 ($code) must be of type string|int, array given
Using STDERR as value:
Exit status is: 0
Output is:
Resource id #3
TypeError: die(): Argument #1 ($code) must be of type string|int, resource given
Using new stdClass() as value:
Exit status is: 0
Output is:
Error: Object of class stdClass could not be converted to string
TypeError: die(): Argument #1 ($code) must be of type string|int, stdClass given
As a statement:
Exit status is: 0
Output is:
Error: Object of class stdClass could not be converted to string
TypeError: die(): Argument #1 ($code) must be of type string|int, stdClass given
7 changes: 7 additions & 0 deletions Zend/zend_API.c
Original file line number Diff line number Diff line change
Expand Up @@ -3541,6 +3541,13 @@ ZEND_API zend_result zend_set_hash_symbol(zval *symbol, const char *name, size_t

static void zend_disable_function(const char *function_name, size_t function_name_length)
{
if (UNEXPECTED(
(function_name_length == strlen("exit") && !memcmp(function_name, "exit", strlen("exit")))
|| (function_name_length == strlen("die") && !memcmp(function_name, "die", strlen("die")))
)) {
zend_error(E_WARNING, "Cannot disable function %s()", function_name);
return;
}
zend_hash_str_del(CG(function_table), function_name, function_name_length);
}

Expand Down
23 changes: 23 additions & 0 deletions Zend/zend_builtin_functions.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,29 @@ zend_result zend_startup_builtin_functions(void) /* {{{ */
}
/* }}} */

ZEND_FUNCTION(exit)
{
zend_string *str = NULL;
zend_long code = 0;

ZEND_PARSE_PARAMETERS_START(0, 1)
Z_PARAM_OPTIONAL
Z_PARAM_STR_OR_LONG(str, code)
ZEND_PARSE_PARAMETERS_END();

if (str) {
size_t len = ZSTR_LEN(str);
if (len != 0) {
zend_write(ZSTR_VAL(str), len);
}
} else {
EG(exit_status) = code;
}

ZEND_ASSERT(!EG(exception));
zend_throw_unwind_exit();
}

/* {{{ Get the version of the Zend Engine */
ZEND_FUNCTION(zend_version)
{
Expand Down

0 comments on commit 04c54f3

Please sign in to comment.