summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2020-04-27 13:01:13 +0200
committerNikita Popov <nikita.ppv@gmail.com>2020-04-27 16:25:59 +0200
commitf38d6cea420f1ab6975647cfc87292072538629f (patch)
treed6afa276910bd3eaceab1e8791aae47242b2f9ea
parent16e9d74f078c48eb62afc97a29fa30d1969cc7fd (diff)
downloadphp-git-f38d6cea420f1ab6975647cfc87292072538629f.tar.gz
Check func_info consistency
Make sure explicitly specified func_info is a subset of automatically computed info. This will at least prevent cases where a type is removed from stubs, but not removed from func_info. Closes GH-5471.
-rw-r--r--ext/opcache/Optimizer/zend_func_info.c50
1 files changed, 38 insertions, 12 deletions
diff --git a/ext/opcache/Optimizer/zend_func_info.c b/ext/opcache/Optimizer/zend_func_info.c
index d63a773b40..6f1c247051 100644
--- a/ext/opcache/Optimizer/zend_func_info.c
+++ b/ext/opcache/Optimizer/zend_func_info.c
@@ -886,6 +886,28 @@ static const func_info_t func_infos[] = {
static HashTable func_info;
int zend_func_info_rid = -1;
+static uint32_t get_internal_func_info(
+ const zend_call_info *call_info, const zend_ssa *ssa, zend_string *lcname) {
+ if (call_info->callee_func->common.scope) {
+ /* This is a method, not a function. */
+ return 0;
+ }
+
+ zval *zv = zend_hash_find_ex(&func_info, lcname, 1);
+ if (!zv) {
+ return 0;
+ }
+
+ func_info_t *info = Z_PTR_P(zv);
+ if (UNEXPECTED(zend_optimizer_is_disabled_func(info->name, info->name_len))) {
+ return MAY_BE_NULL;
+ } else if (info->info_func) {
+ return info->info_func(call_info, ssa);
+ } else {
+ return info->info;
+ }
+}
+
uint32_t zend_get_func_info(
const zend_call_info *call_info, const zend_ssa *ssa,
zend_class_entry **ce, zend_bool *ce_is_instanceof)
@@ -896,21 +918,14 @@ uint32_t zend_get_func_info(
*ce_is_instanceof = 0;
if (callee_func->type == ZEND_INTERNAL_FUNCTION) {
- zval *zv;
zend_string *lcname = Z_STR_P(CRT_CONSTANT_EX(call_info->caller_op_array, call_info->caller_init_opline, call_info->caller_init_opline->op2));
- if (!call_info->callee_func->common.scope
- && (zv = zend_hash_find_ex(&func_info, lcname, 1))) {
- func_info_t *info = Z_PTR_P(zv);
- if (UNEXPECTED(zend_optimizer_is_disabled_func(info->name, info->name_len))) {
- ret = MAY_BE_NULL;
- } else if (info->info_func) {
- ret = info->info_func(call_info, ssa);
- } else {
- ret = info->info;
- }
- return ret;
+ uint32_t internal_ret = get_internal_func_info(call_info, ssa, lcname);
+#if !ZEND_DEBUG
+ if (internal_ret) {
+ return internal_ret;
}
+#endif
if (callee_func->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
ret = zend_fetch_arg_info_type(NULL, callee_func->common.arg_info - 1, ce);
@@ -925,6 +940,17 @@ uint32_t zend_get_func_info(
if (callee_func->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) {
ret |= MAY_BE_REF;
}
+
+#if ZEND_DEBUG
+ /* Check whether the func_info information is a subset of the information we can compute
+ * from the specified return type. */
+ if (internal_ret) {
+ if (internal_ret & ~ret) {
+ fprintf(stderr, "Inaccurate func info for %s()\n", ZSTR_VAL(lcname));
+ }
+ return internal_ret;
+ }
+#endif
} else {
// FIXME: the order of functions matters!!!
zend_func_info *info = ZEND_FUNC_INFO((zend_op_array*)callee_func);