From: Nikita Popov Date: Sun, 5 Jun 2016 19:58:58 +0000 (+0200) Subject: Don't optimize special dynamic calls to non-dynamic X-Git-Tag: php-7.1.0alpha1~22 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=70f05468855ec52cab4223d2e3cfd64e84b9abbd;p=php 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. --- diff --git a/Zend/tests/dynamic_call_008.phpt b/Zend/tests/dynamic_call_008.phpt new file mode 100644 index 0000000000..24240472d1 --- /dev/null +++ b/Zend/tests/dynamic_call_008.phpt @@ -0,0 +1,13 @@ +--TEST-- +Don't optimize dynamic call to non-dynamic one if it drops the warning +--FILE-- + 42]); +} +test(); + +?> +--EXPECTF-- +Warning: Cannot call extract() dynamically in %s on line %d diff --git a/ext/opcache/Optimizer/zend_cfg.c b/ext/opcache/Optimizer/zend_cfg.c index 9701f58606..e986ac0c20 100644 --- a/ext/opcache/Optimizer/zend_cfg.c +++ b/ext/opcache/Optimizer/zend_cfg.c @@ -21,6 +21,8 @@ #include "zend_cfg.h" #include "zend_func_info.h" #include "zend_worklist.h" +#include "zend_optimizer.h" +#include "zend_optimizer_internal.h" static void zend_mark_reachable(zend_op *opcodes, zend_basic_block *blocks, zend_basic_block *b) /* {{{ */ { @@ -319,27 +321,8 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b } if ((fn = zend_hash_find_ptr(EG(function_table), Z_STR_P(zv))) != NULL) { if (fn->type == ZEND_INTERNAL_FUNCTION) { - if (zend_string_equals_literal(Z_STR_P(zv), "extract")) { - flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS; - } else if (zend_string_equals_literal(Z_STR_P(zv), "compact")) { - flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS; - } else if (zend_string_equals_literal(Z_STR_P(zv), "parse_str") && - opline->extended_value == 1) { - flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS; - } else if (zend_string_equals_literal(Z_STR_P(zv), "mb_parse_str") && - opline->extended_value == 1) { - flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS; - } else if (zend_string_equals_literal(Z_STR_P(zv), "get_defined_vars")) { - flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS; - } else if (zend_string_equals_literal(Z_STR_P(zv), "assert")) { - flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS; - } else if (zend_string_equals_literal(Z_STR_P(zv), "func_num_args")) { - flags |= ZEND_FUNC_VARARG; - } else if (zend_string_equals_literal(Z_STR_P(zv), "func_get_arg")) { - flags |= ZEND_FUNC_VARARG; - } else if (zend_string_equals_literal(Z_STR_P(zv), "func_get_args")) { - flags |= ZEND_FUNC_VARARG; - } + flags |= zend_optimizer_classify_function( + Z_STR_P(zv), opline->extended_value); } } break; diff --git a/ext/opcache/Optimizer/zend_optimizer.c b/ext/opcache/Optimizer/zend_optimizer.c index 10cdcaf93c..ea0deb53c8 100644 --- a/ext/opcache/Optimizer/zend_optimizer.c +++ b/ext/opcache/Optimizer/zend_optimizer.c @@ -254,6 +254,13 @@ int zend_optimizer_update_op2_const(zend_op_array *op_array, return 0; } + if (zend_optimizer_classify_function(Z_STR_P(val), opline->extended_value)) { + /* Dynamic call to various special functions must stay dynamic, + * otherwise would drop a warning */ + zval_dtor(val); + return 0; + } + opline->opcode = ZEND_INIT_FCALL_BY_NAME; drop_leading_backslash(val); opline->op2.constant = zend_optimizer_add_literal(op_array, val); @@ -584,6 +591,30 @@ zend_function *zend_optimizer_get_called_func( #undef GET_OP } +uint32_t zend_optimizer_classify_function(zend_string *name, uint32_t num_args) { + if (zend_string_equals_literal(name, "extract")) { + return ZEND_FUNC_INDIRECT_VAR_ACCESS; + } else if (zend_string_equals_literal(name, "compact")) { + return ZEND_FUNC_INDIRECT_VAR_ACCESS; + } else if (zend_string_equals_literal(name, "parse_str") && num_args == 1) { + return ZEND_FUNC_INDIRECT_VAR_ACCESS; + } else if (zend_string_equals_literal(name, "mb_parse_str") && num_args == 1) { + return ZEND_FUNC_INDIRECT_VAR_ACCESS; + } else if (zend_string_equals_literal(name, "get_defined_vars")) { + return ZEND_FUNC_INDIRECT_VAR_ACCESS; + } else if (zend_string_equals_literal(name, "assert")) { + return ZEND_FUNC_INDIRECT_VAR_ACCESS; + } else if (zend_string_equals_literal(name, "func_num_args")) { + return ZEND_FUNC_VARARG; + } else if (zend_string_equals_literal(name, "func_get_arg")) { + return ZEND_FUNC_VARARG; + } else if (zend_string_equals_literal(name, "func_get_args")) { + return ZEND_FUNC_VARARG; + } else { + return 0; + } +} + static void zend_optimize(zend_op_array *op_array, zend_optimizer_ctx *ctx) { diff --git a/ext/opcache/Optimizer/zend_optimizer_internal.h b/ext/opcache/Optimizer/zend_optimizer_internal.h index 1d51b57634..e2e9823c78 100644 --- a/ext/opcache/Optimizer/zend_optimizer_internal.h +++ b/ext/opcache/Optimizer/zend_optimizer_internal.h @@ -108,5 +108,6 @@ void zend_optimizer_compact_literals(zend_op_array *op_array, zend_optimizer_ctx int zend_optimizer_is_disabled_func(const char *name, size_t len); zend_function *zend_optimizer_get_called_func( zend_script *script, zend_op_array *op_array, zend_op *opline, zend_bool rt_constants); +uint32_t zend_optimizer_classify_function(zend_string *name, uint32_t num_args); #endif