Skip to content

Commit 3ccd985

Browse files
committed
Improved method visibility checks
1 parent 5752745 commit 3ccd985

File tree

1 file changed

+42
-48
lines changed

1 file changed

+42
-48
lines changed

Zend/zend_object_handlers.c

Lines changed: 42 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1055,11 +1055,34 @@ ZEND_API void zend_std_unset_dimension(zval *object, zval *offset) /* {{{ */
10551055
}
10561056
/* }}} */
10571057

1058+
static zend_always_inline zend_function *zend_get_parent_private(zend_class_entry *scope, zend_class_entry *ce, zend_string *function_name) /* {{{ */
1059+
{
1060+
zval *func;
1061+
zend_function *fbc;
1062+
1063+
ce = ce->parent;
1064+
while (ce) {
1065+
if (ce == scope) {
1066+
if ((func = zend_hash_find(&ce->function_table, function_name))) {
1067+
fbc = Z_FUNC_P(func);
1068+
if (fbc->common.fn_flags & ZEND_ACC_PRIVATE
1069+
&& fbc->common.scope == scope) {
1070+
return fbc;
1071+
}
1072+
}
1073+
break;
1074+
}
1075+
ce = ce->parent;
1076+
}
1077+
return NULL;
1078+
}
1079+
/* }}} */
1080+
10581081
/* Ensures that we're allowed to call a private method.
10591082
* Returns the function address that should be called, or NULL
10601083
* if no such function exists.
10611084
*/
1062-
static inline zend_function *zend_check_private_int(zend_function *fbc, zend_class_entry *ce, zend_string *function_name) /* {{{ */
1085+
ZEND_API int zend_check_private(zend_function *fbc, zend_class_entry *ce, zend_string *function_name) /* {{{ */
10631086
{
10641087
zval *func;
10651088
zend_class_entry *scope;
@@ -1077,32 +1100,12 @@ static inline zend_function *zend_check_private_int(zend_function *fbc, zend_cla
10771100
scope = zend_get_executed_scope();
10781101
if (fbc->common.scope == ce && scope == ce) {
10791102
/* rule #1 checks out ok, allow the function call */
1080-
return fbc;
1103+
return 1;
10811104
}
10821105

10831106

10841107
/* Check rule #2 */
1085-
ce = ce->parent;
1086-
while (ce) {
1087-
if (ce == scope) {
1088-
if ((func = zend_hash_find(&ce->function_table, function_name))) {
1089-
fbc = Z_FUNC_P(func);
1090-
if (fbc->common.fn_flags & ZEND_ACC_PRIVATE
1091-
&& fbc->common.scope == scope) {
1092-
return fbc;
1093-
}
1094-
}
1095-
break;
1096-
}
1097-
ce = ce->parent;
1098-
}
1099-
return NULL;
1100-
}
1101-
/* }}} */
1102-
1103-
ZEND_API int zend_check_private(zend_function *fbc, zend_class_entry *ce, zend_string *function_name) /* {{{ */
1104-
{
1105-
return zend_check_private_int(fbc, ce, function_name) != NULL;
1108+
return zend_get_parent_private(scope, ce, function_name) != NULL;
11061109
}
11071110
/* }}} */
11081111

@@ -1218,21 +1221,22 @@ ZEND_API zend_function *zend_std_get_method(zend_object **obj_ptr, zend_string *
12181221
fbc = Z_FUNC_P(func);
12191222
/* Check access level */
12201223
if (fbc->op_array.fn_flags & ZEND_ACC_PRIVATE) {
1221-
zend_function *updated_fbc;
1222-
12231224
/* Ensure that if we're calling a private function, we're allowed to do so.
12241225
* If we're not and __call() handler exists, invoke it, otherwise error out.
12251226
*/
1226-
updated_fbc = zend_check_private_int(fbc, zobj->ce, lc_method_name);
1227-
if (EXPECTED(updated_fbc != NULL)) {
1228-
fbc = updated_fbc;
1229-
} else {
1230-
if (zobj->ce->__call) {
1231-
fbc = zend_get_user_call_function(zobj->ce, method_name);
1227+
scope = zend_get_executed_scope();
1228+
if (fbc->common.scope != scope || zobj->ce != scope) {
1229+
zend_function *updated_fbc = zend_get_parent_private(scope, zobj->ce, lc_method_name);
1230+
if (EXPECTED(updated_fbc != NULL)) {
1231+
fbc = updated_fbc;
12321232
} else {
1233-
scope = zend_get_executed_scope();
1234-
zend_throw_error(NULL, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(fbc->common.fn_flags), ZEND_FN_SCOPE_NAME(fbc), ZSTR_VAL(method_name), scope ? ZSTR_VAL(scope->name) : "");
1235-
fbc = NULL;
1233+
if (zobj->ce->__call) {
1234+
fbc = zend_get_user_call_function(zobj->ce, method_name);
1235+
} else {
1236+
scope = zend_get_executed_scope();
1237+
zend_throw_error(NULL, "Call to %s method %s::%s() from context '%s'", zend_visibility_string(fbc->common.fn_flags), ZEND_FN_SCOPE_NAME(fbc), ZSTR_VAL(method_name), scope ? ZSTR_VAL(scope->name) : "");
1238+
fbc = NULL;
1239+
}
12361240
}
12371241
}
12381242
} else if (fbc->op_array.fn_flags & (ZEND_ACC_CHANGED|ZEND_ACC_PROTECTED)) {
@@ -1242,14 +1246,9 @@ ZEND_API zend_function *zend_std_get_method(zend_object **obj_ptr, zend_string *
12421246

12431247
scope = zend_get_executed_scope();
12441248
if (fbc->op_array.fn_flags & ZEND_ACC_CHANGED) {
1245-
if (scope && is_derived_class(fbc->common.scope, scope)) {
1246-
if ((func = zend_hash_find(&scope->function_table, lc_method_name)) != NULL) {
1247-
zend_function *priv_fbc = Z_FUNC_P(func);
1248-
if (priv_fbc->common.fn_flags & ZEND_ACC_PRIVATE
1249-
&& priv_fbc->common.scope == scope) {
1250-
fbc = priv_fbc;
1251-
}
1252-
}
1249+
zend_function *priv_fbc = zend_get_parent_private(scope, fbc->common.scope, lc_method_name);
1250+
if (priv_fbc) {
1251+
fbc = priv_fbc;
12531252
}
12541253
} else {
12551254
/* Ensure that if we're calling a protected function, we're allowed to do so.
@@ -1339,15 +1338,10 @@ ZEND_API zend_function *zend_std_get_static_method(zend_class_entry *ce, zend_st
13391338
if (fbc->op_array.fn_flags & ZEND_ACC_PUBLIC) {
13401339
/* No further checks necessary, most common case */
13411340
} else if (fbc->op_array.fn_flags & ZEND_ACC_PRIVATE) {
1342-
zend_function *updated_fbc;
1343-
13441341
/* Ensure that if we're calling a private function, we're allowed to do so.
13451342
*/
13461343
scope = zend_get_executed_scope();
1347-
updated_fbc = zend_check_private_int(fbc, scope, lc_function_name);
1348-
if (EXPECTED(updated_fbc != NULL)) {
1349-
fbc = updated_fbc;
1350-
} else {
1344+
if (UNEXPECTED(fbc->common.scope != scope)) {
13511345
if (ce->__callstatic) {
13521346
fbc = zend_get_user_callstatic_function(ce, function_name);
13531347
} else {

0 commit comments

Comments
 (0)