]> granicus.if.org Git - php/commitdiff
Unify checks for binary operator errors for ct eval
authorNikita Popov <nikita.ppv@gmail.com>
Wed, 1 Apr 2020 11:02:58 +0000 (13:02 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Wed, 1 Apr 2020 12:42:58 +0000 (14:42 +0200)
Move everything into one function and share it with opcache.
This fixes some discrepancies.

Zend/tests/constant_expressions_exceptions_001.phpt
Zend/tests/runtime_compile_time_binary_operands.phpt
Zend/zend_compile.c
Zend/zend_compile.h
ext/opcache/Optimizer/zend_optimizer.c

index 6a111d3aeddde0630acdba53695bebba88a6f81f..98e61765b36500c5e7ec72b4e2e744196e75a6eb 100644 (file)
@@ -3,8 +3,8 @@ Constant Expressions with unsupported operands 001
 --FILE--
 <?php
 const T = array(1,2) - array(0);
---EXPECT--
-Fatal error: Uncaught TypeError: Unsupported operand types: array - array in [no active file]:0
+--EXPECTF--
+Fatal error: Uncaught TypeError: Unsupported operand types: array - array in %s:%d
 Stack trace:
 #0 {main}
-  thrown in [no active file] on line 0
+  thrown in %s on line %d
index 1a1409c2bbebb7c2db93cead9a278d4797183ffd..8c15a9658fd10794cf0d0b044a0cbc0d08544aad 100644 (file)
@@ -153,8 +153,5 @@ if($c === 0) {
 $fl = __DIR__ . DIRECTORY_SEPARATOR . 'compare_binary_operands_temp.php';
 @unlink($fl);
 ?>
---EXPECTF--
-Fatal error: Uncaught TypeError: Unsupported operand types: int + array in %s:%d
-Stack trace:
-#0 {main}
-  thrown in %s on line %d
+--EXPECT--
+Failed: 0
index ff466c5ef5740117ded6db8d234a064fc119d3a7..914f991bac400405aab2aa754cd6584c7eb877a5 100644 (file)
@@ -7216,14 +7216,32 @@ static zend_bool zend_try_ct_eval_magic_const(zval *zv, zend_ast *ast) /* {{{ */
 }
 /* }}} */
 
-ZEND_API zend_bool zend_binary_op_produces_numeric_string_error(uint32_t opcode, zval *op1, zval *op2) /* {{{ */
+ZEND_API zend_bool zend_binary_op_produces_error(uint32_t opcode, zval *op1, zval *op2) /* {{{ */
 {
+       if ((opcode == ZEND_CONCAT || opcode == ZEND_FAST_CONCAT)) {
+               /* Array to string warning. */
+               return Z_TYPE_P(op1) == IS_ARRAY || Z_TYPE_P(op2) == IS_ARRAY;
+       }
+
        if (!(opcode == ZEND_ADD || opcode == ZEND_SUB || opcode == ZEND_MUL || opcode == ZEND_DIV
-               || opcode == ZEND_POW || opcode == ZEND_MOD || opcode == ZEND_SL || opcode == ZEND_SR
-               || opcode == ZEND_BW_OR || opcode == ZEND_BW_AND || opcode == ZEND_BW_XOR)) {
+               || opcode == ZEND_POW || opcode == ZEND_MOD || opcode == ZEND_SL || opcode == ZEND_SR
+               || opcode == ZEND_BW_OR || opcode == ZEND_BW_AND || opcode == ZEND_BW_XOR)) {
+               /* Only the numeric operations throw errors. */
                return 0;
        }
 
+       if (Z_TYPE_P(op1) == IS_ARRAY || Z_TYPE_P(op2) == IS_ARRAY) {
+               if (opcode == ZEND_ADD && Z_TYPE_P(op1) == IS_ARRAY && Z_TYPE_P(op2) == IS_ARRAY) {
+                       /* Adding two arrays is allowed. */
+                       return 0;
+               }
+               if (opcode == ZEND_ADD || opcode == ZEND_SUB || opcode == ZEND_MUL || opcode == ZEND_POW
+                               || opcode == ZEND_DIV) {
+                       /* These operators throw when one of the operands is an array. */
+                       return 1;
+               }
+       }
+
        /* While basic arithmetic operators always produce numeric string errors,
         * bitwise operators don't produce errors if both operands are strings */
        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,
                return 1;
        }
 
