]> granicus.if.org Git - php/commitdiff
Fixed bug #65845 (Error when Zend Opcache Optimizer is fully enabled).
authorDmitry Stogov <dmitry@zend.com>
Thu, 10 Oct 2013 11:32:30 +0000 (15:32 +0400)
committerDmitry Stogov <dmitry@zend.com>
Thu, 10 Oct 2013 11:32:30 +0000 (15:32 +0400)
NEWS
ext/opcache/Optimizer/pass1_5.c
ext/opcache/Optimizer/zend_optimizer.c
ext/opcache/tests/bug65845.phpt [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index b70bdcc71b98a17995cf1bed6ae17e715e333e43..9436fe98835b284ea4bbead71f310b8d4c63d442 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -48,6 +48,8 @@ PHP                                                                        NEWS
   . Added support for GNU Hurd. (Svante Signell)
   . Added function opcache_compile_file() to load PHP scripts into cache
     without execution. (Julien)
+  . Fixed bug #65845 (Error when Zend Opcache Optimizer is fully enabled).
+    (Dmitry)
   . Fixed bug #65665 (Exception not properly caught when opcache enabled).
     (Laruence)
   . Fixed bug #65510 (5.5.2 crashes in _get_zval_ptr_ptr_var). (Dmitry)
index 795b954173e7bc2a0eed8d2d04e25dc0cd149b00..70ec6d5e2ec11aa1734b5b9a77daef4273ae540d 100644 (file)
@@ -37,7 +37,6 @@ if (ZEND_OPTIMIZER_PASS_1 & OPTIMIZATION_LEVEL) {
                                int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC) = get_binary_op(opline->opcode);
                                zend_uint tv = ZEND_RESULT(opline).var;         /* temporary variable */
                                zval result;
-                               zend_op *tmp_opline;
                                int er;
 
                                if (opline->opcode == ZEND_DIV &&
@@ -61,95 +60,7 @@ if (ZEND_OPTIMIZER_PASS_1 & OPTIMIZATION_LEVEL) {
                                literal_dtor(&ZEND_OP2_LITERAL(opline));
                                MAKE_NOP(opline);
 
-                               /* substitute the following TMP_VAR usage with constant */
-                               for (tmp_opline = opline + 1; tmp_opline < end; tmp_opline++) {
-                                       if (ZEND_OP1_TYPE(tmp_opline) == IS_TMP_VAR &&
-                                               ZEND_OP1(tmp_opline).var == tv) {
-                                               if (tmp_opline->opcode == ZEND_FREE) {
-                                                       MAKE_NOP(tmp_opline);
-                                                       zval_dtor(&result);
-                                               } else {
-                                                       ZEND_OP1_TYPE(tmp_opline) = IS_CONST;
-#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
-                                                       tmp_opline->op1.constant = zend_optimizer_add_literal(op_array, &result TSRMLS_CC);
-                                                       if (Z_TYPE(result) == IS_STRING) {
-                                                               Z_HASH_P(&ZEND_OP1_LITERAL(tmp_opline)) = zend_hash_func(Z_STRVAL(ZEND_OP1_LITERAL(tmp_opline)), Z_STRLEN(ZEND_OP1_LITERAL(tmp_opline)) + 1);
-                                                               if (tmp_opline->opcode == ZEND_INIT_STATIC_METHOD_CALL ||
-                                                                       tmp_opline->opcode == ZEND_DO_FCALL ||
-                                                                       tmp_opline->opcode == ZEND_CATCH ||
-                                                                       tmp_opline->opcode == ZEND_FETCH_CONSTANT) {
-                                                                       op_array->literals[tmp_opline->op1.constant].cache_slot = op_array->last_cache_slot++;
-                                                               }
-                                                       }
-#else
-                                                       ZEND_OP1_LITERAL(tmp_opline) = result;
-#endif
-                                               }
-                                               /* TMP_VAR my be used only once */
-                                               break;
-                                       }
-                                       if (ZEND_OP2_TYPE(tmp_opline) == IS_TMP_VAR &&
-                                               ZEND_OP2(tmp_opline).var == tv) {
-                                               ZEND_OP2_TYPE(tmp_opline) = IS_CONST;
-#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
-                                               tmp_opline->op2.constant = zend_optimizer_add_literal(op_array, &result TSRMLS_CC);
-                                               if (Z_TYPE(result) == IS_STRING) {
-                                                       Z_HASH_P(&ZEND_OP2_LITERAL(tmp_opline)) = zend_hash_func(Z_STRVAL(ZEND_OP2_LITERAL(tmp_opline)), Z_STRLEN(ZEND_OP2_LITERAL(tmp_opline)) + 1);
-                                                       if (tmp_opline->opcode == ZEND_FETCH_R ||
-                                                               tmp_opline->opcode == ZEND_FETCH_W ||
-                                                               tmp_opline->opcode == ZEND_FETCH_RW ||
-                                                               tmp_opline->opcode == ZEND_FETCH_IS ||
-                                                               tmp_opline->opcode == ZEND_FETCH_UNSET ||
-                                                               tmp_opline->opcode == ZEND_FETCH_FUNC_ARG ||
-                                                               tmp_opline->opcode == ZEND_FETCH_CLASS ||
-                                                               tmp_opline->opcode == ZEND_INIT_FCALL_BY_NAME ||
-                                                               tmp_opline->opcode == ZEND_INIT_NS_FCALL_BY_NAME ||
-                                                               tmp_opline->opcode == ZEND_UNSET_VAR ||
-                                                               tmp_opline->opcode == ZEND_ISSET_ISEMPTY_VAR ||
-                                                               tmp_opline->opcode == ZEND_ADD_INTERFACE ||
-                                                               tmp_opline->opcode == ZEND_ADD_TRAIT) {
-                                                               op_array->literals[tmp_opline->op2.constant].cache_slot = op_array->last_cache_slot++;
-                                                       } else if (tmp_opline->opcode == ZEND_INIT_METHOD_CALL ||
-                                                                       tmp_opline->opcode == ZEND_INIT_STATIC_METHOD_CALL ||
-                                                                       tmp_opline->opcode == ZEND_FETCH_CONSTANT ||
-                                                                       tmp_opline->opcode == ZEND_ASSIGN_OBJ ||
-                                                                       tmp_opline->opcode == ZEND_FETCH_OBJ_R ||
-                                                                       tmp_opline->opcode == ZEND_FETCH_OBJ_W ||
-                                                                       tmp_opline->opcode == ZEND_FETCH_OBJ_RW ||
-                                                                       tmp_opline->opcode == ZEND_FETCH_OBJ_IS ||
-                                                                       tmp_opline->opcode == ZEND_FETCH_OBJ_UNSET ||
-                                                                       tmp_opline->opcode == ZEND_FETCH_OBJ_FUNC_ARG ||
-                                                                       tmp_opline->opcode == ZEND_UNSET_OBJ ||
-                                                                       tmp_opline->opcode == ZEND_PRE_INC_OBJ ||
-                                                                       tmp_opline->opcode == ZEND_PRE_DEC_OBJ ||
-                                                                       tmp_opline->opcode == ZEND_POST_INC_OBJ ||
-                                                                       tmp_opline->opcode == ZEND_POST_DEC_OBJ ||
-                                                                       tmp_opline->opcode == ZEND_ISSET_ISEMPTY_PROP_OBJ) {
-                                                               op_array->literals[tmp_opline->op2.constant].cache_slot = op_array->last_cache_slot;
-                                                               op_array->last_cache_slot += 2;
-                                                       } else if (tmp_opline->opcode == ZEND_ASSIGN_ADD ||
-                                                                       tmp_opline->opcode == ZEND_ASSIGN_SUB ||
-                                                                       tmp_opline->opcode == ZEND_ASSIGN_MUL ||
-                                                                       tmp_opline->opcode == ZEND_ASSIGN_DIV ||
-                                                                       tmp_opline->opcode == ZEND_ASSIGN_MOD ||
-                                                                       tmp_opline->opcode == ZEND_ASSIGN_SL ||
-                                                                       tmp_opline->opcode == ZEND_ASSIGN_SR ||
-                                                                       tmp_opline->opcode == ZEND_ASSIGN_CONCAT ||
-                                                                       tmp_opline->opcode == ZEND_ASSIGN_BW_OR ||
-                                                                       tmp_opline->opcode == ZEND_ASSIGN_BW_AND ||
-                                                                       tmp_opline->opcode == ZEND_ASSIGN_BW_XOR) {
-                                                               if (tmp_opline->extended_value == ZEND_ASSIGN_OBJ) {
-                                                                       op_array->literals[tmp_opline->op2.constant].cache_slot = op_array->last_cache_slot;
-                                                                       op_array->last_cache_slot += 2;
-                                                               }
-                                                       }
-                                               }
-#else
-                                               ZEND_OP2_LITERAL(tmp_opline) = result;
-#endif
-                                               break;
-                                       }
-                               }
+                               replace_tmp_by_const(op_array, opline + 1, tv, &result TSRMLS_CC);
                        }
                        break;
 
@@ -159,6 +70,7 @@ if (ZEND_OPTIMIZER_PASS_1 & OPTIMIZATION_LEVEL) {
                                opline->extended_value != IS_OBJECT &&
                                opline->extended_value != IS_RESOURCE) {
                                /* cast of constant operand */
+                               zend_uint tv = ZEND_RESULT(opline).var;         /* temporary variable */
                                zval res;
                                res = ZEND_OP1_LITERAL(opline);
                                zval_copy_ctor(&res);
@@ -179,11 +91,11 @@ if (ZEND_OPTIMIZER_PASS_1 & OPTIMIZATION_LEVEL) {
                                                convert_to_string(&res);
                                                break;
                                }
+
                                literal_dtor(&ZEND_OP1_LITERAL(opline));
-                               opline->opcode = ZEND_QM_ASSIGN;
-                               opline->extended_value = 0;
-                               ZEND_OP1_LITERAL(opline) = res;
-                               SET_UNUSED(opline->op2);
+                               MAKE_NOP(opline);
+
+                               replace_tmp_by_const(op_array, opline + 1, tv, &res TSRMLS_CC);
                        } else if (opline->extended_value == IS_BOOL) {
                                /* T = CAST(X, IS_BOOL) => T = BOOL(X) */
                                opline->opcode = ZEND_BOOL;
@@ -197,7 +109,6 @@ if (ZEND_OPTIMIZER_PASS_1 & OPTIMIZATION_LEVEL) {
                                /* unary operation on constant operand */
                                unary_op_type unary_op = get_unary_op(opline->opcode);
                                zval result;
-                               zend_op *tmp_opline;
                                zend_uint tv = ZEND_RESULT(opline).var;         /* temporary variable */
                                int er;
 
@@ -218,34 +129,7 @@ if (ZEND_OPTIMIZER_PASS_1 & OPTIMIZATION_LEVEL) {
                                literal_dtor(&ZEND_OP1_LITERAL(opline));
                                MAKE_NOP(opline);
 
-                               /* substitute the following TMP_VAR usage with constant */
-                               for (tmp_opline = opline + 1; tmp_opline < end; tmp_opline++) {
-                                       if (ZEND_OP1_TYPE(tmp_opline) == IS_TMP_VAR &&
-                                               ZEND_OP1(tmp_opline).var == tv) {
-                                               if (tmp_opline->opcode == ZEND_FREE) {
-                                                       MAKE_NOP(tmp_opline);
-                                                       zval_dtor(&result);
-                                               } else {
-                                                       ZEND_OP1_TYPE(tmp_opline) = IS_CONST;
-#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
-                                                       tmp_opline->op1.constant = zend_optimizer_add_literal(op_array, &result TSRMLS_CC);
-#else
-                                                       ZEND_OP1_LITERAL(tmp_opline) = result;
-#endif
-                                               }
-                                               break;
-                                       }
-                                       if (ZEND_OP2_TYPE(tmp_opline) == IS_TMP_VAR &&
-                                               ZEND_OP2(tmp_opline).var == tv) {
-                                               ZEND_OP2_TYPE(tmp_opline) = IS_CONST;
-#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
-                                               tmp_opline->op2.constant = zend_optimizer_add_literal(op_array, &result TSRMLS_CC);
-#else
-                                               ZEND_OP2_LITERAL(tmp_opline) = result;
-#endif
-                                               break;
-                                       }
-                               }
+                               replace_tmp_by_const(op_array, opline + 1, tv, &result TSRMLS_CC);
                        }
                        break;
 
index 1f411d5da8073d35008d678792bbd1f20425a15e..28085cb441e221b0b757169aed0457f60c7089aa 100644 (file)
@@ -110,6 +110,137 @@ int zend_optimizer_add_literal(zend_op_array *op_array, const zval *zv TSRMLS_DC
 \r
 #endif\r
 \r
+static void replace_tmp_by_const(zend_op_array *op_array,\r
+                                 zend_op       *opline,\r
+                                 zend_uint      var,\r
+                                 zval          *val\r
+                                 TSRMLS_DC)\r
+{\r
+       zend_op *end = op_array->opcodes + op_array->last;\r
+\r
+       while (opline < end) {\r
+               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
+                       /* TMP_VAR my be used only once */\r
+                       break;\r
+               }\r
+\r
+               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
+                       break;\r
+               }\r
+               opline++;\r
+       }\r
+}\r
+\r
 #include "Optimizer/nop_removal.c"\r
 #include "Optimizer/block_pass.c"\r
 #include "Optimizer/optimize_temp_vars_5.c"\r
diff --git a/ext/opcache/tests/bug65845.phpt b/ext/opcache/tests/bug65845.phpt
new file mode 100644 (file)
index 0000000..2ae5f39
--- /dev/null
@@ -0,0 +1,14 @@
+--TEST--
+Bug #65845 (Error when Zend Opcache Optimizer is fully enabled)
+--INI--
+opcache.enable=1
+opcache.enable_cli=1
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+$Pile['vars'][(string)'toto'] = 'tutu';
+var_dump($Pile['vars']['toto']);
+?>
+--EXPECT--
+string(4) "tutu"