]> granicus.if.org Git - php/commitdiff
Fixed bug #66176 (Invalid constant substitution)
authorDmitry Stogov <dmitry@zend.com>
Tue, 26 Nov 2013 13:47:02 +0000 (17:47 +0400)
committerDmitry Stogov <dmitry@zend.com>
Tue, 26 Nov 2013 13:47:02 +0000 (17:47 +0400)
NEWS
ext/opcache/Optimizer/block_pass.c
ext/opcache/Optimizer/pass1_5.c
ext/opcache/Optimizer/zend_optimizer.c
ext/opcache/tests/bug66176.phpt [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index 571de403ddf75a15cb3b22f2d32e0b5ce0d9ffb1..c835df35955cf36694090019e3af66a1666be301 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -12,6 +12,7 @@ PHP                                                                        NEWS
     string). (Laruence)
 
 - OPCache
+  . Fixed bug #66176 (Invalid constant substitution). (Dmitry)
   . Fixed bug #65915 (Inconsistent results with require return value). (Dmitry)
   . Fixed bug #65559 (Opcache: cache not cleared if changes occur while
     running). (Dmitry)
index 1c34cffbf76e7a7d553153c8291fe4b85d2a5c7a..9f160539e95fd0b969d4b655528bc8b7613189fa 100644 (file)
@@ -1070,10 +1070,9 @@ static void zend_optimize_block(zend_code_block *block, zend_op_array *op_array,
 
                                literal_dtor(&ZEND_OP1_LITERAL(opline));
                                literal_dtor(&ZEND_OP2_LITERAL(opline));
-                               ZEND_OP1_LITERAL(opline) = result;
-                               SET_UNUSED(opline->op2);
-
                                opline->opcode = ZEND_QM_ASSIGN;
+                               SET_UNUSED(opline->op2);
+                               update_op1_const(op_array, opline, &result TSRMLS_CC);
                        }
                        EG(error_reporting) = er;
                } else if ((opline->opcode == ZEND_BOOL ||
@@ -1097,8 +1096,8 @@ static void zend_optimize_block(zend_code_block *block, zend_op_array *op_array,
                        }
                        PZ_SET_REFCOUNT_P(&result, 1);
                        PZ_UNSET_ISREF_P(&result);
-                       ZEND_OP1_LITERAL(opline) = result;
                        opline->opcode = ZEND_QM_ASSIGN;
+                       update_op1_const(op_array, opline, &result TSRMLS_CC);
                } else if ((opline->opcode == ZEND_RETURN || opline->opcode == ZEND_EXIT) &&
                                        ZEND_OP1_TYPE(opline) == IS_TMP_VAR &&
                                        VAR_SOURCE(opline->op1) &&
index 70ec6d5e2ec11aa1734b5b9a77daef4273ae540d..ca5b88290131a587805b44f1e105dcb7dd7bc69b 100644 (file)
@@ -219,15 +219,11 @@ if (ZEND_OPTIMIZER_PASS_1 & OPTIMIZATION_LEVEL) {
                                EG(in_execution) = 1;
                                EG(active_op_array) = op_array;
                                if (zend_get_constant("__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__") - 1, &offset TSRMLS_CC)) {
+                                       zend_uint tv = ZEND_RESULT(opline).var;
+
                                        literal_dtor(&ZEND_OP2_LITERAL(opline));
-                                       ZEND_OP1_TYPE(opline) = IS_CONST;
-#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
-                                       opline->op1.constant = zend_optimizer_add_literal(op_array, &offset TSRMLS_CC);
-#else
-                                       ZEND_OP1_LITERAL(opline) = offset;
-#endif
-                                       SET_UNUSED(opline->op2);
-                                       opline->opcode = ZEND_QM_ASSIGN;
+                                       MAKE_NOP(opline);
+                                       replace_tmp_by_const(op_array, opline, tv, &offset TSRMLS_CC);
                                }
                                EG(active_op_array) = orig_op_array;
                                EG(in_execution) = orig_in_execution;
@@ -238,20 +234,15 @@ if (ZEND_OPTIMIZER_PASS_1 & OPTIMIZATION_LEVEL) {
                                ZEND_OP2_TYPE(opline) == IS_CONST &&
                                ZEND_OP2_LITERAL(opline).type == IS_STRING) {
                                /* substitute persistent constants */
+                               zend_uint tv = ZEND_RESULT(opline).var;
                                zval c;
 
                                if (!zend_get_persistent_constant(Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)), &c, 1 TSRMLS_CC)) {
                                        break;
                                }
                                literal_dtor(&ZEND_OP2_LITERAL(opline));
-                               ZEND_OP1_TYPE(opline) = IS_CONST;
-#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
-                               opline->op1.constant = zend_optimizer_add_literal(op_array, &c TSRMLS_CC);
-#else
-                               ZEND_OP1_LITERAL(opline) = c;
-#endif
-                               SET_UNUSED(opline->op2);
-                               opline->opcode = ZEND_QM_ASSIGN;
+                               MAKE_NOP(opline);
+                               replace_tmp_by_const(op_array, opline, tv, &c TSRMLS_CC);
                        }
                        break;
 
