# By Dmitry Stogov
# Via Christopher Jones (2) and Dmitry Stogov (2)
* 'master' of https://git.php.net/repository/php-src:
  Fixed bug #65845 (Error when Zend Opcache Optimizer is fully enabled).
This commit is contained in:
Christopher Jones 2013-10-10 11:15:12 -07:00
commit 71a3c07843
3 changed files with 152 additions and 123 deletions

View 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;

View File

@ -138,6 +138,137 @@ int zend_optimizer_add_literal(zend_op_array *op_array, const zval *zv TSRMLS_DC
#endif
static void replace_tmp_by_const(zend_op_array *op_array,
zend_op *opline,
zend_uint var,
zval *val
TSRMLS_DC)
{
zend_op *end = op_array->opcodes + op_array->last;
while (opline < end) {
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
}
/* TMP_VAR my be used only once */
break;
}
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
break;
}
opline++;
}
}
#include "Optimizer/nop_removal.c"
#include "Optimizer/block_pass.c"
#include "Optimizer/optimize_temp_vars_5.c"

View File

@ -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"