Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 12 additions & 6 deletions Zend/Optimizer/zend_func_info.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
+----------------------------------------------------------------------+
*/

#include "zend_API.h"
#include "zend_compile.h"
#include "zend_extensions.h"
#include "zend_ssa.h"
Expand Down Expand Up @@ -803,22 +804,27 @@ static const func_info_t func_infos[] = {
static HashTable func_info;
ZEND_API int zend_func_info_rid = -1;

static uint32_t get_internal_func_info(
const zend_call_info *call_info, const zend_ssa *ssa) {
zend_function *callee_func = call_info->callee_func;
uint32_t zend_get_internal_func_info(
const zend_function *callee_func, const zend_call_info *call_info, const zend_ssa *ssa) {
if (callee_func->common.scope) {
/* This is a method, not a function. */
return 0;
}

zval *zv = zend_hash_find_known_hash(&func_info, callee_func->common.function_name);
zend_string *name = callee_func->common.function_name;
if (!name) {
/* zend_pass_function has no name. */
return 0;
}

zval *zv = zend_hash_find_known_hash(&func_info, name);
if (!zv) {
return 0;
}

func_info_t *info = Z_PTR_P(zv);
if (info->info_func) {
return info->info_func(call_info, ssa);
return call_info ? info->info_func(call_info, ssa) : 0;
} else {
return info->info;
}
Expand All @@ -834,7 +840,7 @@ ZEND_API uint32_t zend_get_func_info(
*ce_is_instanceof = 0;

if (callee_func->type == ZEND_INTERNAL_FUNCTION) {
uint32_t internal_ret = get_internal_func_info(call_info, ssa);
uint32_t internal_ret = zend_get_internal_func_info(callee_func, call_info, ssa);
#if !ZEND_DEBUG
if (internal_ret) {
return internal_ret;
Expand Down
2 changes: 2 additions & 0 deletions Zend/Optimizer/zend_func_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ BEGIN_EXTERN_C()

extern ZEND_API int zend_func_info_rid;

uint32_t zend_get_internal_func_info(
const zend_function *callee_func, const zend_call_info *call_info, const zend_ssa *ssa);
ZEND_API uint32_t zend_get_func_info(
const zend_call_info *call_info, const zend_ssa *ssa,
zend_class_entry **ce, bool *ce_is_instanceof);
Expand Down
4 changes: 0 additions & 4 deletions Zend/Optimizer/zend_inference.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,6 @@
#define MAY_BE_GUARD (1<<28) /* needs type guard */
//#define MAY_BE_IN_REG (1<<29) /* deprecated and not used */

//TODO: remome MAY_BE_RC1, MAY_BE_RCN???
#define MAY_BE_RC1 (1<<30) /* may be non-reference with refcount == 1 */
#define MAY_BE_RCN (1u<<31) /* may be non-reference with refcount > 1 */

#define MAY_HAVE_DTOR \
(MAY_BE_OBJECT|MAY_BE_RESOURCE \
|MAY_BE_ARRAY_OF_ARRAY|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE)
Expand Down
63 changes: 63 additions & 0 deletions Zend/zend_execute.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include "zend_smart_str.h"
#include "zend_observer.h"
#include "zend_system_id.h"
#include "Optimizer/zend_func_info.h"

/* Virtual current working directory support */
#include "zend_virtual_cwd.h"
Expand Down Expand Up @@ -1199,6 +1200,68 @@ static void zend_verify_internal_read_property_type(zend_object *obj, zend_strin
zend_verify_property_type(prop_info, val, /* strict */ true);
}
}

#ifndef ZEND_VERIFY_FUNC_INFO
# define ZEND_VERIFY_FUNC_INFO 1
#endif

static void zend_verify_internal_func_info(zend_function *fn, zval *retval) {
#if ZEND_VERIFY_FUNC_INFO
zend_string *name = fn->common.function_name;
uint32_t type_mask = zend_get_internal_func_info(fn, NULL, NULL);
if (!type_mask) {
return;
}

/* Always check refcount of arrays, as immutable arrays are RCN. */
if (Z_REFCOUNTED_P(retval) || Z_TYPE_P(retval) == IS_ARRAY) {
if (!(type_mask & MAY_BE_RC1)) {
zend_error_noreturn(E_CORE_ERROR, "%s() missing rc1", ZSTR_VAL(name));
}
if (Z_REFCOUNT_P(retval) > 1 && !(type_mask & MAY_BE_RCN)) {
zend_error_noreturn(E_CORE_ERROR, "%s() missing rcn", ZSTR_VAL(name));
}
}

uint32_t type = 1u << Z_TYPE_P(retval);
if (!(type_mask & type)) {
zend_error_noreturn(E_CORE_ERROR, "%s() missing type %s",
ZSTR_VAL(name), zend_get_type_by_const(Z_TYPE_P(retval)));
}

if (Z_TYPE_P(retval) == IS_ARRAY) {
HashTable *ht = Z_ARRVAL_P(retval);
uint32_t num_checked = 0;
zend_string *str;
zval *val;
ZEND_HASH_FOREACH_STR_KEY_VAL(ht, str, val) {
if (str) {
if (!(type_mask & MAY_BE_ARRAY_KEY_STRING)) {
zend_error_noreturn(E_CORE_ERROR,
"%s() missing array_key_string", ZSTR_VAL(name));
}
} else {
if (!(type_mask & MAY_BE_ARRAY_KEY_LONG)) {
zend_error_noreturn(E_CORE_ERROR,
"%s() missing array_key_long", ZSTR_VAL(name));
}
}

uint32_t array_type = 1u << (Z_TYPE_P(val) + MAY_BE_ARRAY_SHIFT);
if (!(type_mask & array_type)) {
zend_error_noreturn(E_CORE_ERROR,
"%s() missing array element type %s",
ZSTR_VAL(name), zend_get_type_by_const(Z_TYPE_P(retval)));
}

/* Don't check all elements of large arrays. */
if (++num_checked > 16) {
break;
}
} ZEND_HASH_FOREACH_END();
}
#endif
}
#endif

ZEND_API ZEND_COLD void ZEND_FASTCALL zend_missing_arg_error(zend_execute_data *execute_data)
Expand Down
3 changes: 3 additions & 0 deletions Zend/zend_type_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@
#define MAY_BE_CLASS (1<<24)
#define MAY_BE_INDIRECT (1<<25)

#define MAY_BE_RC1 (1<<30) /* may be non-reference with refcount == 1 */
#define MAY_BE_RCN (1u<<31) /* may be non-reference with refcount > 1 */


#define MAY_BE_ANY_ARRAY \
(MAY_BE_ARRAY|MAY_BE_ARRAY_KEY_ANY|MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF)
Expand Down
4 changes: 4 additions & 0 deletions Zend/zend_vm_def.h
Original file line number Diff line number Diff line change
Expand Up @@ -3905,6 +3905,7 @@ ZEND_VM_HOT_HANDLER(129, ZEND_DO_ICALL, ANY, ANY, SPEC(RETVAL))
zend_verify_internal_return_type(call->func, ret));
ZEND_ASSERT((call->func->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)
? Z_ISREF_P(ret) : !Z_ISREF_P(ret));
zend_verify_internal_func_info(call->func, ret);
}
#endif

Expand Down Expand Up @@ -4023,6 +4024,7 @@ ZEND_VM_HOT_HANDLER(131, ZEND_DO_FCALL_BY_NAME, ANY, ANY, SPEC(RETVAL,OBSERVER))
zend_verify_internal_return_type(call->func, ret));
ZEND_ASSERT((call->func->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)
? Z_ISREF_P(ret) : !Z_ISREF_P(ret));
zend_verify_internal_func_info(call->func, ret);
}
#endif

Expand Down Expand Up @@ -4132,6 +4134,7 @@ ZEND_VM_HOT_HANDLER(60, ZEND_DO_FCALL, ANY, ANY, SPEC(RETVAL,OBSERVER))
zend_verify_internal_return_type(call->func, ret));
ZEND_ASSERT((call->func->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)
? Z_ISREF_P(ret) : !Z_ISREF_P(ret));
zend_verify_internal_func_info(call->func, ret);
}
#endif