index 28085cb441e221b0b757169aed0457f60c7089aa..c7fbad1189f305dbb782835817329ae83e8c7d5e 100644 (file)
@@ -19,6 +19,7 @@
    +----------------------------------------------------------------------+\r
 */\r
 \r
+#include "php.h"\r
 #include "Optimizer/zend_optimizer.h"\r
 #include "Optimizer/zend_optimizer_internal.h"\r
 #include "zend_API.h"\r
@@ -110,6 +111,124 @@ int zend_optimizer_add_literal(zend_op_array *op_array, const zval *zv TSRMLS_DC
 \r
 #endif\r
 \r
+static void update_op1_const(zend_op_array *op_array,\r
+                             zend_op       *opline,\r
+                             zval          *val TSRMLS_DC)\r
+{\r
+       if (opline->opcode == ZEND_FREE) {\r
+               MAKE_NOP(opline);\r
+               zval_dtor(val);\r
+       } else {\r
+               ZEND_OP1_TYPE(opline) = IS_CONST;\r
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO\r
+               if (Z_TYPE_P(val) == IS_STRING) {\r
+                       switch (opline->opcode) {\r
+                               case ZEND_INIT_STATIC_METHOD_CALL:\r
+                               case ZEND_CATCH:\r
+                               case ZEND_FETCH_CONSTANT:\r
+                                       opline->op1.constant = zend_optimizer_add_literal(op_array, val TSRMLS_CC);\r
+                                       Z_HASH_P(&ZEND_OP1_LITERAL(opline)) = zend_hash_func(Z_STRVAL(ZEND_OP1_LITERAL(opline)), Z_STRLEN(ZEND_OP1_LITERAL(opline)) + 1);\r
+                                       op_array->literals[opline->op1.constant].cache_slot = op_array->last_cache_slot++;\r
+                                       zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val));\r
+                                       zend_optimizer_add_literal(op_array, val TSRMLS_CC);\r
+                                       op_array->literals[opline->op1.constant+1].hash_value = zend_hash_func(Z_STRVAL(op_array->literals[opline->op1.constant+1].constant), Z_STRLEN(op_array->literals[opline->op1.constant+1].constant) + 1);\r
+                                       break;\r
+                               case ZEND_DO_FCALL:\r
+                                       zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val));\r
+                                       opline->op1.constant = zend_optimizer_add_literal(op_array, val TSRMLS_CC);\r
+                                       Z_HASH_P(&ZEND_OP1_LITERAL(opline)) = zend_hash_func(Z_STRVAL(ZEND_OP1_LITERAL(opline)), Z_STRLEN(ZEND_OP1_LITERAL(opline)) + 1);\r
+                                       op_array->literals[opline->op1.constant].cache_slot = op_array->last_cache_slot++;\r
+                                       break;\r
+                               default:\r
+                                       opline->op1.constant = zend_optimizer_add_literal(op_array, val TSRMLS_CC);\r
+                                       Z_HASH_P(&ZEND_OP1_LITERAL(opline)) = zend_hash_func(Z_STRVAL(ZEND_OP1_LITERAL(opline)), Z_STRLEN(ZEND_OP1_LITERAL(opline)) + 1);\r
+                                       break;\r
+                       }\r
+               } else {\r
+                       opline->op1.constant = zend_optimizer_add_literal(op_array, val TSRMLS_CC);\r
+               }\r
+#else\r
+               ZEND_OP1_LITERAL(opline) = *val;\r
+#endif\r
+       }\r
+}\r
+\r
+static void update_op2_const(zend_op_array *op_array,\r
+                             zend_op       *opline,\r
+                             zval          *val TSRMLS_DC)\r
+{\r
+       ZEND_OP2_TYPE(opline) = IS_CONST;\r
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO\r
+       opline->op2.constant = zend_optimizer_add_literal(op_array, val TSRMLS_CC);\r
+       if (Z_TYPE_P(val) == IS_STRING) {\r
+               Z_HASH_P(&ZEND_OP2_LITERAL(opline)) = zend_hash_func(Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)) + 1);\r
+               switch (opline->opcode) {\r
+                       case ZEND_FETCH_R:\r
+                       case ZEND_FETCH_W:\r
+                       case ZEND_FETCH_RW:\r
+                       case ZEND_FETCH_IS:\r
+                       case ZEND_FETCH_UNSET:\r
+                       case ZEND_FETCH_FUNC_ARG:\r
+                       case ZEND_FETCH_CLASS:\r
+                       case ZEND_INIT_FCALL_BY_NAME:\r
+                       /*case ZEND_INIT_NS_FCALL_BY_NAME:*/\r
+                       case ZEND_UNSET_VAR:\r
+                       case ZEND_ISSET_ISEMPTY_VAR:\r
+                       case ZEND_ADD_INTERFACE:\r
+                       case ZEND_ADD_TRAIT:\r
+                               op_array->literals[opline->op2.constant].cache_slot = op_array->last_cache_slot++;\r
+                               zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val));\r
+                               zend_optimizer_add_literal(op_array, val TSRMLS_CC);\r
+                               op_array->literals[opline->op2.constant+1].hash_value = zend_hash_func(Z_STRVAL(op_array->literals[opline->op2.constant+1].constant), Z_STRLEN(op_array->literals[opline->op2.constant+1].constant) + 1);\r
+                               break;\r
+                       case ZEND_INIT_METHOD_CALL:\r
+                       case ZEND_INIT_STATIC_METHOD_CALL:\r
+                               zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val));\r
+                               zend_optimizer_add_literal(op_array, val TSRMLS_CC);\r
+                               op_array->literals[opline->op2.constant+1].hash_value = zend_hash_func(Z_STRVAL(op_array->literals[opline->op2.constant+1].constant), Z_STRLEN(op_array->literals[opline->op2.constant+1].constant) + 1);\r
+                               /* break missing intentionally */                                               \r
+                       /*case ZEND_FETCH_CONSTANT:*/\r
+                       case ZEND_ASSIGN_OBJ:\r
+                       case ZEND_FETCH_OBJ_R:\r
+                       case ZEND_FETCH_OBJ_W:\r
+                       case ZEND_FETCH_OBJ_RW:\r
+                       case ZEND_FETCH_OBJ_IS:\r
+                       case ZEND_FETCH_OBJ_UNSET:\r
+                       case ZEND_FETCH_OBJ_FUNC_ARG:\r
+                       case ZEND_UNSET_OBJ:\r
+                       case ZEND_PRE_INC_OBJ:\r
+                       case ZEND_PRE_DEC_OBJ:\r
+                       case ZEND_POST_INC_OBJ:\r
+                       case ZEND_POST_DEC_OBJ:\r
+                       case ZEND_ISSET_ISEMPTY_PROP_OBJ:\r
+                               op_array->literals[opline->op2.constant].cache_slot = op_array->last_cache_slot;\r
+                               op_array->last_cache_slot += 2;\r
+                               break;\r
+                       case ZEND_ASSIGN_ADD:\r
+                       case ZEND_ASSIGN_SUB:\r
+                       case ZEND_ASSIGN_MUL:\r
+                       case ZEND_ASSIGN_DIV:\r
+                       case ZEND_ASSIGN_MOD:\r
+                       case ZEND_ASSIGN_SL:\r
+                       case ZEND_ASSIGN_SR:\r
+                       case ZEND_ASSIGN_CONCAT:\r
+                       case ZEND_ASSIGN_BW_OR:\r
+                       case ZEND_ASSIGN_BW_AND:\r
+                       case ZEND_ASSIGN_BW_XOR:\r
+                               if (opline->extended_value == ZEND_ASSIGN_OBJ) {\r
+                                       op_array->literals[opline->op2.constant].cache_slot = op_array->last_cache_slot;\r
+                                       op_array->last_cache_slot += 2;\r
+                               }\r
+                               break;\r
+                       default:\r
+                               break;\r
+               }\r
+       }\r
+#else\r
+       ZEND_OP2_LITERAL(opline) = *val;\r
+#endif\r
+}\r
+\r
 static void replace_tmp_by_const(zend_op_array *op_array,\r
                                  zend_op       *opline,\r
                                  zend_uint      var,\r
@@ -122,42 +241,7 @@ static void replace_tmp_by_const(zend_op_array *op_array,
                if (ZEND_OP1_TYPE(opline) == IS_TMP_VAR &&\r
                        ZEND_OP1(opline).var == var) {\r
 \r
-                       if (opline->opcode == ZEND_FREE) {\r
-                               MAKE_NOP(opline);\r
-                               zval_dtor(val);\r
-                       } else {\r
-                               ZEND_OP1_TYPE(opline) = IS_CONST;\r
-#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO\r
-                               if (Z_TYPE_P(val) == IS_STRING) {\r
-                                       switch (opline->opcode) {\r
-                                               case ZEND_INIT_STATIC_METHOD_CALL:\r
-                                               case ZEND_CATCH:\r
-                                               case ZEND_FETCH_CONSTANT:\r
-                                                       opline->op1.constant = zend_optimizer_add_literal(op_array, val TSRMLS_CC);\r
-                                                       Z_HASH_P(&ZEND_OP1_LITERAL(opline)) = zend_hash_func(Z_STRVAL(ZEND_OP1_LITERAL(opline)), Z_STRLEN(ZEND_OP1_LITERAL(opline)) + 1);\r
-                                                       op_array->literals[opline->op1.constant].cache_slot = op_array->last_cache_slot++;\r
-                                                       zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val));\r
-                                                       zend_optimizer_add_literal(op_array, val TSRMLS_CC);\r
-                                                       op_array->literals[opline->op1.constant+1].hash_value = zend_hash_func(Z_STRVAL(op_array->literals[opline->op1.constant+1].constant), Z_STRLEN(op_array->literals[opline->op1.constant+1].constant) + 1);\r
-                                                       break;\r
-                                               case ZEND_DO_FCALL:\r
-                                                       zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val));\r
-                                                       opline->op1.constant = zend_optimizer_add_literal(op_array, val TSRMLS_CC);\r
-                                                       Z_HASH_P(&ZEND_OP1_LITERAL(opline)) = zend_hash_func(Z_STRVAL(ZEND_OP1_LITERAL(opline)), Z_STRLEN(ZEND_OP1_LITERAL(opline)) + 1);\r
-                                                       op_array->literals[opline->op1.constant].cache_slot = op_array->last_cache_slot++;\r
-                                                       break;\r
-                                               default:\r
-                                                       opline->op1.constant = zend_optimizer_add_literal(op_array, val TSRMLS_CC);\r
-                                                       Z_HASH_P(&ZEND_OP1_LITERAL(opline)) = zend_hash_func(Z_STRVAL(ZEND_OP1_LITERAL(opline)), Z_STRLEN(ZEND_OP1_LITERAL(opline)) + 1);\r
-                                                       break;\r
-                                       }\r
-                               } else {\r
-                                       opline->op1.constant = zend_optimizer_add_literal(op_array, val TSRMLS_CC);\r
-                               }\r
-#else\r
-                               ZEND_OP1_LITERAL(opline) = *val;\r
-#endif\r
-                       }\r
+                       update_op1_const(op_array, opline, val TSRMLS_CC);\r
                        /* TMP_VAR my be used only once */\r
                        break;\r
                }\r
