]> granicus.if.org Git - php/commitdiff
Fixed bug #78015
authorNikita Popov <nikita.ppv@gmail.com>
Wed, 15 May 2019 12:35:31 +0000 (14:35 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Wed, 15 May 2019 12:35:31 +0000 (14:35 +0200)
Don't try to evaluate various operations with partial array operands.
We could evaluate some of these, but let's be conservative for now...

NEWS
ext/opcache/Optimizer/sccp.c
ext/opcache/tests/bug78015.phpt [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index 958efbc4011ea2289778f344e1ded9cc9534af80..d690c86354b93de8816c24bec2b70685149a7769 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -6,6 +6,10 @@ PHP                                                                        NEWS
   . Fixed bug #76980 (Interface gets skipped if autoloader throws an exception).
     (Nikita)
 
+- Opcache:
+  . Fixed bug #78015 (Incorrect evaluation of expressions involving partials
+    arrays in SCCP). (Nikita)
+
 16 May 2019, PHP 7.3.6RC1
 
 - cURL:
index 9ebaed9c83fd1fc6cc030b5e8be0fe8e2d3108f3..bbe5550f2597631cc52d30701d6e459ec6e5a6c4 100644 (file)
@@ -660,7 +660,13 @@ static inline int ct_eval_isset_isempty(zval *result, uint32_t extended_value, z
 }
 
 static inline void ct_eval_type_check(zval *result, uint32_t type_mask, zval *op1) {
-       ZVAL_BOOL(result, (type_mask >> Z_TYPE_P(op1)) & 1);
+       uint32_t type = Z_TYPE_P(op1);
+       if (type == PARTIAL_ARRAY) {
+               type = IS_ARRAY;
+       } else if (type == PARTIAL_OBJECT) {
+               type = IS_OBJECT;
+       }
+       ZVAL_BOOL(result, (type_mask >> type) & 1);
 }
 
 static inline int ct_eval_in_array(zval *result, uint32_t extended_value, zval *op1, zval *op2) {
@@ -1359,6 +1365,12 @@ static void sccp_visit_instr(scdf_ctx *scdf, zend_op *opline, zend_ssa_op *ssa_o
                        SKIP_IF_TOP(op1);
                        SKIP_IF_TOP(op2);
 
+                       /* TODO: We could implement support for evaluation of + on partial arrays. */
+                       if (IS_PARTIAL_ARRAY(op1) || IS_PARTIAL_ARRAY(op2)) {
+                               SET_RESULT_BOT(result);
+                               break;
+                       }
+
                        if (zend_optimizer_eval_binary_op(&zv, opline->opcode, op1, op2) == SUCCESS) {
                                SET_RESULT(result, &zv);
                                zval_ptr_dtor_nogc(&zv);
@@ -1540,6 +1552,10 @@ static void sccp_visit_instr(scdf_ctx *scdf, zend_op *opline, zend_ssa_op *ssa_o
                case ZEND_BW_NOT:
                case ZEND_BOOL_NOT:
                        SKIP_IF_TOP(op1);
+                       if (IS_PARTIAL_ARRAY(op1)) {
+                               SET_RESULT_BOT(result);
+                               break;
+                       }
                        if (zend_optimizer_eval_unary_op(&zv, opline->opcode, op1) == SUCCESS) {
                                SET_RESULT(result, &zv);
                                zval_ptr_dtor_nogc(&zv);
@@ -1549,6 +1565,10 @@ static void sccp_visit_instr(scdf_ctx *scdf, zend_op *opline, zend_ssa_op *ssa_o
                        break;
                case ZEND_CAST:
                        SKIP_IF_TOP(op1);
+                       if (IS_PARTIAL_ARRAY(op1)) {
+                               SET_RESULT_BOT(result);
+                               break;
+                       }
                        if (zend_optimizer_eval_cast(&zv, opline->extended_value, op1) == SUCCESS) {
                                SET_RESULT(result, &zv);
                                zval_ptr_dtor_nogc(&zv);
@@ -1560,6 +1580,10 @@ static void sccp_visit_instr(scdf_ctx *scdf, zend_op *opline, zend_ssa_op *ssa_o
                case ZEND_JMPZ_EX:
                case ZEND_JMPNZ_EX:
                        SKIP_IF_TOP(op1);
+                       if (IS_PARTIAL_ARRAY(op1)) {
+                               SET_RESULT_BOT(result);
+                               break;
+                       }
                        ZVAL_BOOL(&zv, zend_is_true(op1));
                        SET_RESULT(result, &zv);
                        break;
@@ -1679,6 +1703,10 @@ static void sccp_visit_instr(scdf_ctx *scdf, zend_op *opline, zend_ssa_op *ssa_o
                        break;
                case ZEND_ROPE_INIT:
                        SKIP_IF_TOP(op2);
+                       if (IS_PARTIAL_ARRAY(op2)) {
+                               SET_RESULT_BOT(result);
+                               break;
+                       }
                        if (zend_optimizer_eval_cast(&zv, IS_STRING, op2) == SUCCESS) {
                                SET_RESULT(result, &zv);
                                zval_ptr_dtor_nogc(&zv);
@@ -1693,6 +1721,10 @@ static void sccp_visit_instr(scdf_ctx *scdf, zend_op *opline, zend_ssa_op *ssa_o
                        // string for all SSA vars with some extra checks
                        SKIP_IF_TOP(op1);
                        SKIP_IF_TOP(op2);
+                       if (IS_PARTIAL_ARRAY(op2)) {
+                               SET_RESULT_BOT(result);
+                               break;
+                       }
                        if (zend_optimizer_eval_binary_op(&zv, ZEND_CONCAT, op1, op2) == SUCCESS) {
                                SET_RESULT(result, &zv);
                                zval_ptr_dtor_nogc(&zv);
diff --git a/ext/opcache/tests/bug78015.phpt b/ext/opcache/tests/bug78015.phpt
new file mode 100644 (file)
index 0000000..a71626a
--- /dev/null
@@ -0,0 +1,70 @@
+--TEST--
+Bug #78015: Incorrect evaluation of expressions involving partials array in SCCP
+--FILE--
+<?php
+
+$x = 1;
+
+function test1() {
+    global $x;
+    $a = ['b' => [$x], 'c' => [$x]];
+    $d = $a['b'] + $a['c'];
+    return $d;
+}
+
+function test2() {
+    global $x;
+    $a = ['b' => [$x]];
+    $d = !$a['b'];
+    return $d;
+}
+
+function test3() {
+    global $x;
+    $a = ['b' => [$x]];
+    $d = (int) $a['b'];
+    return $d;
+}
+
+function test4() {
+    global $x;
+    $a = ['b' => [$x]];
+    $d = $a['b'] ?: 42;
+    return $d;
+}
+
+function test5() {
+    global $x;
+    $a = ['b' => [$x]];
+    $d = is_array($a['b']);
+    return $d;
+}
+
+function test6() {
+    global $x;
+    $a = ['b' => [$x]];
+    $b = "foo";
+    $d = "$a[b]{$b}bar";
+    return $d;
+}
+
+var_dump(test1());
+var_dump(test2());
+var_dump(test3());
+var_dump(test4());
+var_dump(test5());
+var_dump(test6());
+
+?>
+--EXPECTF--
+array(1) {
+  [0]=>
+  int(1)
+}
+bool(false)
+int(1)
+int(42)
+bool(true)
+
+Notice: Array to string conversion in %s on line %d
+string(11) "Arrayfoobar"