summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@zend.com>2013-11-26 17:47:02 +0400
committerDmitry Stogov <dmitry@zend.com>2013-11-26 17:47:02 +0400
commitd85ac7fb3f498455cfc1b051f8d48c9ba8ed8fdd (patch)
treecb72043b61ad676d93dab1b58da20acabda86f71
parentf28ac55b6da9cb11c99c1da9153baf551ff603c3 (diff)
downloadphp-git-d85ac7fb3f498455cfc1b051f8d48c9ba8ed8fdd.tar.gz
Fixed bug #66176 (Invalid constant substitution)
-rw-r--r--NEWS1
-rw-r--r--ext/opcache/Optimizer/block_pass.c7
-rw-r--r--ext/opcache/Optimizer/pass1_5.c23
-rw-r--r--ext/opcache/Optimizer/zend_optimizer.c228
-rw-r--r--ext/opcache/tests/bug66176.phpt19
5 files changed, 152 insertions, 126 deletions
diff --git a/NEWS b/NEWS
index 571de403dd..c835df3595 100644
--- 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)
diff --git a/ext/opcache/Optimizer/block_pass.c b/ext/opcache/Optimizer/block_pass.c
index 1c34cffbf7..9f160539e9 100644
--- a/ext/opcache/Optimizer/block_pass.c
+++ b/ext/opcache/Optimizer/block_pass.c
@@ -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) &&
diff --git a/ext/opcache/Optimizer/pass1_5.c b/ext/opcache/Optimizer/pass1_5.c
index 70ec6d5e2e..ca5b882901 100644
--- a/ext/opcache/Optimizer/pass1_5.c
+++ b/ext/opcache/Optimizer/pass1_5.c
@@ -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;
diff --git a/ext/opcache/Optimizer/zend_optimizer.c b/ext/opcache/Optimizer/zend_optimizer.c
index 28085cb441..c7fbad1189 100644
--- a/ext/opcache/Optimizer/zend_optimizer.c
+++ b/ext/opcache/Optimizer/zend_optimizer.c
@@ -19,6 +19,7 @@
+----------------------------------------------------------------------+
*/
+#include "php.h"
#include "Optimizer/zend_optimizer.h"
#include "Optimizer/zend_optimizer_internal.h"
#include "zend_API.h"
@@ -110,6 +111,124 @@ int zend_optimizer_add_literal(zend_op_array *op_array, const zval *zv TSRMLS_DC
#endif
+static void update_op1_const(zend_op_array *op_array,
+ zend_op *opline,
+ zval *val TSRMLS_DC)
+{
+ if (opline->opcode == ZEND_FREE) {
+ MAKE_NOP(opline);
+ zval_dtor(val);
+ } else {
+ ZEND_OP1_TYPE(opline) = IS_CONST;
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ if (Z_TYPE_P(val) == IS_STRING) {
+ switch (opline->opcode) {
+ case ZEND_INIT_STATIC_METHOD_CALL:
+ case ZEND_CATCH:
+ case ZEND_FETCH_CONSTANT:
+ opline->op1.constant = zend_optimizer_add_literal(op_array, val TSRMLS_CC);
+ Z_HASH_P(&ZEND_OP1_LITERAL(opline)) = zend_hash_func(Z_STRVAL(ZEND_OP1_LITERAL(opline)), Z_STRLEN(ZEND_OP1_LITERAL(opline)) + 1);
+ op_array->literals[opline->op1.constant].cache_slot = op_array->last_cache_slot++;
+ zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val));
+ zend_optimizer_add_literal(op_array, val TSRMLS_CC);
+ 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);
+ break;
+ case ZEND_DO_FCALL:
+ zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val));
+ opline->op1.constant = zend_optimizer_add_literal(op_array, val TSRMLS_CC);
+ Z_HASH_P(&ZEND_OP1_LITERAL(opline)) = zend_hash_func(Z_STRVAL(ZEND_OP1_LITERAL(opline)), Z_STRLEN(ZEND_OP1_LITERAL(opline)) + 1);
+ op_array->literals[opline->op1.constant].cache_slot = op_array->last_cache_slot++;
+ break;
+ default:
+ opline->op1.constant = zend_optimizer_add_literal(op_array, val TSRMLS_CC);
+ Z_HASH_P(&ZEND_OP1_LITERAL(opline)) = zend_hash_func(Z_STRVAL(ZEND_OP1_LITERAL(opline)), Z_STRLEN(ZEND_OP1_LITERAL(opline)) + 1);
+ break;
+ }
+ } else {
+ opline->op1.constant = zend_optimizer_add_literal(op_array, val TSRMLS_CC);
+ }
+#else
+ ZEND_OP1_LITERAL(opline) = *val;
+#endif
+ }
+}
+
+static void update_op2_const(zend_op_array *op_array,
+ zend_op *opline,
+ zval *val TSRMLS_DC)
+{
+ ZEND_OP2_TYPE(opline) = IS_CONST;
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ opline->op2.constant = zend_optimizer_add_literal(op_array, val TSRMLS_CC);
+ if (Z_TYPE_P(val) == IS_STRING) {
+ Z_HASH_P(&ZEND_OP2_LITERAL(opline)) = zend_hash_func(Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)) + 1);
+ switch (opline->opcode) {
+ case ZEND_FETCH_R:
+ case ZEND_FETCH_W:
+ case ZEND_FETCH_RW:
+ case ZEND_FETCH_IS:
+ case ZEND_FETCH_UNSET:
+ case ZEND_FETCH_FUNC_ARG:
+ case ZEND_FETCH_CLASS:
+ case ZEND_INIT_FCALL_BY_NAME:
+ /*case ZEND_INIT_NS_FCALL_BY_NAME:*/
+ case ZEND_UNSET_VAR:
+ case ZEND_ISSET_ISEMPTY_VAR:
+ case ZEND_ADD_INTERFACE:
+ case ZEND_ADD_TRAIT:
+ op_array->literals[opline->op2.constant].cache_slot = op_array->last_cache_slot++;
+ zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val));
+ zend_optimizer_add_literal(op_array, val TSRMLS_CC);
+ 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);
+ break;
+ case ZEND_INIT_METHOD_CALL:
+ case ZEND_INIT_STATIC_METHOD_CALL:
+ zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val));
+ zend_optimizer_add_literal(op_array, val TSRMLS_CC);
+ 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);
+ /* break missing intentionally */
+ /*case ZEND_FETCH_CONSTANT:*/
+ case ZEND_ASSIGN_OBJ:
+ case ZEND_FETCH_OBJ_R:
+ case ZEND_FETCH_OBJ_W:
+ case ZEND_FETCH_OBJ_RW:
+ case ZEND_FETCH_OBJ_IS:
+ case ZEND_FETCH_OBJ_UNSET:
+ case ZEND_FETCH_OBJ_FUNC_ARG:
+ case ZEND_UNSET_OBJ:
+ case ZEND_PRE_INC_OBJ:
+ case ZEND_PRE_DEC_OBJ:
+ case ZEND_POST_INC_OBJ:
+ case ZEND_POST_DEC_OBJ:
+ case ZEND_ISSET_ISEMPTY_PROP_OBJ:
+ op_array->literals[opline->op2.constant].cache_slot = op_array->last_cache_slot;
+ op_array->last_cache_slot += 2;
+ break;
+ case ZEND_ASSIGN_ADD:
+ case ZEND_ASSIGN_SUB:
+ case ZEND_ASSIGN_MUL:
+ case ZEND_ASSIGN_DIV:
+ case ZEND_ASSIGN_MOD:
+ case ZEND_ASSIGN_SL:
+ case ZEND_ASSIGN_SR:
+ case ZEND_ASSIGN_CONCAT:
+ case ZEND_ASSIGN_BW_OR:
+ case ZEND_ASSIGN_BW_AND:
+ case ZEND_ASSIGN_BW_XOR:
+ if (opline->extended_value == ZEND_ASSIGN_OBJ) {
+ op_array->literals[opline->op2.constant].cache_slot = op_array->last_cache_slot;
+ op_array->last_cache_slot += 2;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+#else
+ ZEND_OP2_LITERAL(opline) = *val;
+#endif
+}
+
static void replace_tmp_by_const(zend_op_array *op_array,
zend_op *opline,
zend_uint var,
@@ -122,42 +241,7 @@ static void replace_tmp_by_const(zend_op_array *op_array,
if (ZEND_OP1_TYPE(opline) == IS_TMP_VAR &&
ZEND_OP1(opline).var == var) {
- if (opline->opcode == ZEND_FREE) {
- MAKE_NOP(opline);
- zval_dtor(val);
- } else {
- ZEND_OP1_TYPE(opline) = IS_CONST;
-#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
- if (Z_TYPE_P(val) == IS_STRING) {
- switch (opline->opcode) {
- case ZEND_INIT_STATIC_METHOD_CALL:
- case ZEND_CATCH:
- case ZEND_FETCH_CONSTANT:
- opline->op1.constant = zend_optimizer_add_literal(op_array, val TSRMLS_CC);
- Z_HASH_P(&ZEND_OP1_LITERAL(opline)) = zend_hash_func(Z_STRVAL(ZEND_OP1_LITERAL(opline)), Z_STRLEN(ZEND_OP1_LITERAL(opline)) + 1);
- op_array->literals[opline->op1.constant].cache_slot = op_array->last_cache_slot++;
- zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val));
- zend_optimizer_add_literal(op_array, val TSRMLS_CC);
- 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);
- break;
- case ZEND_DO_FCALL:
- zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val));
- opline->op1.constant = zend_optimizer_add_literal(op_array, val TSRMLS_CC);
- Z_HASH_P(&ZEND_OP1_LITERAL(opline)) = zend_hash_func(Z_STRVAL(ZEND_OP1_LITERAL(opline)), Z_STRLEN(ZEND_OP1_LITERAL(opline)) + 1);
- op_array->literals[opline->op1.constant].cache_slot = op_array->last_cache_slot++;
- break;
- default:
- opline->op1.constant = zend_optimizer_add_literal(op_array, val TSRMLS_CC);
- Z_HASH_P(&ZEND_OP1_LITERAL(opline)) = zend_hash_func(Z_STRVAL(ZEND_OP1_LITERAL(opline)), Z_STRLEN(ZEND_OP1_LITERAL(opline)) + 1);
- break;
- }
- } else {
- opline->op1.constant = zend_optimizer_add_literal(op_array, val TSRMLS_CC);
- }
-#else
- ZEND_OP1_LITERAL(opline) = *val;
-#endif
- }
+ update_op1_const(op_array, opline, val TSRMLS_CC);
/* TMP_VAR my be used only once */
break;
}
@@ -165,76 +249,8 @@ static void replace_tmp_by_const(zend_op_array *op_array,
if (ZEND_OP2_TYPE(opline) == IS_TMP_VAR &&
ZEND_OP2(opline).var == var) {
- ZEND_OP2_TYPE(opline) = IS_CONST;
-#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
- opline->op2.constant = zend_optimizer_add_literal(op_array, val TSRMLS_CC);
- if (Z_TYPE_P(val) == IS_STRING) {
- Z_HASH_P(&ZEND_OP2_LITERAL(opline)) = zend_hash_func(Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)) + 1);
- switch (opline->opcode) {
- case ZEND_FETCH_R:
- case ZEND_FETCH_W:
- case ZEND_FETCH_RW:
- case ZEND_FETCH_IS:
- case ZEND_FETCH_UNSET:
- case ZEND_FETCH_FUNC_ARG:
- case ZEND_FETCH_CLASS:
- case ZEND_INIT_FCALL_BY_NAME:
- /*case ZEND_INIT_NS_FCALL_BY_NAME:*/
- case ZEND_UNSET_VAR:
- case ZEND_ISSET_ISEMPTY_VAR:
- case ZEND_ADD_INTERFACE:
- case ZEND_ADD_TRAIT:
- op_array->literals[opline->op2.constant].cache_slot = op_array->last_cache_slot++;
- zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val));
- zend_optimizer_add_literal(op_array, val TSRMLS_CC);
- 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);
- break;
- case ZEND_INIT_METHOD_CALL:
- case ZEND_INIT_STATIC_METHOD_CALL:
- zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val));
- zend_optimizer_add_literal(op_array, val TSRMLS_CC);
- 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);
- /* break missing intentionally */
- /*case ZEND_FETCH_CONSTANT:*/
- case ZEND_ASSIGN_OBJ:
- case ZEND_FETCH_OBJ_R:
- case ZEND_FETCH_OBJ_W:
- case ZEND_FETCH_OBJ_RW:
- case ZEND_FETCH_OBJ_IS:
- case ZEND_FETCH_OBJ_UNSET:
- case ZEND_FETCH_OBJ_FUNC_ARG:
- case ZEND_UNSET_OBJ:
- case ZEND_PRE_INC_OBJ:
- case ZEND_PRE_DEC_OBJ:
- case ZEND_POST_INC_OBJ:
- case ZEND_POST_DEC_OBJ:
- case ZEND_ISSET_ISEMPTY_PROP_OBJ:
- op_array->literals[opline->op2.constant].cache_slot = op_array->last_cache_slot;
- op_array->last_cache_slot += 2;
- break;
- case ZEND_ASSIGN_ADD:
- case ZEND_ASSIGN_SUB:
- case ZEND_ASSIGN_MUL:
- case ZEND_ASSIGN_DIV:
- case ZEND_ASSIGN_MOD:
- case ZEND_ASSIGN_SL:
- case ZEND_ASSIGN_SR:
- case ZEND_ASSIGN_CONCAT:
- case ZEND_ASSIGN_BW_OR:
- case ZEND_ASSIGN_BW_AND:
- case ZEND_ASSIGN_BW_XOR:
- if (opline->extended_value == ZEND_ASSIGN_OBJ) {
- op_array->literals[opline->op2.constant].cache_slot = op_array->last_cache_slot;
- op_array->last_cache_slot += 2;
- }
- break;
- default:
- break;
- }
- }
-#else
- ZEND_OP2_LITERAL(opline) = *val;
-#endif
+ update_op2_const(op_array, opline, val TSRMLS_CC);
+ /* TMP_VAR my be used only once */
break;
}
opline++;
diff --git a/ext/opcache/tests/bug66176.phpt b/ext/opcache/tests/bug66176.phpt
new file mode 100644
index 0000000000..a91024a616
--- /dev/null
+++ b/ext/opcache/tests/bug66176.phpt
@@ -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)