diff options
author | Dmitry Stogov <dmitry@zend.com> | 2013-11-26 17:47:02 +0400 |
---|---|---|
committer | Dmitry Stogov <dmitry@zend.com> | 2013-11-26 17:47:02 +0400 |
commit | d85ac7fb3f498455cfc1b051f8d48c9ba8ed8fdd (patch) | |
tree | cb72043b61ad676d93dab1b58da20acabda86f71 /ext/opcache | |
parent | f28ac55b6da9cb11c99c1da9153baf551ff603c3 (diff) | |
download | php-git-d85ac7fb3f498455cfc1b051f8d48c9ba8ed8fdd.tar.gz |
Fixed bug #66176 (Invalid constant substitution)
Diffstat (limited to 'ext/opcache')
-rw-r--r-- | ext/opcache/Optimizer/block_pass.c | 7 | ||||
-rw-r--r-- | ext/opcache/Optimizer/pass1_5.c | 23 | ||||
-rw-r--r-- | ext/opcache/Optimizer/zend_optimizer.c | 228 | ||||
-rw-r--r-- | ext/opcache/tests/bug66176.phpt | 19 |
4 files changed, 151 insertions, 126 deletions
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) |