Skip to content

Commit db4b7ee

Browse files
committed
Zend: Add zend_check_method_accessible() to DRY method visibility checks
1 parent b8b0497 commit db4b7ee

File tree

8 files changed

+77
-136
lines changed

8 files changed

+77
-136
lines changed

Zend/zend_API.c

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4021,13 +4021,10 @@ static zend_always_inline bool zend_is_callable_check_func(zval *callable, zend_
40214021
((fcc->object && fcc->calling_scope->__call) ||
40224022
(!fcc->object && fcc->calling_scope->__callstatic)))) {
40234023
scope = get_scope(frame);
4024-
if (fcc->function_handler->common.scope != scope) {
4025-
if ((fcc->function_handler->common.fn_flags & ZEND_ACC_PRIVATE)
4026-
|| !zend_check_protected(zend_get_function_root_class(fcc->function_handler), scope)) {
4027-
retval = 0;
4028-
fcc->function_handler = NULL;
4029-
goto get_function_via_handler;
4030-
}
4024+
if (!zend_check_method_accessible(fcc->function_handler, scope)) {
4025+
retval = 0;
4026+
fcc->function_handler = NULL;
4027+
goto get_function_via_handler;
40314028
}
40324029
}
40334030
} else {
@@ -4086,17 +4083,14 @@ static zend_always_inline bool zend_is_callable_check_func(zval *callable, zend_
40864083
if (retval
40874084
&& !(fcc->function_handler->common.fn_flags & ZEND_ACC_PUBLIC)) {
40884085
scope = get_scope(frame);
4089-
if (fcc->function_handler->common.scope != scope) {
4090-
if ((fcc->function_handler->common.fn_flags & ZEND_ACC_PRIVATE)
4091-
|| (!zend_check_protected(zend_get_function_root_class(fcc->function_handler), scope))) {
4092-
if (error) {
4093-
if (*error) {
4094-
efree(*error);
4095-
}
4096-
zend_spprintf(error, 0, "cannot access %s method %s::%s()", zend_visibility_string(fcc->function_handler->common.fn_flags), ZSTR_VAL(fcc->calling_scope->name), ZSTR_VAL(fcc->function_handler->common.function_name));
4086+
if (!zend_check_method_accessible(fcc->function_handler, scope)) {
4087+
if (error) {
4088+
if (*error) {
4089+
efree(*error);
40974090
}
4098-
retval = 0;
4091+
zend_spprintf(error, 0, "cannot access %s method %s::%s()", zend_visibility_string(fcc->function_handler->common.fn_flags), ZSTR_VAL(fcc->calling_scope->name), ZSTR_VAL(fcc->function_handler->common.function_name));
40994092
}
4093+
retval = 0;
41004094
}
41014095
}
41024096
}

Zend/zend_ast.c

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1098,21 +1098,14 @@ ZEND_API zend_result ZEND_FASTCALL zend_ast_evaluate_inner(
10981098
} else {
10991099
fptr = zend_hash_find_ptr_lc(&ce->function_table, method_name);
11001100
if (fptr) {
1101-
if (!(fptr->common.fn_flags & ZEND_ACC_PUBLIC)) {
1102-
if (UNEXPECTED(fptr->common.scope != scope)) {
1103-
if (
1104-
UNEXPECTED(fptr->op_array.fn_flags & ZEND_ACC_PRIVATE)
1105-
|| UNEXPECTED(!zend_check_protected(zend_get_function_root_class(fptr), scope))
1106-
) {
1107-
if (ce->__callstatic) {
1108-
zend_throw_error(NULL, "Creating a callable for the magic __callStatic() method is not supported in constant expressions");
1109-
} else {
1110-
zend_bad_method_call(fptr, method_name, scope);
1111-
}
1112-
1113-
return FAILURE;
1114-
}
1101+
if (!zend_check_method_accessible(fptr, scope)) {
1102+
if (ce->__callstatic) {
1103+
zend_throw_error(NULL, "Creating a callable for the magic __callStatic() method is not supported in constant expressions");
1104+
} else {
1105+
zend_bad_method_call(fptr, method_name, scope);
11151106
}
1107+
1108+
return FAILURE;
11161109
}
11171110
} else {
11181111
if (ce->__callstatic) {

Zend/zend_builtin_functions.c

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -89,14 +89,9 @@ ZEND_FUNCTION(clone)
8989
RETURN_THROWS();
9090
}
9191

92-
if (clone && !(clone->common.fn_flags & ZEND_ACC_PUBLIC)) {
93-
if (clone->common.scope != scope) {
94-
if (UNEXPECTED(clone->common.fn_flags & ZEND_ACC_PRIVATE)
95-
|| UNEXPECTED(!zend_check_protected(zend_get_function_root_class(clone), scope))) {
96-
zend_bad_method_call(clone, clone->common.function_name, scope);
97-
RETURN_THROWS();
98-
}
99-
}
92+
if (clone && !zend_check_method_accessible(clone, scope)) {
93+
zend_bad_method_call(clone, clone->common.function_name, scope);
94+
RETURN_THROWS();
10095
}
10196

10297
zend_object *cloned;
@@ -953,13 +948,7 @@ ZEND_FUNCTION(get_class_methods)
953948
scope = zend_get_executed_scope();
954949

955950
ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, mptr) {
956-
if ((mptr->common.fn_flags & ZEND_ACC_PUBLIC)
957-
|| (scope &&
958-
(((mptr->common.fn_flags & ZEND_ACC_PROTECTED) &&
959-
zend_check_protected(mptr->common.scope, scope))
960-
|| ((mptr->common.fn_flags & ZEND_ACC_PRIVATE) &&
961-
scope == mptr->common.scope)))
962-
) {
951+
if (zend_check_method_accessible(mptr, scope)) {
963952
ZVAL_STR_COPY(&method_name, mptr->common.function_name);
964953
zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &method_name);
965954
}

Zend/zend_object_handlers.c

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1951,15 +1951,12 @@ ZEND_API zend_function *zend_std_get_static_method(zend_class_entry *ce, zend_st
19511951
fbc = Z_FUNC_P(func);
19521952
if (!(fbc->op_array.fn_flags & ZEND_ACC_PUBLIC)) {
19531953
zend_class_entry *scope = zend_get_executed_scope();
1954-
if (UNEXPECTED(fbc->common.scope != scope)) {
1955-
if (UNEXPECTED(fbc->op_array.fn_flags & ZEND_ACC_PRIVATE)
1956-
|| UNEXPECTED(!zend_check_protected(zend_get_function_root_class(fbc), scope))) {
1957-
zend_function *fallback_fbc = get_static_method_fallback(ce, function_name);
1958-
if (!fallback_fbc) {
1959-
zend_bad_method_call(fbc, function_name, scope);
1960-
}
1961-
fbc = fallback_fbc;
1954+
if (!zend_check_method_accessible(fbc, scope)) {
1955+
zend_function *fallback_fbc = get_static_method_fallback(ce, function_name);
1956+
if (!fallback_fbc) {
1957+
zend_bad_method_call(fbc, function_name, scope);
19621958
}
1959+
fbc = fallback_fbc;
19631960
}
19641961
}
19651962
} else {
@@ -2117,13 +2114,10 @@ ZEND_API zend_function *zend_std_get_constructor(zend_object *zobj) /* {{{ */
21172114
if (constructor) {
21182115
if (UNEXPECTED(!(constructor->op_array.fn_flags & ZEND_ACC_PUBLIC))) {
21192116
zend_class_entry *scope = get_fake_or_executed_scope();
2120-
if (UNEXPECTED(constructor->common.scope != scope)) {
2121-
if (UNEXPECTED(constructor->op_array.fn_flags & ZEND_ACC_PRIVATE)
2122-
|| UNEXPECTED(!zend_check_protected(zend_get_function_root_class(constructor), scope))) {
2123-
zend_bad_constructor_call(constructor, scope);
2124-
zend_object_store_ctor_failed(zobj);
2125-
constructor = NULL;
2126-
}
2117+
if (!zend_check_method_accessible(constructor, scope)) {
2118+
zend_bad_constructor_call(constructor, scope);
2119+
zend_object_store_ctor_failed(zobj);
2120+
constructor = NULL;
21272121
}
21282122
}
21292123
}

Zend/zend_objects.c

Lines changed: 14 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -124,48 +124,23 @@ ZEND_API void zend_objects_destroy_object(zend_object *object)
124124
const zend_op *old_opline_before_exception;
125125

126126
if (destructor->op_array.fn_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_PROTECTED)) {
127-
if (destructor->op_array.fn_flags & ZEND_ACC_PRIVATE) {
128-
/* Ensure that if we're calling a private function, we're allowed to do so.
129-
*/
130-
if (EG(current_execute_data)) {
131-
zend_class_entry *scope = zend_get_executed_scope();
132-
133-
if (object->ce != scope) {
134-
zend_throw_error(NULL,
135-
"Call to private %s::__destruct() from %s%s",
136-
ZSTR_VAL(object->ce->name),
137-
scope ? "scope " : "global scope",
138-
scope ? ZSTR_VAL(scope->name) : ""
139-
);
140-
return;
141-
}
142-
} else {
143-
zend_error(E_WARNING,
144-
"Call to private %s::__destruct() from global scope during shutdown ignored",
145-
ZSTR_VAL(object->ce->name));
127+
if (EG(current_execute_data)) {
128+
zend_class_entry *scope = zend_get_executed_scope();
129+
/* Ensure that if we're calling a protected or private function, we're allowed to do so. */
130+
if (!zend_check_method_accessible(destructor, scope)) {
131+
zend_throw_error(NULL,
132+
"Call to %s %s::__destruct() from %s%s",
133+
zend_visibility_string(destructor->common.fn_flags), ZSTR_VAL(object->ce->name),
134+
scope ? "scope " : "global scope",
135+
scope ? ZSTR_VAL(scope->name) : ""
136+
);
146137
return;
147138
}
148139
} else {
149-
/* Ensure that if we're calling a protected function, we're allowed to do so.
150-
*/
151-
if (EG(current_execute_data)) {
152-
zend_class_entry *scope = zend_get_executed_scope();
153-
154-
if (!zend_check_protected(zend_get_function_root_class(destructor), scope)) {
155-
zend_throw_error(NULL,
156-
"Call to protected %s::__destruct() from %s%s",
157-
ZSTR_VAL(object->ce->name),
158-
scope ? "scope " : "global scope",
159-
scope ? ZSTR_VAL(scope->name) : ""
160-
);
161-
return;
162-
}
163-
} else {
164-
zend_error(E_WARNING,
165-
"Call to protected %s::__destruct() from global scope during shutdown ignored",
166-
ZSTR_VAL(object->ce->name));
167-
return;
168-
}
140+
zend_error(E_WARNING,
141+
"Call to %s %s::__destruct() from global scope during shutdown ignored",
142+
zend_visibility_string(destructor->common.fn_flags), ZSTR_VAL(object->ce->name));
143+
return;
169144
}
170145
}
171146

Zend/zend_objects_API.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,5 +137,16 @@ static inline zend_property_info *zend_get_typed_property_info_for_slot(zend_obj
137137
return NULL;
138138
}
139139

140+
static inline bool zend_check_method_accessible(const zend_function *fn, const zend_class_entry *scope)
141+
{
142+
if (!(fn->common.fn_flags & ZEND_ACC_PUBLIC)
143+
&& fn->common.scope != scope
144+
&& (UNEXPECTED(fn->common.fn_flags & ZEND_ACC_PRIVATE)
145+
|| UNEXPECTED(!zend_check_protected(zend_get_function_root_class(fn), scope)))) {
146+
return false;
147+
}
148+
149+
return true;
150+
}
140151

141152
#endif /* ZEND_OBJECTS_H */

Zend/zend_vm_def.h

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6043,14 +6043,11 @@ ZEND_VM_COLD_CONST_HANDLER(110, ZEND_CLONE, CONST|TMPVAR|UNUSED|THIS|CV, ANY)
60436043

60446044
if (clone && !(clone->common.fn_flags & ZEND_ACC_PUBLIC)) {
60456045
scope = EX(func)->op_array.scope;
6046-
if (clone->common.scope != scope) {
6047-
if (UNEXPECTED(clone->common.fn_flags & ZEND_ACC_PRIVATE)
6048-
|| UNEXPECTED(!zend_check_protected(zend_get_function_root_class(clone), scope))) {
6049-
zend_bad_method_call(clone, clone->common.function_name, scope);
6050-
FREE_OP1();
6051-
ZVAL_UNDEF(EX_VAR(opline->result.var));
6052-
HANDLE_EXCEPTION();
6053-
}
6046+
if (!zend_check_method_accessible(clone, scope)) {
6047+
zend_bad_method_call(clone, clone->common.function_name, scope);
6048+
FREE_OP1();
6049+
ZVAL_UNDEF(EX_VAR(opline->result.var));
6050+
HANDLE_EXCEPTION();
60546051
}
60556052
}
60566053

Zend/zend_vm_execute.h

Lines changed: 17 additions & 29 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)