Skip to content

Commit 70f0546

Browse files
committed
Don't optimize special dynamic calls to non-dynamic
As it drops the warning. This is more problematic with constant propagation, as tests would fail. Extract a zend_optimizer_classify_function() function, as its now needed by zend_cfg and update_opN.
1 parent da83e42 commit 70f0546

File tree

4 files changed

+49
-21
lines changed

4 files changed

+49
-21
lines changed

Zend/tests/dynamic_call_008.phpt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
--TEST--
2+
Don't optimize dynamic call to non-dynamic one if it drops the warning
3+
--FILE--
4+
<?php
5+
6+
function test() {
7+
((string) 'extract')(['a' => 42]);
8+
}
9+
test();
10+
11+
?>
12+
--EXPECTF--
13+
Warning: Cannot call extract() dynamically in %s on line %d

ext/opcache/Optimizer/zend_cfg.c

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
#include "zend_cfg.h"
2222
#include "zend_func_info.h"
2323
#include "zend_worklist.h"
24+
#include "zend_optimizer.h"
25+
#include "zend_optimizer_internal.h"
2426

2527
static void zend_mark_reachable(zend_op *opcodes, zend_basic_block *blocks, zend_basic_block *b) /* {{{ */
2628
{
@@ -319,27 +321,8 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b
319321
}
320322
if ((fn = zend_hash_find_ptr(EG(function_table), Z_STR_P(zv))) != NULL) {
321323
if (fn->type == ZEND_INTERNAL_FUNCTION) {
322-
if (zend_string_equals_literal(Z_STR_P(zv), "extract")) {
323-
flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
324-
} else if (zend_string_equals_literal(Z_STR_P(zv), "compact")) {
325-
flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
326-
} else if (zend_string_equals_literal(Z_STR_P(zv), "parse_str") &&
327-
opline->extended_value == 1) {
328-
flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
329-
} else if (zend_string_equals_literal(Z_STR_P(zv), "mb_parse_str") &&
330-
opline->extended_value == 1) {
331-
flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
332-
} else if (zend_string_equals_literal(Z_STR_P(zv), "get_defined_vars")) {
333-
flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
334-
} else if (zend_string_equals_literal(Z_STR_P(zv), "assert")) {
335-
flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS;
336-
} else if (zend_string_equals_literal(Z_STR_P(zv), "func_num_args")) {
337-
flags |= ZEND_FUNC_VARARG;
338-
} else if (zend_string_equals_literal(Z_STR_P(zv), "func_get_arg")) {
339-
flags |= ZEND_FUNC_VARARG;
340-
} else if (zend_string_equals_literal(Z_STR_P(zv), "func_get_args")) {
341-
flags |= ZEND_FUNC_VARARG;
342-
}
324+
flags |= zend_optimizer_classify_function(
325+
Z_STR_P(zv), opline->extended_value);
343326
}
344327
}
345328
break;

ext/opcache/Optimizer/zend_optimizer.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,13 @@ int zend_optimizer_update_op2_const(zend_op_array *op_array,
254254
return 0;
255255
}
256256

257+
if (zend_optimizer_classify_function(Z_STR_P(val), opline->extended_value)) {
258+
/* Dynamic call to various special functions must stay dynamic,
259+
* otherwise would drop a warning */
260+
zval_dtor(val);
261+
return 0;
262+
}
263+
257264
opline->opcode = ZEND_INIT_FCALL_BY_NAME;
258265
drop_leading_backslash(val);
259266
opline->op2.constant = zend_optimizer_add_literal(op_array, val);
@@ -584,6 +591,30 @@ zend_function *zend_optimizer_get_called_func(
584591
#undef GET_OP
585592
}
586593

594+
uint32_t zend_optimizer_classify_function(zend_string *name, uint32_t num_args) {
595+
if (zend_string_equals_literal(name, "extract")) {
596+
return ZEND_FUNC_INDIRECT_VAR_ACCESS;
597+
} else if (zend_string_equals_literal(name, "compact")) {
598+
return ZEND_FUNC_INDIRECT_VAR_ACCESS;
599+
} else if (zend_string_equals_literal(name, "parse_str") && num_args == 1) {
600+
return ZEND_FUNC_INDIRECT_VAR_ACCESS;
601+
} else if (zend_string_equals_literal(name, "mb_parse_str") && num_args == 1) {
602+
return ZEND_FUNC_INDIRECT_VAR_ACCESS;
603+
} else if (zend_string_equals_literal(name, "get_defined_vars")) {
604+
return ZEND_FUNC_INDIRECT_VAR_ACCESS;
605+
} else if (zend_string_equals_literal(name, "assert")) {
606+
return ZEND_FUNC_INDIRECT_VAR_ACCESS;
607+
} else if (zend_string_equals_literal(name, "func_num_args")) {
608+
return ZEND_FUNC_VARARG;
609+
} else if (zend_string_equals_literal(name, "func_get_arg")) {
610+
return ZEND_FUNC_VARARG;
611+
} else if (zend_string_equals_literal(name, "func_get_args")) {
612+
return ZEND_FUNC_VARARG;
613+
} else {
614+
return 0;
615+
}
616+
}
617+
587618
static void zend_optimize(zend_op_array *op_array,
588619
zend_optimizer_ctx *ctx)
589620
{

ext/opcache/Optimizer/zend_optimizer_internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,5 +108,6 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx
108108
int zend_optimizer_is_disabled_func(const char *name, size_t len);
109109
zend_function *zend_optimizer_get_called_func(
110110
zend_script *script, zend_op_array *op_array, zend_op *opline, zend_bool rt_constants);
111+
uint32_t zend_optimizer_classify_function(zend_string *name, uint32_t num_args);
111112

112113
#endif

0 commit comments

Comments
 (0)