]> granicus.if.org Git - php/commitdiff
Handle partial arrays in zend_is_true() checks
authorNikita Popov <nikita.ppv@gmail.com>
Tue, 21 May 2019 14:51:35 +0000 (16:51 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Tue, 21 May 2019 14:53:34 +0000 (16:53 +0200)
ext/opcache/Optimizer/sccp.c
ext/opcache/tests/bug78015.phpt

index e6a905d1028bb68316a43acf1642e3fcadec0d62..81c629b5b4a66925c3c03907717caecb30855813 100644 (file)
@@ -385,6 +385,22 @@ static inline int ct_eval_binary_op(zval *result, zend_uchar binop, zval *op1, z
        return zend_optimizer_eval_binary_op(result, binop, op1, op2);
 }
 
+static inline int ct_eval_bool_cast(zval *result, zval *op) {
+       if (IS_PARTIAL_ARRAY(op)) {
+               if (zend_hash_num_elements(Z_ARRVAL_P(op)) == 0) {
+                       /* An empty partial array may be non-empty at runtime, we don't know whether the
+                        * result will be true or false. */
+                       return FAILURE;
+               }
+
+               ZVAL_TRUE(result);
+               return SUCCESS;
+       }
+
+       ZVAL_BOOL(result, zend_is_true(op));
+       return SUCCESS;
+}
+
 static inline int zval_to_string_offset(zend_long *result, zval *op) {
        switch (Z_TYPE_P(op)) {
                case IS_LONG:
@@ -446,6 +462,23 @@ static inline int ct_eval_fetch_dim(zval *result, zval *op1, zval *op2, int supp
        return FAILURE;
 }
 
+/* op1 may be NULL here to indicate an unset value */
+static inline int ct_eval_isset_isempty(zval *result, uint32_t extended_value, zval *op1) {
+       zval zv;
+       if (!(extended_value & ZEND_ISEMPTY)) {
+               ZVAL_BOOL(result, op1 && Z_TYPE_P(op1) != IS_NULL);
+               return SUCCESS;
+       } else if (!op1) {
+               ZVAL_TRUE(result);
+               return SUCCESS;
+       } else if (ct_eval_bool_cast(&zv, op1) == SUCCESS) {
+               ZVAL_BOOL(result, Z_TYPE(zv) == IS_FALSE);
+               return SUCCESS;
+       } else {
+               return FAILURE;
+       }
+}
+
 static inline int ct_eval_isset_dim(zval *result, uint32_t extended_value, zval *op1, zval *op2) {
        if (Z_TYPE_P(op1) == IS_ARRAY || IS_PARTIAL_ARRAY(op1)) {
                zval *value;
@@ -455,12 +488,7 @@ static inline int ct_eval_isset_dim(zval *result, uint32_t extended_value, zval
                if (IS_PARTIAL_ARRAY(op1) && (!value || IS_BOT(value))) {
                        return FAILURE;
                }
-               if (!(extended_value & ZEND_ISEMPTY)) {
-                       ZVAL_BOOL(result, value && Z_TYPE_P(value) != IS_NULL);
-               } else {
-                       ZVAL_BOOL(result, !value || !zend_is_true(value));
-               }
-               return SUCCESS;
+               return ct_eval_isset_isempty(result, extended_value, value);
        } else if (Z_TYPE_P(op1) == IS_STRING) {
                // TODO
                return FAILURE;
@@ -612,12 +640,7 @@ static inline int ct_eval_isset_obj(zval *result, uint32_t extended_value, zval
                if (!value || IS_BOT(value)) {
                        return FAILURE;
                }
-               if (!(extended_value & ZEND_ISEMPTY)) {
-                       ZVAL_BOOL(result, value && Z_TYPE_P(value) != IS_NULL);
-               } else {
-                       ZVAL_BOOL(result, !value || !zend_is_true(value));
-               }
-               return SUCCESS;
+               return ct_eval_isset_isempty(result, extended_value, value);
        } else {
                ZVAL_BOOL(result, (extended_value & ZEND_ISEMPTY));
                return SUCCESS;
@@ -677,15 +700,6 @@ static inline int ct_eval_incdec(zval *result, zend_uchar opcode, zval *op1) {
        return SUCCESS;
 }
 
-static inline int ct_eval_isset_isempty(zval *result, uint32_t extended_value, zval *op1) {
-       if (!(extended_value & ZEND_ISEMPTY)) {
-               ZVAL_BOOL(result, Z_TYPE_P(op1) != IS_NULL);
-       } else {
-               ZVAL_BOOL(result, !zend_is_true(op1));
-       }
-       return SUCCESS;
-}
-
 static inline void ct_eval_type_check(zval *result, uint32_t type_mask, zval *op1) {
        uint32_t type = Z_TYPE_P(op1);
        if (type == PARTIAL_ARRAY) {
@@ -1601,12 +1615,12 @@ 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);
+                       if (ct_eval_bool_cast(&zv, op1) == SUCCESS) {
+                               SET_RESULT(result, &zv);
+                               zval_ptr_dtor_nogc(&zv);
                                break;
                        }
-                       ZVAL_BOOL(&zv, zend_is_true(op1));
-                       SET_RESULT(result, &zv);
+                       SET_RESULT_BOT(result);
                        break;
                case ZEND_STRLEN:
                        SKIP_IF_TOP(op1);
@@ -1834,7 +1848,7 @@ static void sccp_mark_feasible_successors(
                int block_num, zend_basic_block *block,
                zend_op *opline, zend_ssa_op *ssa_op) {
        sccp_ctx *ctx = (sccp_ctx *) scdf;
-       zval *op1;
+       zval *op1, zv;
        int s;
 
        /* We can't determine the branch target at compile-time for these */
@@ -1869,13 +1883,27 @@ static void sccp_mark_feasible_successors(
                case ZEND_JMPZ:
                case ZEND_JMPZNZ:
                case ZEND_JMPZ_EX:
-                       s = zend_is_true(op1);
+               {
+                       if (ct_eval_bool_cast(&zv, op1) == FAILURE) {
+                               scdf_mark_edge_feasible(scdf, block_num, block->successors[0]);
+                               scdf_mark_edge_feasible(scdf, block_num, block->successors[1]);
+                               return;
+                       }
+                       s = Z_TYPE(zv) == IS_TRUE;
                        break;
+               }
                case ZEND_JMPNZ:
                case ZEND_JMPNZ_EX:
                case ZEND_JMP_SET:
-                       s = !zend_is_true(op1);
+               {
+                       if (ct_eval_bool_cast(&zv, op1) == FAILURE) {
+                               scdf_mark_edge_feasible(scdf, block_num, block->successors[0]);
+                               scdf_mark_edge_feasible(scdf, block_num, block->successors[1]);
+                               return;
+                       }
+                       s = Z_TYPE(zv) == IS_FALSE;
                        break;
+               }
                case ZEND_COALESCE:
                        s = (Z_TYPE_P(op1) == IS_NULL);
                        break;
index a71626aa221d700ff8663c9dcf3d4444418c1086..e93c9ce9e41859314df824f5baa392f3d6e3c13e 100644 (file)
@@ -63,7 +63,10 @@ array(1) {
 }
 bool(false)
 int(1)
-int(42)
+array(1) {
+  [0]=>
+  int(1)
+}
 bool(true)
 
 Notice: Array to string conversion in %s on line %d