]> granicus.if.org Git - php/commitdiff
Don't optimize special dynamic calls to non-dynamic
authorNikita Popov <nikic@php.net>
Sun, 5 Jun 2016 19:58:58 +0000 (21:58 +0200)
committerNikita Popov <nikic@php.net>
Sun, 5 Jun 2016 20:04:36 +0000 (22:04 +0200)
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.

Zend/tests/dynamic_call_008.phpt [new file with mode: 0644]
ext/opcache/Optimizer/zend_cfg.c
ext/opcache/Optimizer/zend_optimizer.c
ext/opcache/Optimizer/zend_optimizer_internal.h

diff --git a/Zend/tests/dynamic_call_008.phpt b/Zend/tests/dynamic_call_008.phpt
new file mode 100644 (file)
index 0000000..2424047
--- /dev/null
@@ -0,0 +1,13 @@
+--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
index 9701f586067c2e39b12683efd8566f503fb94d45..e986ac0c20cc6f7b5bbfafcdf5fc800d59bd24b3 100644 (file)
@@ -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;
index 10cdcaf93c5099635073ee1a5ee052df03cd30d2..ea0deb53c81f570882780a8c12ffa67d8d9bbb7b 100644 (file)
@@ -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)
 {
index 1d51b57634d0d6d883ccf46cc4d9924ef7219788..e2e9823c78e0855a9341de03cf11c9c4d211444d 100644 (file)
@@ -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