Skip to content

Commit ef7fd7f

Browse files
committed
Merge branch 'PHP-5.5' of https://git.php.net/repository/php-src into PHP-5.5
# By Dmitry Stogov # Via Dmitry Stogov * 'PHP-5.5' of https://git.php.net/repository/php-src: Fixed bug #65845 (Error when Zend Opcache Optimizer is fully enabled).
2 parents f859b8d + ef8cf76 commit ef7fd7f

File tree

4 files changed

+154
-123
lines changed

4 files changed

+154
-123
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ PHP NEWS
4848
. Added support for GNU Hurd. (Svante Signell)
4949
. Added function opcache_compile_file() to load PHP scripts into cache
5050
without execution. (Julien)
51+
. Fixed bug #65845 (Error when Zend Opcache Optimizer is fully enabled).
52+
(Dmitry)
5153
. Fixed bug #65665 (Exception not properly caught when opcache enabled).
5254
(Laruence)
5355
. Fixed bug #65510 (5.5.2 crashes in _get_zval_ptr_ptr_var). (Dmitry)

ext/opcache/Optimizer/pass1_5.c

Lines changed: 7 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ if (ZEND_OPTIMIZER_PASS_1 & OPTIMIZATION_LEVEL) {
3737
int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC) = get_binary_op(opline->opcode);
3838
zend_uint tv = ZEND_RESULT(opline).var; /* temporary variable */
3939
zval result;
40-
zend_op *tmp_opline;
4140
int er;
4241

4342
if (opline->opcode == ZEND_DIV &&
@@ -61,95 +60,7 @@ if (ZEND_OPTIMIZER_PASS_1 & OPTIMIZATION_LEVEL) {
6160
literal_dtor(&ZEND_OP2_LITERAL(opline));
6261
MAKE_NOP(opline);
6362

64-
/* substitute the following TMP_VAR usage with constant */
65-
for (tmp_opline = opline + 1; tmp_opline < end; tmp_opline++) {
66-
if (ZEND_OP1_TYPE(tmp_opline) == IS_TMP_VAR &&
67-
ZEND_OP1(tmp_opline).var == tv) {
68-
if (tmp_opline->opcode == ZEND_FREE) {
69-
MAKE_NOP(tmp_opline);
70-
zval_dtor(&result);
71-
} else {
72-
ZEND_OP1_TYPE(tmp_opline) = IS_CONST;
73-
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
74-
tmp_opline->op1.constant = zend_optimizer_add_literal(op_array, &result TSRMLS_CC);
75-
if (Z_TYPE(result) == IS_STRING) {
76-
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);
77-
if (tmp_opline->opcode == ZEND_INIT_STATIC_METHOD_CALL ||
78-
tmp_opline->opcode == ZEND_DO_FCALL ||
79-
tmp_opline->opcode == ZEND_CATCH ||
80-
tmp_opline->opcode == ZEND_FETCH_CONSTANT) {
81-
op_array->literals[tmp_opline->op1.constant].cache_slot = op_array->last_cache_slot++;
82-
}
83-
}
84-
#else
85-
ZEND_OP1_LITERAL(tmp_opline) = result;
86-
#endif
87-
}
88-
/* TMP_VAR my be used only once */
89-
break;
90-
}
91-
if (ZEND_OP2_TYPE(tmp_opline) == IS_TMP_VAR &&
92-
ZEND_OP2(tmp_opline).var == tv) {
93-
ZEND_OP2_TYPE(tmp_opline) = IS_CONST;
94-
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
95-
tmp_opline->op2.constant = zend_optimizer_add_literal(op_array, &result TSRMLS_CC);
96-
if (Z_TYPE(result) == IS_STRING) {
97-
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);
98-
if (tmp_opline->opcode == ZEND_FETCH_R ||
99-
tmp_opline->opcode == ZEND_FETCH_W ||
100-
tmp_opline->opcode == ZEND_FETCH_RW ||
101-
tmp_opline->opcode == ZEND_FETCH_IS ||
102-
tmp_opline->opcode == ZEND_FETCH_UNSET ||
103-
tmp_opline->opcode == ZEND_FETCH_FUNC_ARG ||
104-
tmp_opline->opcode == ZEND_FETCH_CLASS ||
105-
tmp_opline->opcode == ZEND_INIT_FCALL_BY_NAME ||
106-
tmp_opline->opcode == ZEND_INIT_NS_FCALL_BY_NAME ||
107-
tmp_opline->opcode == ZEND_UNSET_VAR ||
108-
tmp_opline->opcode == ZEND_ISSET_ISEMPTY_VAR ||
109-
tmp_opline->opcode == ZEND_ADD_INTERFACE ||
110-
tmp_opline->opcode == ZEND_ADD_TRAIT) {
111-
op_array->literals[tmp_opline->op2.constant].cache_slot = op_array->last_cache_slot++;
112-
} else if (tmp_opline->opcode == ZEND_INIT_METHOD_CALL ||
113-
tmp_opline->opcode == ZEND_INIT_STATIC_METHOD_CALL ||
114-
tmp_opline->opcode == ZEND_FETCH_CONSTANT ||
115-
tmp_opline->opcode == ZEND_ASSIGN_OBJ ||
116-
tmp_opline->opcode == ZEND_FETCH_OBJ_R ||
117-
tmp_opline->opcode == ZEND_FETCH_OBJ_W ||
118-
tmp_opline->opcode == ZEND_FETCH_OBJ_RW ||
119-
tmp_opline->opcode == ZEND_FETCH_OBJ_IS ||
120-
tmp_opline->opcode == ZEND_FETCH_OBJ_UNSET ||
121-
tmp_opline->opcode == ZEND_FETCH_OBJ_FUNC_ARG ||
122-
tmp_opline->opcode == ZEND_UNSET_OBJ ||
123-
tmp_opline->opcode == ZEND_PRE_INC_OBJ ||
124-
tmp_opline->opcode == ZEND_PRE_DEC_OBJ ||
125-
tmp_opline->opcode == ZEND_POST_INC_OBJ ||
126-
tmp_opline->opcode == ZEND_POST_DEC_OBJ ||
127-
tmp_opline->opcode == ZEND_ISSET_ISEMPTY_PROP_OBJ) {
128-
op_array->literals[tmp_opline->op2.constant].cache_slot = op_array->last_cache_slot;
129-
op_array->last_cache_slot += 2;
130-
} else if (tmp_opline->opcode == ZEND_ASSIGN_ADD ||
131-
tmp_opline->opcode == ZEND_ASSIGN_SUB ||
132-
tmp_opline->opcode == ZEND_ASSIGN_MUL ||
133-
tmp_opline->opcode == ZEND_ASSIGN_DIV ||
134-
tmp_opline->opcode == ZEND_ASSIGN_MOD ||
135-
tmp_opline->opcode == ZEND_ASSIGN_SL ||
136-
tmp_opline->opcode == ZEND_ASSIGN_SR ||
137-
tmp_opline->opcode == ZEND_ASSIGN_CONCAT ||
138-
tmp_opline->opcode == ZEND_ASSIGN_BW_OR ||
139-
tmp_opline->opcode == ZEND_ASSIGN_BW_AND ||
140-
tmp_opline->opcode == ZEND_ASSIGN_BW_XOR) {
141-
if (tmp_opline->extended_value == ZEND_ASSIGN_OBJ) {
142-
op_array->literals[tmp_opline->op2.constant].cache_slot = op_array->last_cache_slot;
143-
op_array->last_cache_slot += 2;
144-
}
145-
}
146-
}
147-
#else
148-
ZEND_OP2_LITERAL(tmp_opline) = result;
149-
#endif
150-
break;
151-
}
152-
}
63+
replace_tmp_by_const(op_array, opline + 1, tv, &result TSRMLS_CC);
15364
}
15465
break;
15566

