Skip to content

Commit a9fd352

Browse files
committed
Zend: make exit/die a function instead of a language construct
1 parent 8983724 commit a9fd352

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1352
-1398
lines changed

Zend/Optimizer/block_pass.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -868,7 +868,6 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array
868868
break;
869869

870870
case ZEND_RETURN:
871-
case ZEND_EXIT:
872871
if (opline->op1_type == IS_TMP_VAR) {
873872
src = VAR_SOURCE(opline->op1);
874873
if (src && src->opcode == ZEND_QM_ASSIGN) {
@@ -1221,8 +1220,7 @@ static void zend_jmp_optimization(zend_basic_block *block, zend_op_array *op_arr
12211220
target = op_array->opcodes + target_block->start;
12221221
if ((target->opcode == ZEND_RETURN ||
12231222
target->opcode == ZEND_RETURN_BY_REF ||
1224-
target->opcode == ZEND_GENERATOR_RETURN ||
1225-
target->opcode == ZEND_EXIT) &&
1223+
target->opcode == ZEND_GENERATOR_RETURN) &&
12261224
!(op_array->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK)) {
12271225
/* JMP L, L: RETURN to immediate RETURN */
12281226
*last_op = *target;

Zend/Optimizer/pass1.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,6 @@ void zend_optimizer_pass1(zend_op_array *op_array, zend_optimizer_ctx *ctx)
331331
case ZEND_RETURN:
332332
case ZEND_RETURN_BY_REF:
333333
case ZEND_GENERATOR_RETURN:
334-
case ZEND_EXIT:
335334
case ZEND_THROW:
336335
case ZEND_MATCH_ERROR:
337336
case ZEND_CATCH:

Zend/Optimizer/pass3.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,7 @@ void zend_optimizer_pass3(zend_op_array *op_array, zend_optimizer_ctx *ctx)
8888
MAKE_NOP(opline);
8989
} else if ((target->opcode == ZEND_RETURN ||
9090
target->opcode == ZEND_RETURN_BY_REF ||
91-
target->opcode == ZEND_GENERATOR_RETURN ||
92-
target->opcode == ZEND_EXIT) &&
91+
target->opcode == ZEND_GENERATOR_RETURN) &&
9392
!(op_array->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK)) {
9493
/* JMP L, L: RETURN to immediate RETURN */
9594
*opline = *target;

Zend/Optimizer/zend_call_graph.c

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -161,10 +161,6 @@ ZEND_API void zend_analyze_calls(zend_arena **arena, zend_script *script, uint32
161161
call_info->send_unpack = 1;
162162
}
163163
break;
164-
case ZEND_EXIT:
165-
/* In this case the DO_CALL opcode may have been dropped
166-
* and caller_call_opline will be NULL. */
167-
break;
168164
}
169165
opline++;
170166
}

