]> granicus.if.org Git - php/commitdiff
Constant evaluation of in_array() (support for more cases).
authorDmitry Stogov <dmitry@zend.com>
Mon, 17 Jul 2017 14:27:21 +0000 (17:27 +0300)
committerDmitry Stogov <dmitry@zend.com>
Mon, 17 Jul 2017 14:27:21 +0000 (17:27 +0300)
ext/opcache/Optimizer/dce.c
ext/opcache/Optimizer/sccp.c

index e3b42851974c9f6446fecfb0b11a7e739b0fa04a..cf75f0ad4ae5a86ea2fbcfcb31228bffa334c93b 100644 (file)
@@ -119,6 +119,7 @@ static inline zend_bool may_have_side_effects(
                case ZEND_ISSET_ISEMPTY_CV:
                case ZEND_ISSET_ISEMPTY_VAR:
                case ZEND_FETCH_IS:
+               case ZEND_IN_ARRAY:
                        /* No side effects */
                        return 0;
                case ZEND_JMP:
index 06a4406fe8c5733c08920e6b8e50006572df1ad4..86111e30a0a0e1b531996d41dceefadaac08939d 100644 (file)
@@ -455,6 +455,42 @@ static inline void ct_eval_type_check(zval *result, uint32_t type, zval *op1) {
        }
 }
 
+static inline int ct_eval_in_array(zval *result, uint32_t extended_value, zval *op1, zval *op2) {
+       HashTable *ht;
+       zend_bool res;
+
+       if (Z_TYPE_P(op2) != IS_ARRAY) {
+               return FAILURE;
+       }
+       ht = Z_ARRVAL_P(op2);
+       if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) {
+               res = zend_hash_exists(ht, Z_STR_P(op1));
+       } else if (extended_value) {
+               if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) {
+                       res = zend_hash_index_exists(ht, Z_LVAL_P(op1));
+               } else {
+                       res = 0;
+               }
+       } else if (Z_TYPE_P(op1) <= IS_FALSE) {
+               res = zend_hash_exists(ht, ZSTR_EMPTY_ALLOC());
+       } else {
+               zend_string *key;
+               zval tmp;
+
+               res = 0;
+               ZEND_HASH_FOREACH_STR_KEY(ht, key) {
+                       ZVAL_STR(&tmp, key);
+                       compare_function(&tmp, op1, &tmp);
+                       if (Z_LVAL(tmp) == 0) {
+                               res = 1;
+                               break;
+                       }
+               } ZEND_HASH_FOREACH_END();
+       }
+       ZVAL_BOOL(result, res);
+       return SUCCESS;
+}
+
 /* The functions chosen here are simple to implement and either likely to affect a branch,
  * or just happened to be commonly used with constant operands in WP (need to test other
  * applications as well, of course). */
@@ -500,7 +536,11 @@ static inline int ct_eval_func_call(
                }
                return SUCCESS;
        } else if (zend_string_equals_literal(name, "in_array")) {
-               if (num_args != 2 || Z_TYPE_P(args[1]) != IS_ARRAY) {
+               if ((num_args != 2
+                                       && (num_args != 3
+                                               || (Z_TYPE_P(args[2]) != IS_FALSE
+                                                       && Z_TYPE_P(args[2]) != IS_TRUE)))
+                               || Z_TYPE_P(args[1]) != IS_ARRAY) {
                        return FAILURE;
                }
                /* pass */
@@ -837,6 +877,16 @@ static void sccp_visit_instr(scdf_ctx *scdf, zend_op *opline, zend_ssa_op *ssa_o
                        }
                        SET_RESULT_BOT(result);
                        break;
+               case ZEND_IN_ARRAY:
+                       SKIP_IF_TOP(op1);
+                       SKIP_IF_TOP(op2);
+                       if (ct_eval_in_array(&zv, opline->extended_value, op1, op2) == SUCCESS) {
+                               SET_RESULT(result, &zv);
+                               zval_ptr_dtor_nogc(&zv);
+                               break;
+                       }
+                       SET_RESULT_BOT(result);
+                       break;
                case ZEND_FETCH_DIM_R:
                case ZEND_FETCH_DIM_IS:
                case ZEND_FETCH_LIST: