Skip to content

Commit 1ed132e

Browse files
committed
Unify checks for binary operator errors for ct eval
Move everything into one function and share it with opcache. This fixes some discrepancies.
1 parent 56b18d4 commit 1ed132e

File tree

5 files changed

+36
-74
lines changed

5 files changed

+36
-74
lines changed

Zend/tests/constant_expressions_exceptions_001.phpt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ Constant Expressions with unsupported operands 001
33
--FILE--
44
<?php
55
const T = array(1,2) - array(0);
6-
--EXPECT--
7-
Fatal error: Uncaught TypeError: Unsupported operand types: array - array in [no active file]:0
6+
--EXPECTF--
7+
Fatal error: Uncaught TypeError: Unsupported operand types: array - array in %s:%d
88
Stack trace:
99
#0 {main}
10-
thrown in [no active file] on line 0
10+
thrown in %s on line %d

Zend/tests/runtime_compile_time_binary_operands.phpt

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,5 @@ if($c === 0) {
153153
$fl = __DIR__ . DIRECTORY_SEPARATOR . 'compare_binary_operands_temp.php';
154154
@unlink($fl);
155155
?>
156-
--EXPECTF--
157-
Fatal error: Uncaught TypeError: Unsupported operand types: int + array in %s:%d
158-
Stack trace:
159-
#0 {main}
160-
thrown in %s on line %d
156+
--EXPECT--
157+
Failed: 0

Zend/zend_compile.c

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -7216,14 +7216,32 @@ static zend_bool zend_try_ct_eval_magic_const(zval *zv, zend_ast *ast) /* {{{ */
72167216
}
72177217
/* }}} */
72187218

7219-
ZEND_API zend_bool zend_binary_op_produces_numeric_string_error(uint32_t opcode, zval *op1, zval *op2) /* {{{ */
7219+
ZEND_API zend_bool zend_binary_op_produces_error(uint32_t opcode, zval *op1, zval *op2) /* {{{ */
72207220
{
7221+
if ((opcode == ZEND_CONCAT || opcode == ZEND_FAST_CONCAT)) {
7222+
/* Array to string warning. */
7223+
return Z_TYPE_P(op1) == IS_ARRAY || Z_TYPE_P(op2) == IS_ARRAY;
7224+
}
7225+
72217226
if (!(opcode == ZEND_ADD || opcode == ZEND_SUB || opcode == ZEND_MUL || opcode == ZEND_DIV
7222-
|| opcode == ZEND_POW || opcode == ZEND_MOD || opcode == ZEND_SL || opcode == ZEND_SR
7223-
|| opcode == ZEND_BW_OR || opcode == ZEND_BW_AND || opcode == ZEND_BW_XOR)) {
7227+
|| opcode == ZEND_POW || opcode == ZEND_MOD || opcode == ZEND_SL || opcode == ZEND_SR
7228+
|| opcode == ZEND_BW_OR || opcode == ZEND_BW_AND || opcode == ZEND_BW_XOR)) {
7229+
/* Only the numeric operations throw errors. */
72247230
return 0;
72257231
}
72267232