Zend/Optimizer/zend_cfg.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,6 @@ ZEND_API void zend_build_cfg(zend_arena **arena, const zend_op_array *op_array,
303303
}
304304
break;
305305
case ZEND_MATCH_ERROR:
306-
case ZEND_EXIT:
307306
case ZEND_THROW:
308307
/* Don't treat THROW as terminator if it's used in expression context,
309308
* as we may lose live ranges when eliminating unreachable code. */
@@ -507,7 +506,6 @@ ZEND_API void zend_build_cfg(zend_arena **arena, const zend_op_array *op_array,
507506
case ZEND_RETURN:
508507
case ZEND_RETURN_BY_REF:
509508
case ZEND_GENERATOR_RETURN:
510-
case ZEND_EXIT:
511509
case ZEND_THROW:
512510
case ZEND_MATCH_ERROR:
513511
case ZEND_VERIFY_NEVER_TYPE:

Zend/tests/arginfo_zpp_mismatch.inc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ function skipFunction($function): bool {
66
|| $function === 'readline'
77
|| $function === 'readline_read_history'
88
|| $function === 'readline_write_history'
9+
/* terminates script */
10+
|| $function === 'exit'
11+
|| $function === 'die'
912
/* intentionally violate invariants */
1013
|| $function === 'zend_create_unterminated_string'
1114
|| $function === 'zend_test_array_return'

Zend/tests/exit/define_die_constant.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,4 @@ var_dump(die);
99

1010
?>
1111
--EXPECTF--
12-
Parse error: syntax error, unexpected token "exit", expecting identifier in %s on line %d
12+
Fatal error: Cannot define constant with name die in %s on line %d

Zend/tests/exit/define_die_constant_namespace.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@ var_dump(die);
1111

1212
?>
1313
--EXPECTF--
14-
Parse error: syntax error, unexpected token "exit", expecting identifier in %s on line %d
14+
Fatal error: Cannot define constant with name die in %s on line %d

Zend/tests/exit/define_die_function.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@ function die() { }
77

88
?>
99
--EXPECTF--
10-
Parse error: syntax error, unexpected token "exit", expecting "(" in %s on line %d
10+
Fatal error: Defining a custom die() function is not allowed, as the function has special semantics in %s on line %d

Zend/tests/exit/define_die_function_namespace.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@ var_dump(die());
1111

1212
?>
1313
--EXPECTF--
14-
Parse error: syntax error, unexpected token "exit", expecting "(" in %s on line %d
14+
Fatal error: Defining a custom die() function is not allowed, as the function has special semantics in %s on line %d

Zend/tests/exit/define_exit_constant.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,4 @@ var_dump(exit);
99

1010
?>
1111
--EXPECTF--
12-
Parse error: syntax error, unexpected token "exit", expecting identifier in %s on line %d
12+
Fatal error: Cannot define constant with name exit in %s on line %d

Zend/tests/exit/define_exit_constant_namespace.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@ var_dump(exit);
1111

1212
?>
1313
--EXPECTF--
14-
Parse error: syntax error, unexpected token "exit", expecting identifier in %s on line %d
14+
Fatal error: Cannot define constant with name exit in %s on line %d

Zend/tests/exit/define_exit_function.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@ function exit() { }
77

88
?>
99
--EXPECTF--
10-
Parse error: syntax error, unexpected token "exit", expecting "(" in %s on line %d
10+
Fatal error: Defining a custom exit() function is not allowed, as the function has special semantics in %s on line %d

Zend/tests/exit/define_exit_function_namespace.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,4 @@ function exit() { }
99

1010
?>
1111
--EXPECTF--
12-
Parse error: syntax error, unexpected token "exit", expecting "(" in %s on line %d
12+
Fatal error: Defining a custom exit() function is not allowed, as the function has special semantics in %s on line %d

Zend/tests/exit/define_goto_label_die.phpt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,7 @@ die:
1010
echo "After\n";
1111

1212
?>
13-
--EXPECTF--
14-
Parse error: syntax error, unexpected token ":" in %s on line %d
13+
--EXPECT--
14+
Before
15+
In between
16+
After

Zend/tests/exit/define_goto_label_die_with_jump.phpt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@ die:
1010
echo "After\n";
1111

1212
?>
13-
--EXPECTF--
14-
Parse error: syntax error, unexpected token "exit", expecting identifier in %s on line %d
13+
--EXPECT--
14+
Before
15+
After

Zend/tests/exit/define_goto_label_exit.phpt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,7 @@ exit:
1010
echo "After\n";
1111

1212
?>
13-
--EXPECTF--
14-
Parse error: syntax error, unexpected token ":" in %s on line %d
13+
--EXPECT--
14+
Before
15+
In between
16+
After

Zend/tests/exit/define_goto_label_exit_with_jump.phpt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@ exit:
1010
echo "After\n";
1111

1212
?>
13-
--EXPECTF--
14-
Parse error: syntax error, unexpected token "exit", expecting identifier in %s on line %d
13+
--EXPECT--
14+
Before
15+
After

Zend/tests/exit/die_string_cast_exception.phpt

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@ Bug #79777: String cast exception during die should be handled gracefully
33
--FILE--
44
<?php
55

6-
die(new stdClass);
6+
try {
7+
die(new stdClass);
8+
} catch (TypeError $e) {
9+
echo $e->getMessage(), PHP_EOL;
10+
}
711

812
?>
9-
--EXPECTF--
10-
Fatal error: Uncaught Error: Object of class stdClass could not be converted to string in %s:%d
11-
Stack trace:
12-
#0 {main}
13-
thrown in %s on line %d
13+
--EXPECT--
14+
die(): Argument #1 ($code) must be of type string|int, stdClass given

Zend/tests/exit/disabling_die.phpt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ die();
99

1010
?>
1111
--EXPECT--
12+
Warning: Cannot disable function die() in Unknown on line 0

Zend/tests/exit/disabling_exit.phpt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ exit();
99

1010
?>
1111
--EXPECT--
12+
Warning: Cannot disable function exit() in Unknown on line 0

Zend/tests/exit/exit_as_function.phpt

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,24 @@ foreach ($values as $value) {
1919
}
2020

2121
?>
22-
--EXPECTF--
23-
Parse error: syntax error, unexpected token "...", expecting ")" in %s on line %d
22+
--EXPECT--
23+
string(4) "exit"
24+
string(3) "die"
25+
object(Closure)#1 (2) {
26+
["function"]=>
27+
string(4) "exit"
28+
["parameter"]=>
29+
array(1) {
30+
["$code"]=>
31+
string(10) "<optional>"
32+
}
33+
}
34+
object(Closure)#2 (2) {
35+
["function"]=>
36+
string(3) "die"
37+
["parameter"]=>
38+
array(1) {
39+
["$code"]=>
40+
string(10) "<optional>"
41+
}
42+
}