@@ -165,76 +249,8 @@ static void replace_tmp_by_const(zend_op_array *op_array,
                if (ZEND_OP2_TYPE(opline) == IS_TMP_VAR &&\r
                        ZEND_OP2(opline).var == var) {\r
 \r
-                       ZEND_OP2_TYPE(opline) = IS_CONST;\r
-#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO\r
-                       opline->op2.constant = zend_optimizer_add_literal(op_array, val TSRMLS_CC);\r
-                       if (Z_TYPE_P(val) == IS_STRING) {\r
-                               Z_HASH_P(&ZEND_OP2_LITERAL(opline)) = zend_hash_func(Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)) + 1);\r
-                               switch (opline->opcode) {\r
-                                       case ZEND_FETCH_R:\r
-                                       case ZEND_FETCH_W:\r
-                                       case ZEND_FETCH_RW:\r
-                                       case ZEND_FETCH_IS:\r
-                                       case ZEND_FETCH_UNSET:\r
-                                       case ZEND_FETCH_FUNC_ARG:\r
-                                       case ZEND_FETCH_CLASS:\r
-                                       case ZEND_INIT_FCALL_BY_NAME:\r
-                                       /*case ZEND_INIT_NS_FCALL_BY_NAME:*/\r
-                                       case ZEND_UNSET_VAR:\r
-                                       case ZEND_ISSET_ISEMPTY_VAR:\r
-                                       case ZEND_ADD_INTERFACE:\r
-                                       case ZEND_ADD_TRAIT:\r
-                                               op_array->literals[opline->op2.constant].cache_slot = op_array->last_cache_slot++;\r
-                                               zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val));\r
-                                               zend_optimizer_add_literal(op_array, val TSRMLS_CC);\r
-                                               op_array->literals[opline->op2.constant+1].hash_value = zend_hash_func(Z_STRVAL(op_array->literals[opline->op2.constant+1].constant), Z_STRLEN(op_array->literals[opline->op2.constant+1].constant) + 1);\r
-                                               break;\r
-                                       case ZEND_INIT_METHOD_CALL:\r
-                                       case ZEND_INIT_STATIC_METHOD_CALL:\r
-                                               zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val));\r
-                                               zend_optimizer_add_literal(op_array, val TSRMLS_CC);\r
-                                               op_array->literals[opline->op2.constant+1].hash_value = zend_hash_func(Z_STRVAL(op_array->literals[opline->op2.constant+1].constant), Z_STRLEN(op_array->literals[opline->op2.constant+1].constant) + 1);\r
-                                               /* break missing intentionally */                                               \r
-                                       /*case ZEND_FETCH_CONSTANT:*/\r
-                                       case ZEND_ASSIGN_OBJ:\r
-                                       case ZEND_FETCH_OBJ_R:\r
-                                       case ZEND_FETCH_OBJ_W:\r
-                                       case ZEND_FETCH_OBJ_RW:\r
-                                       case ZEND_FETCH_OBJ_IS:\r
-                                       case ZEND_FETCH_OBJ_UNSET:\r
-                                       case ZEND_FETCH_OBJ_FUNC_ARG:\r
-                                       case ZEND_UNSET_OBJ:\r
-                                       case ZEND_PRE_INC_OBJ:\r
-                                       case ZEND_PRE_DEC_OBJ:\r
-                                       case ZEND_POST_INC_OBJ:\r
-                                       case ZEND_POST_DEC_OBJ:\r
-                                       case ZEND_ISSET_ISEMPTY_PROP_OBJ:\r
-                                               op_array->literals[opline->op2.constant].cache_slot = op_array->last_cache_slot;\r
-                                               op_array->last_cache_slot += 2;\r
-                                               break;\r
-                                       case ZEND_ASSIGN_ADD:\r
-                                       case ZEND_ASSIGN_SUB:\r
-                                       case ZEND_ASSIGN_MUL:\r
-                                       case ZEND_ASSIGN_DIV:\r
-                                       case ZEND_ASSIGN_MOD:\r
-                                       case ZEND_ASSIGN_SL:\r
-                                       case ZEND_ASSIGN_SR:\r
-                                       case ZEND_ASSIGN_CONCAT:\r
-                                       case ZEND_ASSIGN_BW_OR:\r
-                                       case ZEND_ASSIGN_BW_AND:\r
-                                       case ZEND_ASSIGN_BW_XOR:\r
-                                               if (opline->extended_value == ZEND_ASSIGN_OBJ) {\r
-                                                       op_array->literals[opline->op2.constant].cache_slot = op_array->last_cache_slot;\r
-                                                       op_array->last_cache_slot += 2;\r
-                                               }\r
-                                               break;\r
-                                       default:\r
-                                               break;\r
-                               }\r
-                       }\r
-#else\r
-                       ZEND_OP2_LITERAL(opline) = *val;\r
-#endif\r
+                       update_op2_const(op_array, opline, val TSRMLS_CC);\r
+                       /* TMP_VAR my be used only once */\r
                        break;\r
                }\r
                opline++;\r
diff --git a/ext/opcache/tests/bug66176.phpt b/ext/opcache/tests/bug66176.phpt
new file mode 100644 (file)
index 0000000..a91024a
--- /dev/null
@@ -0,0 +1,19 @@
+--TEST--
+Bug #66176 (Invalid constant substitution)
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+opcache.optimization_level=-1
+opcache.file_update_protection=0
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+function foo($v) {
+       global $a;
+       return $a[$v];
+}
+$a = array(PHP_VERSION => 1);
+var_dump(foo(PHP_VERSION));
+--EXPECT--
+int(1)