Expand Down Expand Up @@ -8639,6 +8642,7 @@ ZEND_VM_HANDLER(158, ZEND_CALL_TRAMPOLINE, ANY, ANY, SPEC(OBSERVER))
zend_verify_internal_return_type(call->func, ret));
ZEND_ASSERT((call->func->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)
? Z_ISREF_P(ret) : !Z_ISREF_P(ret));
zend_verify_internal_func_info(call->func, ret);
}
#endif

Expand Down
10 changes: 10 additions & 0 deletions Zend/zend_vm_execute.h
Original file line number Diff line number Diff line change
Expand Up @@ -1243,6 +1243,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_ICALL_SPEC_RETV
zend_verify_internal_return_type(call->func, ret));
ZEND_ASSERT((call->func->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)
? Z_ISREF_P(ret) : !Z_ISREF_P(ret));
zend_verify_internal_func_info(call->func, ret);
}
#endif

Expand Down Expand Up @@ -1304,6 +1305,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_ICALL_SPEC_RETV
zend_verify_internal_return_type(call->func, ret));
ZEND_ASSERT((call->func->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)
? Z_ISREF_P(ret) : !Z_ISREF_P(ret));
zend_verify_internal_func_info(call->func, ret);
}
#endif

Expand Down Expand Up @@ -1469,6 +1471,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_S
zend_verify_internal_return_type(call->func, ret));
ZEND_ASSERT((call->func->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)
? Z_ISREF_P(ret) : !Z_ISREF_P(ret));
zend_verify_internal_func_info(call->func, ret);
}
#endif