Zend/tests/exit/exit_values.phpt

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -80,15 +80,15 @@ const FILE_PATH = __DIR__ . '/exit_values.inc';
8080
Using NULL as value:
8181
Exit status is: 0
8282
Output is:
83-
83+
Deprecated: exit(): Passing null to parameter #1 ($code) of type string|int is deprecated in %s on line %d
8484
Using false as value:
8585
Exit status is: 0
8686
Output is:
8787

8888
Using true as value:
89-
Exit status is: 0
89+
Exit status is: 1
9090
Output is:
91-
1
91+
9292
Using 0 as value:
9393
Exit status is: 0
9494
Output is:
@@ -102,45 +102,45 @@ Exit status is: 20
102102
Output is:
103103

104104
Using 10.0 as value:
105-
Exit status is: 0
105+
Exit status is: 10
106106
Output is:
107-
10
107+
108108
Using 15.5 as value:
109-
Exit status is: 0
109+
Exit status is: 15
110110
Output is:
111-
15.5
111+
Deprecated: Implicit conversion from float 15.5 to int loses precision in %s on line %d
112112
Using 'Hello world' as value:
113113
Exit status is: 0
114114
Output is:
115115
Hello world
116116
Using [] as value:
117117
Exit status is: 0
118118
Output is:
119-
Warning: Array to string conversion in %s on line 3Array
119+
TypeError: exit(): Argument #1 ($code) must be of type string|int, array given
120120
Using STDERR as value:
121121
Exit status is: 0
122122
Output is:
123-
Resource id #3
123+
TypeError: exit(): Argument #1 ($code) must be of type string|int, resource given
124124
Using new stdClass() as value:
125125
Exit status is: 0
126126
Output is:
127-
Error: Object of class stdClass could not be converted to string
127+
TypeError: exit(): Argument #1 ($code) must be of type string|int, stdClass given
128128
As a statement:
129129
Exit status is: 0
130130
Output is:
131-
Error: Object of class stdClass could not be converted to string
131+
TypeError: exit(): Argument #1 ($code) must be of type string|int, stdClass given
132132
Using NULL as value:
133133
Exit status is: 0
134134
Output is:
135-
135+
Deprecated: die(): Passing null to parameter #1 ($code) of type string|int is deprecated in %s on line %d
136136
Using false as value:
137137
Exit status is: 0
138138
Output is:
139139

