Skip to content

Commit f38d6ce

Browse files
committed
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 phpGH-5471.
1 parent 16e9d74 commit f38d6ce

File tree

1 file changed

+38
-12
lines changed

1 file changed

+38
-12
lines changed

ext/opcache/Optimizer/zend_func_info.c

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -886,6 +886,28 @@ static const func_info_t func_infos[] = {
886886
static HashTable func_info;
887887
int zend_func_info_rid = -1;
888888

889+
static uint32_t get_internal_func_info(
890+
const zend_call_info *call_info, const zend_ssa *ssa, zend_string *lcname) {
891+
if (call_info->callee_func->common.scope) {
892+
/* This is a method, not a function. */
893+
return 0;
894+
}
895+
896+
zval *zv = zend_hash_find_ex(&func_info, lcname, 1);
897+
if (!zv) {
898+
return 0;
899+
}
900+
901+
func_info_t *info = Z_PTR_P(zv);
902+
if (UNEXPECTED(zend_optimizer_is_disabled_func(info->name, info->name_len))) {
903+
return MAY_BE_NULL;
904+
} else if (info->info_func) {
905+
return info->info_func(call_info, ssa);
906+
} else {
907+
return info->info;
908+
}
909+
}
910+
889911
uint32_t zend_get_func_info(
890912
const zend_call_info *call_info, const zend_ssa *ssa,
891913
zend_class_entry **ce, zend_bool *ce_is_instanceof)
@@ -896,21 +918,14 @@ uint32_t zend_get_func_info(
896918
*ce_is_instanceof = 0;
897919

898920
if (callee_func->type == ZEND_INTERNAL_FUNCTION) {
899-
zval *zv;
900921
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));
901922

902-
if (!call_info->callee_func->common.scope
903-
&& (zv = zend_hash_find_ex(&func_info, lcname, 1))) {
904-
func_info_t *info = Z_PTR_P(zv);
905-
if (UNEXPECTED(zend_optimizer_is_disabled_func(info->name, info->name_len))) {
906-
ret = MAY_BE_NULL;
907-
} else if (info->info_func) {
908-
ret = info->info_func(call_info, ssa);
909-
} else {
910-
ret = info->info;
911-
}
912-
return ret;
923+
uint32_t internal_ret = get_internal_func_info(call_info, ssa, lcname);
924+
#if !ZEND_DEBUG
925+
if (internal_ret) {
926+
return internal_ret;
913927
}
928+
#endif
914929

915930
if (callee_func->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
916931
ret = zend_fetch_arg_info_type(NULL, callee_func->common.arg_info - 1, ce);
@@ -925,6 +940,17 @@ uint32_t zend_get_func_info(
925940
if (callee_func->common.fn_flags & ZEND_ACC_RETURN_REFERENCE) {
926941
ret |= MAY_BE_REF;
927942
}
943+
944+
#if ZEND_DEBUG
945+
/* Check whether the func_info information is a subset of the information we can compute
946+
* from the specified return type. */
947+
if (internal_ret) {
948+
if (internal_ret & ~ret) {
949+
fprintf(stderr, "Inaccurate func info for %s()\n", ZSTR_VAL(lcname));
950+
}
951+
return internal_ret;
952+
}
953+
#endif
928954
} else {
929955
// FIXME: the order of functions matters!!!
930956
zend_func_info *info = ZEND_FUNC_INFO((zend_op_array*)callee_func);

0 commit comments

Comments
 (0)