@@ -159,6 +70,7 @@ if (ZEND_OPTIMIZER_PASS_1 & OPTIMIZATION_LEVEL) {
15970
opline->extended_value != IS_OBJECT &&
16071
opline->extended_value != IS_RESOURCE) {
16172
/* cast of constant operand */
73+
zend_uint tv = ZEND_RESULT(opline).var; /* temporary variable */
16274
zval res;
16375
res = ZEND_OP1_LITERAL(opline);
16476
zval_copy_ctor(&res);
@@ -179,11 +91,11 @@ if (ZEND_OPTIMIZER_PASS_1 & OPTIMIZATION_LEVEL) {
17991
convert_to_string(&res);
18092
break;
18193
}
94+
18295
literal_dtor(&ZEND_OP1_LITERAL(opline));
183-
opline->opcode = ZEND_QM_ASSIGN;
184-
opline->extended_value = 0;
185-
ZEND_OP1_LITERAL(opline) = res;
186-
SET_UNUSED(opline->op2);
96+
MAKE_NOP(opline);
97+
98+
replace_tmp_by_const(op_array, opline + 1, tv, &res TSRMLS_CC);
18799
} else if (opline->extended_value == IS_BOOL) {
188100
/* T = CAST(X, IS_BOOL) => T = BOOL(X) */
189101
opline->opcode = ZEND_BOOL;
@@ -197,7 +109,6 @@ if (ZEND_OPTIMIZER_PASS_1 & OPTIMIZATION_LEVEL) {
197109
/* unary operation on constant operand */
198110
unary_op_type unary_op = get_unary_op(opline->opcode);
199111
zval result;
200-
zend_op *tmp_opline;
201112
zend_uint tv = ZEND_RESULT(opline).var; /* temporary variable */
202113
int er;
203114

@@ -218,34 +129,7 @@ if (ZEND_OPTIMIZER_PASS_1 & OPTIMIZATION_LEVEL) {
218129
literal_dtor(&ZEND_OP1_LITERAL(opline));
219130
MAKE_NOP(opline);
220131

221-
/* substitute the following TMP_VAR usage with constant */
222-
for (tmp_opline = opline + 1; tmp_opline < end; tmp_opline++) {
223-
if (ZEND_OP1_TYPE(tmp_opline) == IS_TMP_VAR &&
224-
ZEND_OP1(tmp_opline).var == tv) {
225-
if (tmp_opline->opcode == ZEND_FREE) {
226-
MAKE_NOP(tmp_opline);
227-
zval_dtor(&result);
228-
} else {
229-
ZEND_OP1_TYPE(tmp_opline) = IS_CONST;
230-
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
231-
tmp_opline->op1.constant = zend_optimizer_add_literal(op_array, &result TSRMLS_CC);
232-
#else
233-
ZEND_OP1_LITERAL(tmp_opline) = result;
234-
#endif
235-
}
236-
break;
237-
}
238-
if (ZEND_OP2_TYPE(tmp_opline) == IS_TMP_VAR &&
239-
ZEND_OP2(tmp_opline).var == tv) {
240-
ZEND_OP2_TYPE(tmp_opline) = IS_CONST;
241-
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
242-
tmp_opline->op2.constant = zend_optimizer_add_literal(op_array, &result TSRMLS_CC);
243-
#else
244-
ZEND_OP2_LITERAL(tmp_opline) = result;
245-
#endif
246-
break;
247-
}
248-
}
132+
replace_tmp_by_const(op_array, opline + 1, tv, &result TSRMLS_CC);
249133
}
250134
break;
251135

ext/opcache/Optimizer/zend_optimizer.c

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,137 @@ int zend_optimizer_add_literal(zend_op_array *op_array, const zval *zv TSRMLS_DC
110110

111111
#endif
112112

113+
static void replace_tmp_by_const(zend_op_array *op_array,
114+
zend_op *opline,
115+
zend_uint var,
116+
zval *val
117+
TSRMLS_DC)
118+
{
119+
zend_op *end = op_array->opcodes + op_array->last;
120+
121+
while (opline < end) {
122+
if (ZEND_OP1_TYPE(opline) == IS_TMP_VAR &&
123+
ZEND_OP1(opline).var == var) {
124+
125+
if (opline->opcode == ZEND_FREE) {
126+
MAKE_NOP(opline);
127+
zval_dtor(val);
128+
} else {
129+
ZEND_OP1_TYPE(opline) = IS_CONST;
130+
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
131+
if (Z_TYPE_P(val) == IS_STRING) {
132+
switch (opline->opcode) {
133+
case ZEND_INIT_STATIC_METHOD_CALL:
134+
case ZEND_CATCH:
135+
case ZEND_FETCH_CONSTANT:
136+
opline->op1.constant = zend_optimizer_add_literal(op_array, val TSRMLS_CC);
137+
Z_HASH_P(&ZEND_OP1_LITERAL(opline)) = zend_hash_func(Z_STRVAL(ZEND_OP1_LITERAL(opline)), Z_STRLEN(ZEND_OP1_LITERAL(opline)) + 1);
138+
op_array->literals[opline->op1.constant].cache_slot = op_array->last_cache_slot++;
139+
zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val));
140+
zend_optimizer_add_literal(op_array, val TSRMLS_CC);
141+
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);
142+
break;
143+
case ZEND_DO_FCALL:
144+
zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val));
145+
opline->op1.constant = zend_optimizer_add_literal(op_array, val TSRMLS_CC);
146+
Z_HASH_P(&ZEND_OP1_LITERAL(opline)) = zend_hash_func(Z_STRVAL(ZEND_OP1_LITERAL(opline)), Z_STRLEN(ZEND_OP1_LITERAL(opline)) + 1);
147+
op_array->literals[opline->op1.constant].cache_slot = op_array->last_cache_slot++;
148+
break;
149+
default:
150+
opline->op1.constant = zend_optimizer_add_literal(op_array, val TSRMLS_CC);
151+
Z_HASH_P(&ZEND_OP1_LITERAL(opline)) = zend_hash_func(Z_STRVAL(ZEND_OP1_LITERAL(opline)), Z_STRLEN(ZEND_OP1_LITERAL(opline)) + 1);
152+
break;
153+
}
154+
} else {
155+
opline->op1.constant = zend_optimizer_add_literal(op_array, val TSRMLS_CC);
156+
}
157+
#else
158+
ZEND_OP1_LITERAL(opline) = *val;
159+
#endif
160+
}
161+
/* TMP_VAR my be used only once */
162+
break;
163+
}
164+
165+
if (ZEND_OP2_TYPE(opline) == IS_TMP_VAR &&
166+
ZEND_OP2(opline).var == var) {
167+
168+
ZEND_OP2_TYPE(opline) = IS_CONST;
169+
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
170+
opline->op2.constant = zend_optimizer_add_literal(op_array, val TSRMLS_CC);
171+
if (Z_TYPE_P(val) == IS_STRING) {
172+
Z_HASH_P(&ZEND_OP2_LITERAL(opline)) = zend_hash_func(Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)) + 1);
173+
switch (opline->opcode) {
174+
case ZEND_FETCH_R:
175+
case ZEND_FETCH_W:
176+
case ZEND_FETCH_RW:
177+
case ZEND_FETCH_IS:
178+
case ZEND_FETCH_UNSET:
179+
case ZEND_FETCH_FUNC_ARG:
180+
case ZEND_FETCH_CLASS:
181+
case ZEND_INIT_FCALL_BY_NAME:
182+
/*case ZEND_INIT_NS_FCALL_BY_NAME:*/
183+
case ZEND_UNSET_VAR:
184+
case ZEND_ISSET_ISEMPTY_VAR:
185+
case ZEND_ADD_INTERFACE:
186+
case ZEND_ADD_TRAIT:
187+
op_array->literals[opline->op2.constant].cache_slot = op_array->last_cache_slot++;
188+
zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val));
189+
zend_optimizer_add_literal(op_array, val TSRMLS_CC);
190+
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);
191+
break;
192+
case ZEND_INIT_METHOD_CALL:
193+
case ZEND_INIT_STATIC_METHOD_CALL:
194+
zend_str_tolower(Z_STRVAL_P(val), Z_STRLEN_P(val));
195+
zend_optimizer_add_literal(op_array, val TSRMLS_CC);
196+
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);
197+
/* break missing intentionally */
198+
/*case ZEND_FETCH_CONSTANT:*/
199+
case ZEND_ASSIGN_OBJ:
200+
case ZEND_FETCH_OBJ_R:
201+
case ZEND_FETCH_OBJ_W:
202+
case ZEND_FETCH_OBJ_RW:
203+
case ZEND_FETCH_OBJ_IS:
204+
case ZEND_FETCH_OBJ_UNSET:
205+
case ZEND_FETCH_OBJ_FUNC_ARG:
206+
case ZEND_UNSET_OBJ:
207+
case ZEND_PRE_INC_OBJ:
208+
case ZEND_PRE_DEC_OBJ:
209+
case ZEND_POST_INC_OBJ:
210+
case ZEND_POST_DEC_OBJ:
211+
case ZEND_ISSET_ISEMPTY_PROP_OBJ:
212+
op_array->literals[opline->op2.constant].cache_slot = op_array->last_cache_slot;
213+
op_array->last_cache_slot += 2;
214+
break;
215+
case ZEND_ASSIGN_ADD:
216+
case ZEND_ASSIGN_SUB:
217+
case ZEND_ASSIGN_MUL:
218+
case ZEND_ASSIGN_DIV:
219+
case ZEND_ASSIGN_MOD:
220+
case ZEND_ASSIGN_SL:
221+
case ZEND_ASSIGN_SR:
222+
case ZEND_ASSIGN_CONCAT:
223+
case ZEND_ASSIGN_BW_OR:
224+
case ZEND_ASSIGN_BW_AND:
225+
case ZEND_ASSIGN_BW_XOR:
226+
if (opline->extended_value == ZEND_ASSIGN_OBJ) {
227+
op_array->literals[opline->op2.constant].cache_slot = op_array->last_cache_slot;
228+
op_array->last_cache_slot += 2;
229+
}
230+
break;
231+
default:
232+
break;
233+
}
234+
}
235+
#else
236+
ZEND_OP2_LITERAL(opline) = *val;
237+
#endif
238+
break;
239+
}
240+
opline++;
241+
}
242+
}
243+
113244
#include "Optimizer/nop_removal.c"
114245
#include "Optimizer/block_pass.c"
115246
#include "Optimizer/optimize_temp_vars_5.c"

ext/opcache/tests/bug65845.phpt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
--TEST--
2+
Bug #65845 (Error when Zend Opcache Optimizer is fully enabled)
3+
--INI--
4+
opcache.enable=1
5+
opcache.enable_cli=1
6+
--SKIPIF--
7+
<?php require_once('skipif.inc'); ?>
8+
--FILE--
9+
<?php
10+
$Pile['vars'][(string)'toto'] = 'tutu';
11+
var_dump($Pile['vars']['toto']);
12+
?>
13+
--EXPECT--
14+
string(4) "tutu"

0 commit comments

Comments
 (0)