7233+
if (Z_TYPE_P(op1) == IS_ARRAY || Z_TYPE_P(op2) == IS_ARRAY) {
7234+
if (opcode == ZEND_ADD && Z_TYPE_P(op1) == IS_ARRAY && Z_TYPE_P(op2) == IS_ARRAY) {
7235+
/* Adding two arrays is allowed. */
7236+
return 0;
7237+
}
7238+
if (opcode == ZEND_ADD || opcode == ZEND_SUB || opcode == ZEND_MUL || opcode == ZEND_POW
7239+
|| opcode == ZEND_DIV) {
7240+
/* These operators throw when one of the operands is an array. */
7241+
return 1;
7242+
}
7243+
}
7244+
72277245
/* While basic arithmetic operators always produce numeric string errors,
72287246
* bitwise operators don't produce errors if both operands are strings */
72297247
if ((opcode == ZEND_BW_OR || opcode == ZEND_BW_AND || opcode == ZEND_BW_XOR)
@@ -7241,13 +7259,12 @@ ZEND_API zend_bool zend_binary_op_produces_numeric_string_error(uint32_t opcode,
72417259
return 1;
72427260
}
72437261

7244-
return 0;
7245-
}
7246-
/* }}} */
7247-
7248-
ZEND_API zend_bool zend_binary_op_produces_array_conversion_error(uint32_t opcode, zval *op1, zval *op2) /* {{{ */
7249-
{
7250-
if (opcode == ZEND_CONCAT && (Z_TYPE_P(op1) == IS_ARRAY || Z_TYPE_P(op2) == IS_ARRAY)) {
7262+
if ((opcode == ZEND_DIV || opcode == ZEND_MOD) && zval_get_long(op2) == 0) {
7263+
/* Division by zero throws an error. */
7264+
return 1;
7265+
}
7266+
if ((opcode == ZEND_SL || opcode == ZEND_SR) && zval_get_long(op2) < 0) {
7267+
/* Shift by negative number throws an error. */
72517268
return 1;
72527269
}
72537270

@@ -7257,26 +7274,11 @@ ZEND_API zend_bool zend_binary_op_produces_array_conversion_error(uint32_t opcod
72577274

72587275
static inline zend_bool zend_try_ct_eval_binary_op(zval *result, uint32_t opcode, zval *op1, zval *op2) /* {{{ */
72597276
{
7260-
binary_op_type fn = get_binary_op(opcode);
7261-
7262-
/* don't evaluate division by zero at compile-time */
7263-
if ((opcode == ZEND_DIV || opcode == ZEND_MOD) &&
7264-
zval_get_long(op2) == 0) {
7265-
return 0;
7266-
} else if ((opcode == ZEND_SL || opcode == ZEND_SR) &&
7267-
zval_get_long(op2) < 0) {
7268-
return 0;
7269-
}
7270-
7271-
/* don't evaluate numeric string error-producing operations at compile-time */
7272-
if (zend_binary_op_produces_numeric_string_error(opcode, op1, op2)) {
7273-
return 0;
7274-
}
7275-
/* don't evaluate array to string conversions at compile-time */
7276-
if (zend_binary_op_produces_array_conversion_error(opcode, op1, op2)) {
7277+
if (zend_binary_op_produces_error(opcode, op1, op2)) {
72777278
return 0;
72787279
}
72797280

7281+
binary_op_type fn = get_binary_op(opcode);
72807282
fn(result, op1, op2);
72817283
return 1;
72827284
}

Zend/zend_compile.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1094,6 +1094,6 @@ END_EXTERN_C()
10941094
/* The default value for CG(compiler_options) during eval() */
10951095
#define ZEND_COMPILE_DEFAULT_FOR_EVAL 0
10961096

1097-
ZEND_API zend_bool zend_binary_op_produces_numeric_string_error(uint32_t opcode, zval *op1, zval *op2);
1097+
ZEND_API zend_bool zend_binary_op_produces_error(uint32_t opcode, zval *op1, zval *op2);
10981098

10991099
#endif /* ZEND_COMPILE_H */

ext/opcache/Optimizer/zend_optimizer.c

Lines changed: 1 addition & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -54,47 +54,10 @@ int zend_optimizer_eval_binary_op(zval *result, zend_uchar opcode, zval *op1, zv
5454
binary_op_type binary_op = get_binary_op(opcode);
5555
int er, ret;
5656

57-
if (zend_binary_op_produces_numeric_string_error(opcode, op1, op2)) {
58-
/* produces numeric string E_NOTICE/E_WARNING */
57+
if (zend_binary_op_produces_error(opcode, op1, op2)) {
5958
return FAILURE;
6059
}
6160

62-
switch (opcode) {
63-
case ZEND_ADD:
64-
if ((Z_TYPE_P(op1) == IS_ARRAY
65-
|| Z_TYPE_P(op2) == IS_ARRAY)
66-
&& Z_TYPE_P(op1) != Z_TYPE_P(op2)) {
67-
/* produces "Unsupported operand types" exception */
68-
return FAILURE;
69-
}
70-
break;
71-
case ZEND_DIV:
72-
case ZEND_MOD:
73-
if (zval_get_long(op2) == 0) {
74-
/* division by 0 */
75-
return FAILURE;
76-
}
77-
/* break missing intentionally */
78-
case ZEND_SUB:
79-
case ZEND_MUL:
80-
case ZEND_POW:
81-
case ZEND_CONCAT:
82-
case ZEND_FAST_CONCAT:
83-
if (Z_TYPE_P(op1) == IS_ARRAY
84-
|| Z_TYPE_P(op2) == IS_ARRAY) {
85-
/* produces "Unsupported operand types" exception */
86-
return FAILURE;
87-
}
88-
break;
89-
case ZEND_SL:
90-
case ZEND_SR:
91-
if (zval_get_long(op2) < 0) {
92-
/* shift by negative number */
93-
return FAILURE;
94-
}
95-
break;
96-
}
97-
9861
er = EG(error_reporting);
9962
EG(error_reporting) = 0;
10063
ret = binary_op(result, op1, op2);

0 commit comments

Comments
 (0)