-       return 0;
-}
-/* }}} */
-
-ZEND_API zend_bool zend_binary_op_produces_array_conversion_error(uint32_t opcode, zval *op1, zval *op2) /* {{{ */
-{
-       if (opcode == ZEND_CONCAT && (Z_TYPE_P(op1) == IS_ARRAY || Z_TYPE_P(op2) == IS_ARRAY)) {
+       if ((opcode == ZEND_DIV || opcode == ZEND_MOD) && zval_get_long(op2) == 0) {
+               /* Division by zero throws an error. */
+               return 1;
+       }
+       if ((opcode == ZEND_SL || opcode == ZEND_SR) && zval_get_long(op2) < 0) {
+               /* Shift by negative number throws an error. */
                return 1;
        }
 
@@ -7257,26 +7274,11 @@ ZEND_API zend_bool zend_binary_op_produces_array_conversion_error(uint32_t opcod
 
 static inline zend_bool zend_try_ct_eval_binary_op(zval *result, uint32_t opcode, zval *op1, zval *op2) /* {{{ */
 {
-       binary_op_type fn = get_binary_op(opcode);
-
-       /* don't evaluate division by zero at compile-time */
-       if ((opcode == ZEND_DIV || opcode == ZEND_MOD) &&
-           zval_get_long(op2) == 0) {
-               return 0;
-       } else if ((opcode == ZEND_SL || opcode == ZEND_SR) &&
-           zval_get_long(op2) < 0) {
-               return 0;
-       }
-
-       /* don't evaluate numeric string error-producing operations at compile-time */
-       if (zend_binary_op_produces_numeric_string_error(opcode, op1, op2)) {
-               return 0;
-       }
-       /* don't evaluate array to string conversions at compile-time */
-       if (zend_binary_op_produces_array_conversion_error(opcode, op1, op2)) {
+       if (zend_binary_op_produces_error(opcode, op1, op2)) {
                return 0;
        }
 
+       binary_op_type fn = get_binary_op(opcode);
        fn(result, op1, op2);
        return 1;
 }
index 8a64ed86c3d03fe57a43f7c1b23d4955837f4f54..d6ddb0760f2a96b447f7f8561c51ba863add676e 100644 (file)
@@ -1094,6 +1094,6 @@ END_EXTERN_C()
 /* The default value for CG(compiler_options) during eval() */
 #define ZEND_COMPILE_DEFAULT_FOR_EVAL                  0
 
-ZEND_API zend_bool zend_binary_op_produces_numeric_string_error(uint32_t opcode, zval *op1, zval *op2);
+ZEND_API zend_bool zend_binary_op_produces_error(uint32_t opcode, zval *op1, zval *op2);
 
 #endif /* ZEND_COMPILE_H */
index 678d435a9a7b9fa78ae8bad45d1988ceda840bec..facb238c21cb210f2b3486af3e1af22c09a5de39 100644 (file)
@@ -54,47 +54,10 @@ int zend_optimizer_eval_binary_op(zval *result, zend_uchar opcode, zval *op1, zv
        binary_op_type binary_op = get_binary_op(opcode);
        int er, ret;
 
-       if (zend_binary_op_produces_numeric_string_error(opcode, op1, op2)) {
-               /* produces numeric string E_NOTICE/E_WARNING */
+       if (zend_binary_op_produces_error(opcode, op1, op2)) {
                return FAILURE;
        }
 
-       switch (opcode) {
-               case ZEND_ADD:
-                       if ((Z_TYPE_P(op1) == IS_ARRAY
-                         || Z_TYPE_P(op2) == IS_ARRAY)
-                        && Z_TYPE_P(op1) != Z_TYPE_P(op2)) {
-                               /* produces "Unsupported operand types" exception */
-                               return FAILURE;
-                       }
-                       break;
-               case ZEND_DIV:
-               case ZEND_MOD:
-                       if (zval_get_long(op2) == 0) {
-                               /* division by 0 */
-                               return FAILURE;
-                       }
-                       /* break missing intentionally */
-               case ZEND_SUB:
-               case ZEND_MUL:
-               case ZEND_POW:
-               case ZEND_CONCAT:
-               case ZEND_FAST_CONCAT:
-                       if (Z_TYPE_P(op1) == IS_ARRAY
-                        || Z_TYPE_P(op2) == IS_ARRAY) {
-                               /* produces "Unsupported operand types" exception */
-                               return FAILURE;
-                       }
-                       break;
-               case ZEND_SL:
-               case ZEND_SR:
-                       if (zval_get_long(op2) < 0) {
-                               /* shift by negative number */
-                               return FAILURE;
-                       }
-                       break;
-       }
-
        er = EG(error_reporting);
        EG(error_reporting) = 0;
        ret = binary_op(result, op1, op2);