Skip to content

Commit 5de43f4

Browse files
committed
Zend: Add zend_check_method_accessible() to DRY method visibility checks
1 parent 4a98b36 commit 5de43f4

File tree

8 files changed

+82
-132
lines changed

8 files changed

+82
-132
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: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -89,18 +89,13 @@ 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_throw_error(NULL, "Call to %s %s::__clone() from %s%s",
97-
zend_visibility_string(clone->common.fn_flags), ZSTR_VAL(clone->common.scope->name),
98-
scope ? "scope " : "global scope",
99-
scope ? ZSTR_VAL(scope->name) : ""
100-
);
101-
RETURN_THROWS();
102-
}
103-
}
92+
if (clone && !zend_check_method_accessible(clone, scope)) {
93+
zend_throw_error(NULL, "Call to %s %s::__clone() from %s%s",
94+
zend_visibility_string(clone->common.fn_flags), ZSTR_VAL(clone->common.scope->name),
95+
scope ? "scope " : "global scope",
96+
scope ? ZSTR_VAL(scope->name) : ""
97+
);
98+
RETURN_THROWS();
10499
}
105100

106101
zend_object *cloned;
@@ -957,13 +952,7 @@ ZEND_FUNCTION(get_class_methods)
957952
scope = zend_get_executed_scope();
958953

959954
ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, mptr) {
960-
if ((mptr->common.fn_flags & ZEND_ACC_PUBLIC)
961-
|| (scope &&
962-
(((mptr->common.fn_flags & ZEND_ACC_PROTECTED) &&
963-
zend_check_protected(mptr->common.scope, scope))
964-
|| ((mptr->common.fn_flags & ZEND_ACC_PRIVATE) &&
965-
scope == mptr->common.scope)))
966-
) {
955+
if (zend_check_method_accessible(mptr, scope)) {
967956
ZVAL_STR_COPY(&method_name, mptr->common.function_name);
968957
zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &method_name);
969958
}

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: 11 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -124,48 +124,28 @@ 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)) {
127+
if (EG(current_execute_data)) {
128+
zend_class_entry *scope = zend_get_executed_scope();
129+
if (!zend_check_method_accessible(destructor, scope)) {
130+
/* Ensure that if we're calling a protected or private function, we're allowed to do so.
131+
*/
131132
zend_class_entry *scope = zend_get_executed_scope();
132133

133134
if (object->ce != scope) {
134135
zend_throw_error(NULL,
135-
"Call to private %s::__destruct() from %s%s",
136-
ZSTR_VAL(object->ce->name),
136+
"Call to %s %s::__destruct() from %s%s",
137+
zend_visibility_string(destructor->common.fn_flags), ZSTR_VAL(object->ce->name),
137138
scope ? "scope " : "global scope",
138139
scope ? ZSTR_VAL(scope->name) : ""
139140
);
140141
return;
141142
}
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));
146-
return;
147143
}
148144
} 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-
}
145+
zend_error(E_WARNING,
146+
"Call to %s %s::__destruct() from global scope during shutdown ignored",
147+
zend_visibility_string(destructor->common.fn_flags), ZSTR_VAL(object->ce->name));
148+
return;
169149
}
170150
}
171151

Zend/zend_objects_API.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,5 +137,20 @@ 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 (
143+
!(fn->common.fn_flags & ZEND_ACC_PUBLIC)
144+
&& fn->common.scope != scope
145+
&& (
146+
UNEXPECTED(fn->common.fn_flags & ZEND_ACC_PRIVATE)
147+
|| UNEXPECTED(!zend_check_protected(zend_get_function_root_class(fn), scope))
148+
)
149+
) {
150+
return false;
151+
}
152+
153+
return true;
154+
}
140155

141156
#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_wrong_clone_call(clone, 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_wrong_clone_call(clone, 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)