140140
Using true as value:
141-
Exit status is: 0
141+
Exit status is: 1
142142
Output is:
143-
1
143+
144144
Using 0 as value:
145145
Exit status is: 0
146146
Output is:
@@ -154,30 +154,30 @@ Exit status is: 20
154154
Output is:
155155

156156
Using 10.0 as value:
157-
Exit status is: 0
157+
Exit status is: 10
158158
Output is:
159-
10
159+
160160
Using 15.5 as value:
161-
Exit status is: 0
161+
Exit status is: 15
162162
Output is:
163-
15.5
163+
Deprecated: Implicit conversion from float 15.5 to int loses precision in %s on line %d
164164
Using 'Hello world' as value:
165165
Exit status is: 0
166166
Output is:
167167
Hello world
168168
Using [] as value:
169169
Exit status is: 0
170170
Output is:
171-
Warning: Array to string conversion in %s on line 3Array
171+
TypeError: die(): Argument #1 ($code) must be of type string|int, array given
172172
Using STDERR as value:
173173
Exit status is: 0
174174
Output is:
175-
Resource id #3
175+
TypeError: die(): Argument #1 ($code) must be of type string|int, resource given
176176
Using new stdClass() as value:
177177
Exit status is: 0
178178
Output is:
179-
Error: Object of class stdClass could not be converted to string
179+
TypeError: die(): Argument #1 ($code) must be of type string|int, stdClass given
180180
As a statement:
181181
Exit status is: 0
182182
Output is:
183-
Error: Object of class stdClass could not be converted to string
183+
TypeError: die(): Argument #1 ($code) must be of type string|int, stdClass given

Zend/zend_API.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3541,6 +3541,13 @@ ZEND_API zend_result zend_set_hash_symbol(zval *symbol, const char *name, size_t
35413541

35423542
static void zend_disable_function(const char *function_name, size_t function_name_length)
35433543
{
3544+
if (UNEXPECTED(
3545+
(function_name_length == strlen("exit") && !memcmp(function_name, "exit", strlen("exit")))
3546+
|| (function_name_length == strlen("die") && !memcmp(function_name, "die", strlen("die")))
3547+
)) {
3548+
zend_error(E_WARNING, "Cannot disable function %s()", function_name);
3549+
return;
3550+
}
35443551
zend_hash_str_del(CG(function_table), function_name, function_name_length);
35453552
}
35463553

Zend/zend_builtin_functions.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,29 @@ zend_result zend_startup_builtin_functions(void) /* {{{ */
6969
}
7070
/* }}} */
7171

72+
ZEND_FUNCTION(exit)
73+
{
74+
zend_string *str = NULL;
75+
zend_long code = 0;
76+
77+
ZEND_PARSE_PARAMETERS_START(0, 1)
78+
Z_PARAM_OPTIONAL
79+
Z_PARAM_STR_OR_LONG(str, code)
80+
ZEND_PARSE_PARAMETERS_END();
81+
82+
if (str) {
83+
size_t len = ZSTR_LEN(str);
84+
if (len != 0) {
85+
zend_write(ZSTR_VAL(str), len);
86+
}
87+
} else {
88+
EG(exit_status) = code;
89+
}
90+
91+
ZEND_ASSERT(!EG(exception));
92+
zend_throw_unwind_exit();
93+
}
94+
7295
/* {{{ Get the version of the Zend Engine */
7396
ZEND_FUNCTION(zend_version)
7497
{

Zend/zend_builtin_functions.stub.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ class stdClass
77
{
88
}
99

10+
function exit(string|int $code = 0): never {}
11+
12+
/** @alias exit */
13+
function die(string|int $code = 0): never {}
14+
1015
/** @refcount 1 */
1116
function zend_version(): string {}
1217

0 commit comments

Comments
 (0)