Expand Down Expand Up @@ -1563,6 +1566,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_S
zend_verify_internal_return_type(call->func, ret));
ZEND_ASSERT((call->func->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)
? Z_ISREF_P(ret) : !Z_ISREF_P(ret));
zend_verify_internal_func_info(call->func, ret);
}
#endif

Expand Down Expand Up @@ -1658,6 +1662,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_BY_NAME_
zend_verify_internal_return_type(call->func, ret));
ZEND_ASSERT((call->func->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)
? Z_ISREF_P(ret) : !Z_ISREF_P(ret));
zend_verify_internal_func_info(call->func, ret);
}
#endif

Expand Down Expand Up @@ -1767,6 +1772,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETV
zend_verify_internal_return_type(call->func, ret));
ZEND_ASSERT((call->func->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)
? Z_ISREF_P(ret) : !Z_ISREF_P(ret));
zend_verify_internal_func_info(call->func, ret);
}
#endif

Expand Down Expand Up @@ -1875,6 +1881,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_RETV
zend_verify_internal_return_type(call->func, ret));
ZEND_ASSERT((call->func->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)
? Z_ISREF_P(ret) : !Z_ISREF_P(ret));
zend_verify_internal_func_info(call->func, ret);
}
#endif

Expand Down Expand Up @@ -1983,6 +1990,7 @@ static ZEND_VM_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DO_FCALL_SPEC_OBS
zend_verify_internal_return_type(call->func, ret));
ZEND_ASSERT((call->func->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)
? Z_ISREF_P(ret) : !Z_ISREF_P(ret));
zend_verify_internal_func_info(call->func, ret);
}
#endif

Expand Down Expand Up @@ -3338,6 +3346,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CALL_TRAMPOLINE_SPEC_HANDLER(Z
zend_verify_internal_return_type(call->func, ret));
ZEND_ASSERT((call->func->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)
? Z_ISREF_P(ret) : !Z_ISREF_P(ret));
zend_verify_internal_func_info(call->func, ret);
}
#endif

Expand Down Expand Up @@ -3474,6 +3483,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CALL_TRAMPOLINE_SPEC_OBSERVER_
zend_verify_internal_return_type(call->func, ret));
ZEND_ASSERT((call->func->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)
? Z_ISREF_P(ret) : !Z_ISREF_P(ret));
zend_verify_internal_func_info(call->func, ret);
}
#endif

Expand Down