--- /dev/null
+--TEST--
+Don't optimize dynamic call to non-dynamic one if it drops the warning
+--FILE--
+<?php
+
+function test() {
+ ((string) 'extract')(['a' => 42]);
+}
+test();
+
+?>
+--EXPECTF--
+Warning: Cannot call extract() dynamically in %s on line %d
#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) /* {{{ */
{
}
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;
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);
#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)
{
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