1 /*
2 +----------------------------------------------------------------------+
3 | Zend Engine |
4 +----------------------------------------------------------------------+
5 | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 2.00 of the Zend license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.zend.com/license/2_00.txt. |
11 | If you did not receive a copy of the Zend license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@zend.com so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Authors: Andi Gutmans <andi@php.net> |
16 | Zeev Suraski <zeev@php.net> |
17 +----------------------------------------------------------------------+
18 */
19
20 #include "zend.h"
21 #include "zend_API.h"
22 #include "zend_compile.h"
23 #include "zend_execute.h"
24 #include "zend_inheritance.h"
25 #include "zend_interfaces.h"
26 #include "zend_smart_str.h"
27 #include "zend_operators.h"
28 #include "zend_exceptions.h"
29
30 static void add_dependency_obligation(zend_class_entry *ce, zend_class_entry *dependency_ce);
31 static void add_compatibility_obligation(
32 zend_class_entry *ce, const zend_function *child_fn, zend_class_entry *child_scope,
33 const zend_function *parent_fn, zend_class_entry *parent_scope);
34 static void add_property_compatibility_obligation(
35 zend_class_entry *ce, const zend_property_info *child_prop,
36 const zend_property_info *parent_prop);
37
zend_type_copy_ctor(zend_type * type,zend_bool persistent)38 static void zend_type_copy_ctor(zend_type *type, zend_bool persistent) {
39 if (ZEND_TYPE_HAS_LIST(*type)) {
40 zend_type_list *old_list = ZEND_TYPE_LIST(*type);
41 size_t size = ZEND_TYPE_LIST_SIZE(old_list->num_types);
42 zend_type_list *new_list = ZEND_TYPE_USES_ARENA(*type)
43 ? zend_arena_alloc(&CG(arena), size) : pemalloc(size, persistent);
44 memcpy(new_list, old_list, ZEND_TYPE_LIST_SIZE(old_list->num_types));
45 ZEND_TYPE_SET_PTR(*type, new_list);
46
47 zend_type *list_type;
48 ZEND_TYPE_LIST_FOREACH(new_list, list_type) {
49 ZEND_ASSERT(ZEND_TYPE_HAS_NAME(*list_type));
50 zend_string_addref(ZEND_TYPE_NAME(*list_type));
51 } ZEND_TYPE_LIST_FOREACH_END();
52 } else if (ZEND_TYPE_HAS_NAME(*type)) {
53 zend_string_addref(ZEND_TYPE_NAME(*type));
54 }
55 }
56
zend_duplicate_property_info_internal(zend_property_info * property_info)57 static zend_property_info *zend_duplicate_property_info_internal(zend_property_info *property_info) /* {{{ */
58 {
59 zend_property_info* new_property_info = pemalloc(sizeof(zend_property_info), 1);
60 memcpy(new_property_info, property_info, sizeof(zend_property_info));
61 zend_string_addref(new_property_info->name);
62 zend_type_copy_ctor(&new_property_info->type, /* persistent */ 1);
63
64 return new_property_info;
65 }
66 /* }}} */
67
zend_duplicate_internal_function(zend_function * func,zend_class_entry * ce)68 static zend_function *zend_duplicate_internal_function(zend_function *func, zend_class_entry *ce) /* {{{ */
69 {
70 zend_function *new_function;
71
72 if (UNEXPECTED(ce->type & ZEND_INTERNAL_CLASS)) {
73 new_function = pemalloc(sizeof(zend_internal_function), 1);
74 memcpy(new_function, func, sizeof(zend_internal_function));
75 } else {
76 new_function = zend_arena_alloc(&CG(arena), sizeof(zend_internal_function));
77 memcpy(new_function, func, sizeof(zend_internal_function));
78 new_function->common.fn_flags |= ZEND_ACC_ARENA_ALLOCATED;
79 }
80 if (EXPECTED(new_function->common.function_name)) {
81 zend_string_addref(new_function->common.function_name);
82 }
83 return new_function;
84 }
85 /* }}} */
86
zend_duplicate_user_function(zend_function * func)87 static zend_function *zend_duplicate_user_function(zend_function *func) /* {{{ */
88 {
89 zend_function *new_function;
90
91 new_function = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
92 memcpy(new_function, func, sizeof(zend_op_array));
93
94 if (CG(compiler_options) & ZEND_COMPILE_PRELOAD) {
95 ZEND_ASSERT(new_function->op_array.fn_flags & ZEND_ACC_PRELOADED);
96 ZEND_MAP_PTR_NEW(new_function->op_array.static_variables_ptr);
97 } else {
98 ZEND_MAP_PTR_INIT(new_function->op_array.static_variables_ptr, &new_function->op_array.static_variables);
99 }
100
101 HashTable *static_properties_ptr = ZEND_MAP_PTR_GET(func->op_array.static_variables_ptr);
102 if (static_properties_ptr) {
103 /* See: Zend/tests/method_static_var.phpt */
104 ZEND_MAP_PTR_SET(new_function->op_array.static_variables_ptr, static_properties_ptr);
105 GC_TRY_ADDREF(static_properties_ptr);
106 } else {
107 GC_TRY_ADDREF(new_function->op_array.static_variables);
108 }
109
110 return new_function;
111 }
112 /* }}} */
113
zend_duplicate_function(zend_function * func,zend_class_entry * ce,zend_bool is_interface)114 static zend_always_inline zend_function *zend_duplicate_function(zend_function *func, zend_class_entry *ce, zend_bool is_interface) /* {{{ */
115 {
116 if (UNEXPECTED(func->type == ZEND_INTERNAL_FUNCTION)) {
117 return zend_duplicate_internal_function(func, ce);
118 } else {
119 if (func->op_array.refcount) {
120 (*func->op_array.refcount)++;
121 }
122 if (EXPECTED(func->op_array.function_name)) {
123 zend_string_addref(func->op_array.function_name);
124 }
125 if (is_interface
126 || EXPECTED(!func->op_array.static_variables)) {
127 /* reuse the same op_array structure */
128 return func;
129 }
130 return zend_duplicate_user_function(func);
131 }
132 }
133 /* }}} */
134
do_inherit_parent_constructor(zend_class_entry * ce)135 static void do_inherit_parent_constructor(zend_class_entry *ce) /* {{{ */
136 {
137 zend_class_entry *parent = ce->parent;
138
139 ZEND_ASSERT(parent != NULL);
140
141 /* You cannot change create_object */
142 ce->create_object = parent->create_object;
143
144 /* Inherit special functions if needed */
145 if (EXPECTED(!ce->get_iterator)) {
146 ce->get_iterator = parent->get_iterator;
147 }
148 if (EXPECTED(!ce->__get)) {
149 ce->__get = parent->__get;
150 }
151 if (EXPECTED(!ce->__set)) {
152 ce->__set = parent->__set;
153 }
154 if (EXPECTED(!ce->__unset)) {
155 ce->__unset = parent->__unset;
156 }
157 if (EXPECTED(!ce->__isset)) {
158 ce->__isset = parent->__isset;
159 }
160 if (EXPECTED(!ce->__call)) {
161 ce->__call = parent->__call;
162 }
163 if (EXPECTED(!ce->__callstatic)) {
164 ce->__callstatic = parent->__callstatic;
165 }
166 if (EXPECTED(!ce->__tostring)) {
167 ce->__tostring = parent->__tostring;
168 }
169 if (EXPECTED(!ce->clone)) {
170 ce->clone = parent->clone;
171 }
172 if (EXPECTED(!ce->__serialize)) {
173 ce->__serialize = parent->__serialize;
174 }
175 if (EXPECTED(!ce->__unserialize)) {
176 ce->__unserialize = parent->__unserialize;
177 }
178 if (EXPECTED(!ce->serialize)) {
179 ce->serialize = parent->serialize;
180 }
181 if (EXPECTED(!ce->unserialize)) {
182 ce->unserialize = parent->unserialize;
183 }
184 if (!ce->destructor) {
185 ce->destructor = parent->destructor;
186 }
187 if (EXPECTED(!ce->__debugInfo)) {
188 ce->__debugInfo = parent->__debugInfo;
189 }
190
191 if (ce->constructor) {
192 if (parent->constructor && UNEXPECTED(parent->constructor->common.fn_flags & ZEND_ACC_FINAL)) {
193 zend_error_noreturn(E_ERROR, "Cannot override final %s::%s() with %s::%s()",
194 ZSTR_VAL(parent->name), ZSTR_VAL(parent->constructor->common.function_name),
195 ZSTR_VAL(ce->name), ZSTR_VAL(ce->constructor->common.function_name));
196 }
197 return;
198 }
199
200 ce->constructor = parent->constructor;
201 }
202 /* }}} */
203
zend_visibility_string(uint32_t fn_flags)204 char *zend_visibility_string(uint32_t fn_flags) /* {{{ */
205 {
206 if (fn_flags & ZEND_ACC_PUBLIC) {
207 return "public";
208 } else if (fn_flags & ZEND_ACC_PRIVATE) {
209 return "private";
210 } else {
211 ZEND_ASSERT(fn_flags & ZEND_ACC_PROTECTED);
212 return "protected";
213 }
214 }
215 /* }}} */
216
resolve_class_name(zend_class_entry * scope,zend_string * name)217 static zend_string *resolve_class_name(zend_class_entry *scope, zend_string *name) {
218 ZEND_ASSERT(scope);
219 if (zend_string_equals_literal_ci(name, "parent") && scope->parent) {
220 if (scope->ce_flags & ZEND_ACC_RESOLVED_PARENT) {
221 return scope->parent->name;
222 } else {
223 return scope->parent_name;
224 }
225 } else if (zend_string_equals_literal_ci(name, "self")) {
226 return scope->name;
227 } else {
228 return name;
229 }
230 }
231
class_visible(zend_class_entry * ce)232 static zend_bool class_visible(zend_class_entry *ce) {
233 if (ce->type == ZEND_INTERNAL_CLASS) {
234 return !(CG(compiler_options) & ZEND_COMPILE_IGNORE_INTERNAL_CLASSES);
235 } else {
236 ZEND_ASSERT(ce->type == ZEND_USER_CLASS);
237 return !(CG(compiler_options) & ZEND_COMPILE_IGNORE_OTHER_FILES)
238 || ce->info.user.filename == CG(compiled_filename);
239 }
240 }
241
lookup_class(zend_class_entry * scope,zend_string * name,zend_bool register_unresolved)242 static zend_class_entry *lookup_class(
243 zend_class_entry *scope, zend_string *name, zend_bool register_unresolved) {
244 uint32_t flags = ZEND_FETCH_CLASS_ALLOW_UNLINKED | ZEND_FETCH_CLASS_NO_AUTOLOAD;
245 zend_class_entry *ce = zend_lookup_class_ex(name, NULL, flags);
246 if (!CG(in_compilation)) {
247 if (ce) {
248 return ce;
249 }
250
251 if (register_unresolved) {
252 /* We'll autoload this class and process delayed variance obligations later. */
253 if (!CG(delayed_autoloads)) {
254 ALLOC_HASHTABLE(CG(delayed_autoloads));
255 zend_hash_init(CG(delayed_autoloads), 0, NULL, NULL, 0);
256 }
257 zend_hash_add_empty_element(CG(delayed_autoloads), name);
258 }
259 } else {
260 if (ce && class_visible(ce)) {
261 return ce;
262 }
263
264 /* The current class may not be registered yet, so check for it explicitly. */
265 if (zend_string_equals_ci(scope->name, name)) {
266 return scope;
267 }
268 }
269
270 return NULL;
271 }
272
273 /* Instanceof that's safe to use on unlinked classes. */
unlinked_instanceof(zend_class_entry * ce1,zend_class_entry * ce2)274 static zend_bool unlinked_instanceof(zend_class_entry *ce1, zend_class_entry *ce2) {
275 if (ce1 == ce2) {
276 return 1;
277 }
278
279 if (ce1->ce_flags & ZEND_ACC_LINKED) {
280 return instanceof_function(ce1, ce2);
281 }
282
283 if (ce1->parent) {
284 zend_class_entry *parent_ce;
285 if (ce1->ce_flags & ZEND_ACC_RESOLVED_PARENT) {
286 parent_ce = ce1->parent;
287 } else {
288 parent_ce = zend_lookup_class_ex(ce1->parent_name, NULL,
289 ZEND_FETCH_CLASS_ALLOW_UNLINKED | ZEND_FETCH_CLASS_NO_AUTOLOAD);
290 }
291
292 /* It's not sufficient to only check the parent chain itself, as need to do a full
293 * recursive instanceof in case the parent interfaces haven't been copied yet. */
294 if (parent_ce && unlinked_instanceof(parent_ce, ce2)) {
295 return 1;
296 }
297 }
298
299 if (ce1->num_interfaces) {
300 uint32_t i;
301 if (ce1->ce_flags & ZEND_ACC_RESOLVED_INTERFACES) {
302 /* Unlike the normal instanceof_function(), we have to perform a recursive
303 * check here, as the parent interfaces might not have been fully copied yet. */
304 for (i = 0; i < ce1->num_interfaces; i++) {
305 if (unlinked_instanceof(ce1->interfaces[i], ce2)) {
306 return 1;
307 }
308 }
309 } else {
310 for (i = 0; i < ce1->num_interfaces; i++) {
311 zend_class_entry *ce = zend_lookup_class_ex(
312 ce1->interface_names[i].name, ce1->interface_names[i].lc_name,
313 ZEND_FETCH_CLASS_ALLOW_UNLINKED | ZEND_FETCH_CLASS_NO_AUTOLOAD);
314 /* Avoid recursing if class implements ifself. */
315 if (ce && ce != ce1 && unlinked_instanceof(ce, ce2)) {
316 return 1;
317 }
318 }
319 }
320 }
321
322 return 0;
323 }
324
zend_type_contains_traversable(zend_type type)325 static zend_bool zend_type_contains_traversable(zend_type type) {
326 zend_type *single_type;
327 if (ZEND_TYPE_FULL_MASK(type) & MAY_BE_OBJECT) {
328 return 1;
329 }
330
331 ZEND_TYPE_FOREACH(type, single_type) {
332 if (ZEND_TYPE_HAS_NAME(*single_type)
333 && zend_string_equals_literal_ci(ZEND_TYPE_NAME(*single_type), "Traversable")) {
334 return 1;
335 }
336 } ZEND_TYPE_FOREACH_END();
337 return 0;
338 }
339
zend_type_permits_self(zend_type type,zend_class_entry * scope,zend_class_entry * self)340 static zend_bool zend_type_permits_self(
341 zend_type type, zend_class_entry *scope, zend_class_entry *self) {
342 if (ZEND_TYPE_FULL_MASK(type) & MAY_BE_OBJECT) {
343 return 1;
344 }
345
346 /* Any types that may satisfy self must have already been loaded at this point
347 * (as a parent or interface), so we never need to register delayed variance obligations
348 * for this case. */
349 zend_type *single_type;
350 ZEND_TYPE_FOREACH(type, single_type) {
351 if (ZEND_TYPE_HAS_NAME(*single_type)) {
352 zend_string *name = resolve_class_name(scope, ZEND_TYPE_NAME(*single_type));
353 zend_class_entry *ce = lookup_class(self, name, /* register_unresolved */ 0);
354 if (ce && unlinked_instanceof(self, ce)) {
355 return 1;
356 }
357 }
358 } ZEND_TYPE_FOREACH_END();
359 return 0;
360 }
361
362 /* Unresolved means that class declarations that are currently not available are needed to
363 * determine whether the inheritance is valid or not. At runtime UNRESOLVED should be treated
364 * as an ERROR. */
365 typedef enum {
366 INHERITANCE_UNRESOLVED = -1,
367 INHERITANCE_ERROR = 0,
368 INHERITANCE_SUCCESS = 1,
369 } inheritance_status;
370
zend_perform_covariant_class_type_check(zend_class_entry * fe_scope,zend_string * fe_class_name,zend_class_entry * fe_ce,zend_class_entry * proto_scope,zend_type proto_type,zend_bool register_unresolved)371 static inheritance_status zend_perform_covariant_class_type_check(
372 zend_class_entry *fe_scope, zend_string *fe_class_name, zend_class_entry *fe_ce,
373 zend_class_entry *proto_scope, zend_type proto_type,
374 zend_bool register_unresolved) {
375 zend_bool have_unresolved = 0;
376 if (ZEND_TYPE_FULL_MASK(proto_type) & MAY_BE_OBJECT) {
377 /* Currently, any class name would be allowed here. We still perform a class lookup
378 * for forward-compatibility reasons, as we may have named types in the future that
379 * are not classes (such as enums or typedefs). */
380 if (!fe_ce) fe_ce = lookup_class(fe_scope, fe_class_name, register_unresolved);
381 if (!fe_ce) {
382 have_unresolved = 1;
383 } else {
384 return INHERITANCE_SUCCESS;
385 }
386 }
387 if (ZEND_TYPE_FULL_MASK(proto_type) & MAY_BE_ITERABLE) {
388 if (!fe_ce) fe_ce = lookup_class(fe_scope, fe_class_name, register_unresolved);
389 if (!fe_ce) {
390 have_unresolved = 1;
391 } else if (unlinked_instanceof(fe_ce, zend_ce_traversable)) {
392 return INHERITANCE_SUCCESS;
393 }
394 }
395
396 zend_type *single_type;
397 ZEND_TYPE_FOREACH(proto_type, single_type) {
398 zend_class_entry *proto_ce;
399 if (ZEND_TYPE_HAS_NAME(*single_type)) {
400 zend_string *proto_class_name =
401 resolve_class_name(proto_scope, ZEND_TYPE_NAME(*single_type));
402 if (zend_string_equals_ci(fe_class_name, proto_class_name)) {
403 return INHERITANCE_SUCCESS;
404 }
405
406 if (!fe_ce) fe_ce = lookup_class(fe_scope, fe_class_name, register_unresolved);
407 proto_ce =
408 lookup_class(proto_scope, proto_class_name, register_unresolved);
409 } else if (ZEND_TYPE_HAS_CE(*single_type)) {
410 if (!fe_ce) fe_ce = lookup_class(fe_scope, fe_class_name, register_unresolved);
411 proto_ce = ZEND_TYPE_CE(*single_type);
412 } else {
413 continue;
414 }
415
416 if (!fe_ce || !proto_ce) {
417 have_unresolved = 1;
418 } else if (unlinked_instanceof(fe_ce, proto_ce)) {
419 return INHERITANCE_SUCCESS;
420 }
421 } ZEND_TYPE_FOREACH_END();
422
423 return have_unresolved ? INHERITANCE_UNRESOLVED : INHERITANCE_ERROR;
424 }
425
zend_perform_covariant_type_check(zend_class_entry * fe_scope,zend_type fe_type,zend_class_entry * proto_scope,zend_type proto_type)426 static inheritance_status zend_perform_covariant_type_check(
427 zend_class_entry *fe_scope, zend_type fe_type,
428 zend_class_entry *proto_scope, zend_type proto_type) /* {{{ */
429 {
430 ZEND_ASSERT(ZEND_TYPE_IS_SET(fe_type) && ZEND_TYPE_IS_SET(proto_type));
431
432 /* Apart from void, everything is trivially covariant to the mixed type.
433 * Handle this case separately to ensure it never requires class loading. */
434 if (ZEND_TYPE_PURE_MASK(proto_type) == MAY_BE_ANY &&
435 !ZEND_TYPE_CONTAINS_CODE(fe_type, IS_VOID)) {
436 return INHERITANCE_SUCCESS;
437 }
438
439 /* Builtin types may be removed, but not added */
440 uint32_t fe_type_mask = ZEND_TYPE_PURE_MASK(fe_type);
441 uint32_t proto_type_mask = ZEND_TYPE_PURE_MASK(proto_type);
442 uint32_t added_types = fe_type_mask & ~proto_type_mask;
443 if (added_types) {
444 // TODO: Make "iterable" an alias of "array|Traversable" instead,
445 // so these special cases will be handled automatically.
446 if ((added_types & MAY_BE_ITERABLE)
447 && (proto_type_mask & MAY_BE_ARRAY)
448 && zend_type_contains_traversable(proto_type)) {
449 /* Replacing array|Traversable with iterable is okay */
450 added_types &= ~MAY_BE_ITERABLE;
451 }
452 if ((added_types & MAY_BE_ARRAY) && (proto_type_mask & MAY_BE_ITERABLE)) {
453 /* Replacing iterable with array is okay */
454 added_types &= ~MAY_BE_ARRAY;
455 }
456 if ((added_types & MAY_BE_STATIC)
457 && zend_type_permits_self(proto_type, proto_scope, fe_scope)) {
458 /* Replacing type that accepts self with static is okay */
459 added_types &= ~MAY_BE_STATIC;
460 }
461 if (added_types) {
462 /* Otherwise adding new types is illegal */
463 return INHERITANCE_ERROR;
464 }
465 }
466
467 zend_type *single_type;
468 zend_bool all_success = 1;
469
470 /* First try to check whether we can succeed without resolving anything */
471 ZEND_TYPE_FOREACH(fe_type, single_type) {
472 inheritance_status status;
473 if (ZEND_TYPE_HAS_NAME(*single_type)) {
474 zend_string *fe_class_name =
475 resolve_class_name(fe_scope, ZEND_TYPE_NAME(*single_type));
476 status = zend_perform_covariant_class_type_check(
477 fe_scope, fe_class_name, NULL,
478 proto_scope, proto_type, /* register_unresolved */ 0);
479 } else if (ZEND_TYPE_HAS_CE(*single_type)) {
480 zend_class_entry *fe_ce = ZEND_TYPE_CE(*single_type);
481 status = zend_perform_covariant_class_type_check(
482 fe_scope, fe_ce->name, fe_ce,
483 proto_scope, proto_type, /* register_unresolved */ 0);
484 } else {
485 continue;
486 }
487
488 if (status == INHERITANCE_ERROR) {
489 return INHERITANCE_ERROR;
490 }
491 if (status != INHERITANCE_SUCCESS) {
492 all_success = 0;
493 }
494 } ZEND_TYPE_FOREACH_END();
495
496 /* All individual checks succeeded, overall success */
497 if (all_success) {
498 return INHERITANCE_SUCCESS;
499 }
500
501 /* Register all classes that may have to be resolved */
502 ZEND_TYPE_FOREACH(fe_type, single_type) {
503 if (ZEND_TYPE_HAS_NAME(*single_type)) {
504 zend_string *fe_class_name =
505 resolve_class_name(fe_scope, ZEND_TYPE_NAME(*single_type));
506 zend_perform_covariant_class_type_check(
507 fe_scope, fe_class_name, NULL,
508 proto_scope, proto_type, /* register_unresolved */ 1);
509 } else if (ZEND_TYPE_HAS_CE(*single_type)) {
510 zend_class_entry *fe_ce = ZEND_TYPE_CE(*single_type);
511 zend_perform_covariant_class_type_check(
512 fe_scope, fe_ce->name, fe_ce,
513 proto_scope, proto_type, /* register_unresolved */ 1);
514 }
515 } ZEND_TYPE_FOREACH_END();
516 return INHERITANCE_UNRESOLVED;
517 }
518 /* }}} */
519
zend_do_perform_arg_type_hint_check(zend_class_entry * fe_scope,zend_arg_info * fe_arg_info,zend_class_entry * proto_scope,zend_arg_info * proto_arg_info)520 static inheritance_status zend_do_perform_arg_type_hint_check(
521 zend_class_entry *fe_scope, zend_arg_info *fe_arg_info,
522 zend_class_entry *proto_scope, zend_arg_info *proto_arg_info) /* {{{ */
523 {
524 if (!ZEND_TYPE_IS_SET(fe_arg_info->type) || ZEND_TYPE_PURE_MASK(fe_arg_info->type) == MAY_BE_ANY) {
525 /* Child with no type or mixed type is always compatible */
526 return INHERITANCE_SUCCESS;
527 }
528
529 if (!ZEND_TYPE_IS_SET(proto_arg_info->type)) {
530 /* Child defines a type, but parent doesn't, violates LSP */
531 return INHERITANCE_ERROR;
532 }
533
534 /* Contravariant type check is performed as a covariant type check with swapped
535 * argument order. */
536 return zend_perform_covariant_type_check(
537 proto_scope, proto_arg_info->type, fe_scope, fe_arg_info->type);
538 }
539 /* }}} */
540
541 /* For trait methods, fe_scope/proto_scope may differ from fe/proto->common.scope,
542 * as self will refer to the self of the class the trait is used in, not the trait
543 * the method was declared in. */
zend_do_perform_implementation_check(const zend_function * fe,zend_class_entry * fe_scope,const zend_function * proto,zend_class_entry * proto_scope)544 static inheritance_status zend_do_perform_implementation_check(
545 const zend_function *fe, zend_class_entry *fe_scope,
546 const zend_function *proto, zend_class_entry *proto_scope) /* {{{ */
547 {
548 uint32_t i, num_args, proto_num_args, fe_num_args;
549 inheritance_status status, local_status;
550 zend_bool proto_is_variadic, fe_is_variadic;
551
552 /* Checks for constructors only if they are declared in an interface,
553 * or explicitly marked as abstract
554 */
555 ZEND_ASSERT(!((fe->common.fn_flags & ZEND_ACC_CTOR)
556 && ((proto->common.scope->ce_flags & ZEND_ACC_INTERFACE) == 0
557 && (proto->common.fn_flags & ZEND_ACC_ABSTRACT) == 0)));
558
559 /* If the prototype method is private and not abstract, we do not enforce a signature.
560 * private abstract methods can only occur in traits. */
561 ZEND_ASSERT(!(proto->common.fn_flags & ZEND_ACC_PRIVATE)
562 || (proto->common.fn_flags & ZEND_ACC_ABSTRACT));
563
564 /* The number of required arguments cannot increase. */
565 if (proto->common.required_num_args < fe->common.required_num_args) {
566 return INHERITANCE_ERROR;
567 }
568
569 /* by-ref constraints on return values are covariant */
570 if ((proto->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)
571 && !(fe->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)) {
572 return INHERITANCE_ERROR;
573 }
574
575 proto_is_variadic = (proto->common.fn_flags & ZEND_ACC_VARIADIC) != 0;
576 fe_is_variadic = (fe->common.fn_flags & ZEND_ACC_VARIADIC) != 0;
577
578 /* A variadic function cannot become non-variadic */
579 if (proto_is_variadic && !fe_is_variadic) {
580 return INHERITANCE_ERROR;
581 }
582
583 /* The variadic argument is not included in the stored argument count. */
584 proto_num_args = proto->common.num_args + proto_is_variadic;
585 fe_num_args = fe->common.num_args + fe_is_variadic;
586 num_args = MAX(proto_num_args, fe_num_args);
587
588 status = INHERITANCE_SUCCESS;
589 for (i = 0; i < num_args; i++) {
590 zend_arg_info *proto_arg_info =
591 i < proto_num_args ? &proto->common.arg_info[i] :
592 proto_is_variadic ? &proto->common.arg_info[proto_num_args - 1] : NULL;
593 zend_arg_info *fe_arg_info =
594 i < fe_num_args ? &fe->common.arg_info[i] :
595 fe_is_variadic ? &fe->common.arg_info[fe_num_args - 1] : NULL;
596 if (!proto_arg_info) {
597 /* A new (optional) argument has been added, which is fine. */
598 continue;
599 }
600 if (!fe_arg_info) {
601 /* An argument has been removed. This is considered illegal, because arity checks
602 * work based on a model where passing more than the declared number of parameters
603 * to a function is an error. */
604 return INHERITANCE_ERROR;
605 }
606
607 local_status = zend_do_perform_arg_type_hint_check(
608 fe_scope, fe_arg_info, proto_scope, proto_arg_info);
609
610 if (UNEXPECTED(local_status != INHERITANCE_SUCCESS)) {
611 if (UNEXPECTED(local_status == INHERITANCE_ERROR)) {
612 return INHERITANCE_ERROR;
613 }
614 ZEND_ASSERT(local_status == INHERITANCE_UNRESOLVED);
615 status = INHERITANCE_UNRESOLVED;
616 }
617
618 /* by-ref constraints on arguments are invariant */
619 if (ZEND_ARG_SEND_MODE(fe_arg_info) != ZEND_ARG_SEND_MODE(proto_arg_info)) {
620 return INHERITANCE_ERROR;
621 }
622 }
623
624 /* Check return type compatibility, but only if the prototype already specifies
625 * a return type. Adding a new return type is always valid. */
626 if (proto->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
627 /* Removing a return type is not valid. */
628 if (!(fe->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE)) {
629 return INHERITANCE_ERROR;
630 }
631
632 local_status = zend_perform_covariant_type_check(
633 fe_scope, fe->common.arg_info[-1].type,
634 proto_scope, proto->common.arg_info[-1].type);
635
636 if (UNEXPECTED(local_status != INHERITANCE_SUCCESS)) {
637 if (UNEXPECTED(local_status == INHERITANCE_ERROR)) {
638 return INHERITANCE_ERROR;
639 }
640 ZEND_ASSERT(local_status == INHERITANCE_UNRESOLVED);
641 status = INHERITANCE_UNRESOLVED;
642 }
643 }
644
645 return status;
646 }
647 /* }}} */
648
zend_append_type_hint(smart_str * str,zend_class_entry * scope,zend_arg_info * arg_info,bool return_hint)649 static ZEND_COLD void zend_append_type_hint(
650 smart_str *str, zend_class_entry *scope, zend_arg_info *arg_info, bool return_hint) /* {{{ */
651 {
652 if (ZEND_TYPE_IS_SET(arg_info->type)) {
653 zend_string *type_str = zend_type_to_string_resolved(arg_info->type, scope);
654 smart_str_append(str, type_str);
655 zend_string_release(type_str);
656 if (!return_hint) {
657 smart_str_appendc(str, ' ');
658 }
659 }
660 }
661 /* }}} */
662
zend_get_function_declaration(const zend_function * fptr,zend_class_entry * scope)663 static ZEND_COLD zend_string *zend_get_function_declaration(
664 const zend_function *fptr, zend_class_entry *scope) /* {{{ */
665 {
666 smart_str str = {0};
667
668 if (fptr->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE) {
669 smart_str_appends(&str, "& ");
670 }
671
672 if (fptr->common.scope) {
673 /* cut off on NULL byte ... class@anonymous */
674 smart_str_appendl(&str, ZSTR_VAL(fptr->common.scope->name), strlen(ZSTR_VAL(fptr->common.scope->name)));
675 smart_str_appends(&str, "::");
676 }
677
678 smart_str_append(&str, fptr->common.function_name);
679 smart_str_appendc(&str, '(');
680
681 if (fptr->common.arg_info) {
682 uint32_t i, num_args, required;
683 zend_arg_info *arg_info = fptr->common.arg_info;
684
685 required = fptr->common.required_num_args;
686 num_args = fptr->common.num_args;
687 if (fptr->common.fn_flags & ZEND_ACC_VARIADIC) {
688 num_args++;
689 }
690 for (i = 0; i < num_args;) {
691 zend_append_type_hint(&str, scope, arg_info, 0);
692
693 if (ZEND_ARG_SEND_MODE(arg_info)) {
694 smart_str_appendc(&str, '&');
695 }
696
697 if (ZEND_ARG_IS_VARIADIC(arg_info)) {
698 smart_str_appends(&str, "...");
699 }
700
701 smart_str_appendc(&str, '$');
702 if (fptr->type == ZEND_INTERNAL_FUNCTION) {
703 smart_str_appends(&str, ((zend_internal_arg_info*)arg_info)->name);
704 } else {
705 smart_str_appendl(&str, ZSTR_VAL(arg_info->name), ZSTR_LEN(arg_info->name));
706 }
707
708 if (i >= required && !ZEND_ARG_IS_VARIADIC(arg_info)) {
709 smart_str_appends(&str, " = ");
710
711 if (fptr->type == ZEND_INTERNAL_FUNCTION) {
712 if (((zend_internal_arg_info*)arg_info)->default_value) {
713 smart_str_appends(&str, ((zend_internal_arg_info*)arg_info)->default_value);
714 } else {
715 smart_str_appends(&str, "<default>");
716 }
717 } else {
718 zend_op *precv = NULL;
719 {
720 uint32_t idx = i;
721 zend_op *op = fptr->op_array.opcodes;
722 zend_op *end = op + fptr->op_array.last;
723
724 ++idx;
725 while (op < end) {
726 if ((op->opcode == ZEND_RECV || op->opcode == ZEND_RECV_INIT)
727 && op->op1.num == (zend_ulong)idx)
728 {
729 precv = op;
730 }
731 ++op;
732 }
733 }
734 if (precv && precv->opcode == ZEND_RECV_INIT && precv->op2_type != IS_UNUSED) {
735 zval *zv = RT_CONSTANT(precv, precv->op2);
736
737 if (Z_TYPE_P(zv) == IS_FALSE) {
738 smart_str_appends(&str, "false");
739 } else if (Z_TYPE_P(zv) == IS_TRUE) {
740 smart_str_appends(&str, "true");
741 } else if (Z_TYPE_P(zv) == IS_NULL) {
742 smart_str_appends(&str, "null");
743 } else if (Z_TYPE_P(zv) == IS_STRING) {
744 smart_str_appendc(&str, '\'');
745 smart_str_appendl(&str, Z_STRVAL_P(zv), MIN(Z_STRLEN_P(zv), 10));
746 if (Z_STRLEN_P(zv) > 10) {
747 smart_str_appends(&str, "...");
748 }
749 smart_str_appendc(&str, '\'');
750 } else if (Z_TYPE_P(zv) == IS_ARRAY) {
751 if (zend_hash_num_elements(Z_ARRVAL_P(zv)) == 0) {
752 smart_str_appends(&str, "[]");
753 } else {
754 smart_str_appends(&str, "[...]");
755 }
756 } else if (Z_TYPE_P(zv) == IS_CONSTANT_AST) {
757 zend_ast *ast = Z_ASTVAL_P(zv);
758 if (ast->kind == ZEND_AST_CONSTANT) {
759 smart_str_append(&str, zend_ast_get_constant_name(ast));
760 } else {
761 smart_str_appends(&str, "<expression>");
762 }
763 } else {
764 zend_string *tmp_zv_str;
765 zend_string *zv_str = zval_get_tmp_string(zv, &tmp_zv_str);
766 smart_str_append(&str, zv_str);
767 zend_tmp_string_release(tmp_zv_str);
768 }
769 }
770 }
771 }
772
773 if (++i < num_args) {
774 smart_str_appends(&str, ", ");
775 }
776 arg_info++;
777 }
778 }
779
780 smart_str_appendc(&str, ')');
781
782 if (fptr->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
783 smart_str_appends(&str, ": ");
784 zend_append_type_hint(&str, scope, fptr->common.arg_info - 1, 1);
785 }
786 smart_str_0(&str);
787
788 return str.s;
789 }
790 /* }}} */
791
func_lineno(const zend_function * fn)792 static zend_always_inline uint32_t func_lineno(const zend_function *fn) {
793 return fn->common.type == ZEND_USER_FUNCTION ? fn->op_array.line_start : 0;
794 }
795
emit_incompatible_method_error(const zend_function * child,zend_class_entry * child_scope,const zend_function * parent,zend_class_entry * parent_scope,inheritance_status status)796 static void ZEND_COLD emit_incompatible_method_error(
797 const zend_function *child, zend_class_entry *child_scope,
798 const zend_function *parent, zend_class_entry *parent_scope,
799 inheritance_status status) {
800 zend_string *parent_prototype = zend_get_function_declaration(parent, parent_scope);
801 zend_string *child_prototype = zend_get_function_declaration(child, child_scope);
802 if (status == INHERITANCE_UNRESOLVED) {
803 /* Fetch the first unresolved class from registered autoloads */
804 zend_string *unresolved_class = NULL;
805 ZEND_HASH_FOREACH_STR_KEY(CG(delayed_autoloads), unresolved_class) {
806 break;
807 } ZEND_HASH_FOREACH_END();
808 ZEND_ASSERT(unresolved_class);
809
810 zend_error_at(E_COMPILE_ERROR, NULL, func_lineno(child),
811 "Could not check compatibility between %s and %s, because class %s is not available",
812 ZSTR_VAL(child_prototype), ZSTR_VAL(parent_prototype), ZSTR_VAL(unresolved_class));
813 } else {
814 zend_error_at(E_COMPILE_ERROR, NULL, func_lineno(child),
815 "Declaration of %s must be compatible with %s",
816 ZSTR_VAL(child_prototype), ZSTR_VAL(parent_prototype));
817 }
818 zend_string_efree(child_prototype);
819 zend_string_efree(parent_prototype);
820 }
821
perform_delayable_implementation_check(zend_class_entry * ce,const zend_function * fe,zend_class_entry * fe_scope,const zend_function * proto,zend_class_entry * proto_scope)822 static void perform_delayable_implementation_check(
823 zend_class_entry *ce,
824 const zend_function *fe, zend_class_entry *fe_scope,
825 const zend_function *proto, zend_class_entry *proto_scope)
826 {
827 inheritance_status status =
828 zend_do_perform_implementation_check(fe, fe_scope, proto, proto_scope);
829 if (UNEXPECTED(status != INHERITANCE_SUCCESS)) {
830 if (EXPECTED(status == INHERITANCE_UNRESOLVED)) {
831 add_compatibility_obligation(ce, fe, fe_scope, proto, proto_scope);
832 } else {
833 ZEND_ASSERT(status == INHERITANCE_ERROR);
834 emit_incompatible_method_error(fe, fe_scope, proto, proto_scope, status);
835 }
836 }
837 }
838
do_inheritance_check_on_method_ex(zend_function * child,zend_class_entry * child_scope,zend_function * parent,zend_class_entry * parent_scope,zend_class_entry * ce,zval * child_zv,zend_bool check_visibility,zend_bool check_only,zend_bool checked)839 static zend_always_inline inheritance_status do_inheritance_check_on_method_ex(
840 zend_function *child, zend_class_entry *child_scope,
841 zend_function *parent, zend_class_entry *parent_scope,
842 zend_class_entry *ce, zval *child_zv,
843 zend_bool check_visibility, zend_bool check_only, zend_bool checked) /* {{{ */
844 {
845 uint32_t child_flags;
846 uint32_t parent_flags = parent->common.fn_flags;
847 zend_function *proto;
848
849 if (UNEXPECTED((parent_flags & ZEND_ACC_PRIVATE) && !(parent_flags & ZEND_ACC_ABSTRACT) && !(parent_flags & ZEND_ACC_CTOR))) {
850 if (!check_only) {
851 child->common.fn_flags |= ZEND_ACC_CHANGED;
852 }
853 /* The parent method is private and not an abstract so we don't need to check any inheritance rules */
854 return INHERITANCE_SUCCESS;
855 }
856
857 if (!checked && UNEXPECTED(parent_flags & ZEND_ACC_FINAL)) {
858 if (check_only) {
859 return INHERITANCE_ERROR;
860 }
861 zend_error_at_noreturn(E_COMPILE_ERROR, NULL, func_lineno(child),
862 "Cannot override final method %s::%s()",
863 ZEND_FN_SCOPE_NAME(parent), ZSTR_VAL(child->common.function_name));
864 }
865
866 child_flags = child->common.fn_flags;
867 /* You cannot change from static to non static and vice versa.
868 */
869 if (!checked && UNEXPECTED((child_flags & ZEND_ACC_STATIC) != (parent_flags & ZEND_ACC_STATIC))) {
870 if (check_only) {
871 return INHERITANCE_ERROR;
872 }
873 if (child_flags & ZEND_ACC_STATIC) {
874 zend_error_at_noreturn(E_COMPILE_ERROR, NULL, func_lineno(child),
875 "Cannot make non static method %s::%s() static in class %s",
876 ZEND_FN_SCOPE_NAME(parent), ZSTR_VAL(child->common.function_name), ZEND_FN_SCOPE_NAME(child));
877 } else {
878 zend_error_at_noreturn(E_COMPILE_ERROR, NULL, func_lineno(child),
879 "Cannot make static method %s::%s() non static in class %s",
880 ZEND_FN_SCOPE_NAME(parent), ZSTR_VAL(child->common.function_name), ZEND_FN_SCOPE_NAME(child));
881 }
882 }
883
884 /* Disallow making an inherited method abstract. */
885 if (!checked && UNEXPECTED((child_flags & ZEND_ACC_ABSTRACT) > (parent_flags & ZEND_ACC_ABSTRACT))) {
886 if (check_only) {
887 return INHERITANCE_ERROR;
888 }
889 zend_error_at_noreturn(E_COMPILE_ERROR, NULL, func_lineno(child),
890 "Cannot make non abstract method %s::%s() abstract in class %s",
891 ZEND_FN_SCOPE_NAME(parent), ZSTR_VAL(child->common.function_name), ZEND_FN_SCOPE_NAME(child));
892 }
893
894 if (!check_only && (parent_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_CHANGED))) {
895 child->common.fn_flags |= ZEND_ACC_CHANGED;
896 }
897
898 proto = parent->common.prototype ?
899 parent->common.prototype : parent;
900
901 if (parent_flags & ZEND_ACC_CTOR) {
902 /* ctors only have a prototype if is abstract (or comes from an interface) */
903 /* and if that is the case, we want to check inheritance against it */
904 if (!(proto->common.fn_flags & ZEND_ACC_ABSTRACT)) {
905 return INHERITANCE_SUCCESS;
906 }
907 parent = proto;
908 }
909
910 if (!check_only && child->common.prototype != proto && child_zv) {
911 do {
912 if (child->common.scope != ce
913 && child->type == ZEND_USER_FUNCTION
914 && !child->op_array.static_variables) {
915 if (ce->ce_flags & ZEND_ACC_INTERFACE) {
916 /* Few parent interfaces contain the same method */
917 break;
918 } else {
919 /* op_array wasn't duplicated yet */
920 zend_function *new_function = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
921 memcpy(new_function, child, sizeof(zend_op_array));
922 Z_PTR_P(child_zv) = child = new_function;
923 }
924 }
925 child->common.prototype = proto;
926 } while (0);
927 }
928
929 /* Prevent derived classes from restricting access that was available in parent classes (except deriving from non-abstract ctors) */
930 if (!checked && check_visibility
931 && (child_flags & ZEND_ACC_PPP_MASK) > (parent_flags & ZEND_ACC_PPP_MASK)) {
932 if (check_only) {
933 return INHERITANCE_ERROR;
934 }
935 zend_error_at_noreturn(E_COMPILE_ERROR, NULL, func_lineno(child),
936 "Access level to %s::%s() must be %s (as in class %s)%s",
937 ZEND_FN_SCOPE_NAME(child), ZSTR_VAL(child->common.function_name), zend_visibility_string(parent_flags), ZEND_FN_SCOPE_NAME(parent), (parent_flags&ZEND_ACC_PUBLIC) ? "" : " or weaker");
938 }
939
940 if (!checked) {
941 if (check_only) {
942 return zend_do_perform_implementation_check(child, child_scope, parent, parent_scope);
943 }
944 perform_delayable_implementation_check(ce, child, child_scope, parent, parent_scope);
945 }
946 return INHERITANCE_SUCCESS;
947 }
948 /* }}} */
949
do_inheritance_check_on_method(zend_function * child,zend_class_entry * child_scope,zend_function * parent,zend_class_entry * parent_scope,zend_class_entry * ce,zval * child_zv,zend_bool check_visibility)950 static zend_never_inline void do_inheritance_check_on_method(
951 zend_function *child, zend_class_entry *child_scope,
952 zend_function *parent, zend_class_entry *parent_scope,
953 zend_class_entry *ce, zval *child_zv, zend_bool check_visibility)
954 {
955 do_inheritance_check_on_method_ex(child, child_scope, parent, parent_scope, ce, child_zv, check_visibility, 0, 0);
956 }
957
do_inherit_method(zend_string * key,zend_function * parent,zend_class_entry * ce,zend_bool is_interface,zend_bool checked)958 static zend_always_inline void do_inherit_method(zend_string *key, zend_function *parent, zend_class_entry *ce, zend_bool is_interface, zend_bool checked) /* {{{ */
959 {
960 zval *child = zend_hash_find_ex(&ce->function_table, key, 1);
961
962 if (child) {
963 zend_function *func = (zend_function*)Z_PTR_P(child);
964
965 if (is_interface && UNEXPECTED(func == parent)) {
966 /* The same method in interface may be inherited few times */
967 return;
968 }
969
970 if (checked) {
971 do_inheritance_check_on_method_ex(
972 func, func->common.scope, parent, parent->common.scope, ce, child,
973 /* check_visibility */ 1, 0, checked);
974 } else {
975 do_inheritance_check_on_method(
976 func, func->common.scope, parent, parent->common.scope, ce, child,
977 /* check_visibility */ 1);
978 }
979 } else {
980
981 if (is_interface || (parent->common.fn_flags & (ZEND_ACC_ABSTRACT))) {
982 ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
983 }
984
985 parent = zend_duplicate_function(parent, ce, is_interface);
986
987 if (!is_interface) {
988 _zend_hash_append_ptr(&ce->function_table, key, parent);
989 } else {
990 zend_hash_add_new_ptr(&ce->function_table, key, parent);
991 }
992 }
993 }
994 /* }}} */
995
property_types_compatible(const zend_property_info * parent_info,const zend_property_info * child_info)996 inheritance_status property_types_compatible(
997 const zend_property_info *parent_info, const zend_property_info *child_info) {
998 if (ZEND_TYPE_PURE_MASK(parent_info->type) == ZEND_TYPE_PURE_MASK(child_info->type)
999 && ZEND_TYPE_NAME(parent_info->type) == ZEND_TYPE_NAME(child_info->type)) {
1000 return INHERITANCE_SUCCESS;
1001 }
1002
1003 if (ZEND_TYPE_IS_SET(parent_info->type) != ZEND_TYPE_IS_SET(child_info->type)) {
1004 return INHERITANCE_ERROR;
1005 }
1006
1007 /* Perform a covariant type check in both directions to determined invariance. */
1008 inheritance_status status1 = zend_perform_covariant_type_check(
1009 child_info->ce, child_info->type, parent_info->ce, parent_info->type);
1010 inheritance_status status2 = zend_perform_covariant_type_check(
1011 parent_info->ce, parent_info->type, child_info->ce, child_info->type);
1012 if (status1 == INHERITANCE_SUCCESS && status2 == INHERITANCE_SUCCESS) {
1013 return INHERITANCE_SUCCESS;
1014 }
1015 if (status1 == INHERITANCE_ERROR || status2 == INHERITANCE_ERROR) {
1016 return INHERITANCE_ERROR;
1017 }
1018 ZEND_ASSERT(status1 == INHERITANCE_UNRESOLVED || status2 == INHERITANCE_UNRESOLVED);
1019 return INHERITANCE_UNRESOLVED;
1020 }
1021
emit_incompatible_property_error(const zend_property_info * child,const zend_property_info * parent)1022 static void emit_incompatible_property_error(
1023 const zend_property_info *child, const zend_property_info *parent) {
1024 zend_string *type_str = zend_type_to_string_resolved(parent->type, parent->ce);
1025 zend_error_noreturn(E_COMPILE_ERROR,
1026 "Type of %s::$%s must be %s (as in class %s)",
1027 ZSTR_VAL(child->ce->name),
1028 zend_get_unmangled_property_name(child->name),
1029 ZSTR_VAL(type_str),
1030 ZSTR_VAL(parent->ce->name));
1031 }
1032
do_inherit_property(zend_property_info * parent_info,zend_string * key,zend_class_entry * ce)1033 static void do_inherit_property(zend_property_info *parent_info, zend_string *key, zend_class_entry *ce) /* {{{ */
1034 {
1035 zval *child = zend_hash_find_ex(&ce->properties_info, key, 1);
1036 zend_property_info *child_info;
1037
1038 if (UNEXPECTED(child)) {
1039 child_info = Z_PTR_P(child);
1040 if (parent_info->flags & (ZEND_ACC_PRIVATE|ZEND_ACC_CHANGED)) {
1041 child_info->flags |= ZEND_ACC_CHANGED;
1042 }
1043 if (!(parent_info->flags & ZEND_ACC_PRIVATE)) {
1044 if (UNEXPECTED((parent_info->flags & ZEND_ACC_STATIC) != (child_info->flags & ZEND_ACC_STATIC))) {
1045 zend_error_noreturn(E_COMPILE_ERROR, "Cannot redeclare %s%s::$%s as %s%s::$%s",
1046 (parent_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", ZSTR_VAL(parent_info->ce->name), ZSTR_VAL(key),
1047 (child_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", ZSTR_VAL(ce->name), ZSTR_VAL(key));
1048 }
1049
1050 if (UNEXPECTED((child_info->flags & ZEND_ACC_PPP_MASK) > (parent_info->flags & ZEND_ACC_PPP_MASK))) {
1051 zend_error_noreturn(E_COMPILE_ERROR, "Access level to %s::$%s must be %s (as in class %s)%s", ZSTR_VAL(ce->name), ZSTR_VAL(key), zend_visibility_string(parent_info->flags), ZSTR_VAL(parent_info->ce->name), (parent_info->flags&ZEND_ACC_PUBLIC) ? "" : " or weaker");
1052 } else if ((child_info->flags & ZEND_ACC_STATIC) == 0) {
1053 int parent_num = OBJ_PROP_TO_NUM(parent_info->offset);
1054 int child_num = OBJ_PROP_TO_NUM(child_info->offset);
1055
1056 /* Don't keep default properties in GC (they may be freed by opcache) */
1057 zval_ptr_dtor_nogc(&(ce->default_properties_table[parent_num]));
1058 ce->default_properties_table[parent_num] = ce->default_properties_table[child_num];
1059 ZVAL_UNDEF(&ce->default_properties_table[child_num]);
1060 child_info->offset = parent_info->offset;
1061 }
1062
1063 if (UNEXPECTED(ZEND_TYPE_IS_SET(parent_info->type))) {
1064 inheritance_status status = property_types_compatible(parent_info, child_info);
1065 if (status == INHERITANCE_ERROR) {
1066 emit_incompatible_property_error(child_info, parent_info);
1067 }
1068 if (status == INHERITANCE_UNRESOLVED) {
1069 add_property_compatibility_obligation(ce, child_info, parent_info);
1070 }
1071 } else if (UNEXPECTED(ZEND_TYPE_IS_SET(child_info->type) && !ZEND_TYPE_IS_SET(parent_info->type))) {
1072 zend_error_noreturn(E_COMPILE_ERROR,
1073 "Type of %s::$%s must not be defined (as in class %s)",
1074 ZSTR_VAL(ce->name),
1075 ZSTR_VAL(key),
1076 ZSTR_VAL(parent_info->ce->name));
1077 }
1078 }
1079 } else {
1080 if (UNEXPECTED(ce->type & ZEND_INTERNAL_CLASS)) {
1081 child_info = zend_duplicate_property_info_internal(parent_info);
1082 } else {
1083 child_info = parent_info;
1084 }
1085 _zend_hash_append_ptr(&ce->properties_info, key, child_info);
1086 }
1087 }
1088 /* }}} */
1089
do_implement_interface(zend_class_entry * ce,zend_class_entry * iface)1090 static inline void do_implement_interface(zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
1091 {
1092 if (!(ce->ce_flags & ZEND_ACC_INTERFACE) && iface->interface_gets_implemented && iface->interface_gets_implemented(iface, ce) == FAILURE) {
1093 zend_error_noreturn(E_CORE_ERROR, "Class %s could not implement interface %s", ZSTR_VAL(ce->name), ZSTR_VAL(iface->name));
1094 }
1095 /* This should be prevented by the class lookup logic. */
1096 ZEND_ASSERT(ce != iface);
1097 }
1098 /* }}} */
1099
zend_do_inherit_interfaces(zend_class_entry * ce,const zend_class_entry * iface)1100 static void zend_do_inherit_interfaces(zend_class_entry *ce, const zend_class_entry *iface) /* {{{ */
1101 {
1102 /* expects interface to be contained in ce's interface list already */
1103 uint32_t i, ce_num, if_num = iface->num_interfaces;
1104 zend_class_entry *entry;
1105
1106 ce_num = ce->num_interfaces;
1107
1108 if (ce->type == ZEND_INTERNAL_CLASS) {
1109 ce->interfaces = (zend_class_entry **) realloc(ce->interfaces, sizeof(zend_class_entry *) * (ce_num + if_num));
1110 } else {
1111 ce->interfaces = (zend_class_entry **) erealloc(ce->interfaces, sizeof(zend_class_entry *) * (ce_num + if_num));
1112 }
1113
1114 /* Inherit the interfaces, only if they're not already inherited by the class */
1115 while (if_num--) {
1116 entry = iface->interfaces[if_num];
1117 for (i = 0; i < ce_num; i++) {
1118 if (ce->interfaces[i] == entry) {
1119 break;
1120 }
1121 }
1122 if (i == ce_num) {
1123 ce->interfaces[ce->num_interfaces++] = entry;
1124 }
1125 }
1126 ce->ce_flags |= ZEND_ACC_RESOLVED_INTERFACES;
1127
1128 /* and now call the implementing handlers */
1129 while (ce_num < ce->num_interfaces) {
1130 do_implement_interface(ce, ce->interfaces[ce_num++]);
1131 }
1132 }
1133 /* }}} */
1134
do_inherit_class_constant(zend_string * name,zend_class_constant * parent_const,zend_class_entry * ce)1135 static void do_inherit_class_constant(zend_string *name, zend_class_constant *parent_const, zend_class_entry *ce) /* {{{ */
1136 {
1137 zval *zv = zend_hash_find_ex(&ce->constants_table, name, 1);
1138 zend_class_constant *c;
1139
1140 if (zv != NULL) {
1141 c = (zend_class_constant*)Z_PTR_P(zv);
1142 if (UNEXPECTED((Z_ACCESS_FLAGS(c->value) & ZEND_ACC_PPP_MASK) > (Z_ACCESS_FLAGS(parent_const->value) & ZEND_ACC_PPP_MASK))) {
1143 zend_error_noreturn(E_COMPILE_ERROR, "Access level to %s::%s must be %s (as in class %s)%s",
1144 ZSTR_VAL(ce->name), ZSTR_VAL(name), zend_visibility_string(Z_ACCESS_FLAGS(parent_const->value)), ZSTR_VAL(parent_const->ce->name), (Z_ACCESS_FLAGS(parent_const->value) & ZEND_ACC_PUBLIC) ? "" : " or weaker");
1145 }
1146 } else if (!(Z_ACCESS_FLAGS(parent_const->value) & ZEND_ACC_PRIVATE)) {
1147 if (Z_TYPE(parent_const->value) == IS_CONSTANT_AST) {
1148 ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
1149 }
1150 if (ce->type & ZEND_INTERNAL_CLASS) {
1151 c = pemalloc(sizeof(zend_class_constant), 1);
1152 memcpy(c, parent_const, sizeof(zend_class_constant));
1153 parent_const = c;
1154 }
1155 _zend_hash_append_ptr(&ce->constants_table, name, parent_const);
1156 }
1157 }
1158 /* }}} */
1159
zend_build_properties_info_table(zend_class_entry * ce)1160 void zend_build_properties_info_table(zend_class_entry *ce)
1161 {
1162 zend_property_info **table, *prop;
1163 size_t size;
1164 if (ce->default_properties_count == 0) {
1165 return;
1166 }
1167
1168 ZEND_ASSERT(ce->properties_info_table == NULL);
1169 size = sizeof(zend_property_info *) * ce->default_properties_count;
1170 if (ce->type == ZEND_USER_CLASS) {
1171 ce->properties_info_table = table = zend_arena_alloc(&CG(arena), size);
1172 } else {
1173 ce->properties_info_table = table = pemalloc(size, 1);
1174 }
1175
1176 /* Dead slots may be left behind during inheritance. Make sure these are NULLed out. */
1177 memset(table, 0, size);
1178
1179 if (ce->parent && ce->parent->default_properties_count != 0) {
1180 zend_property_info **parent_table = ce->parent->properties_info_table;
1181 memcpy(
1182 table, parent_table,
1183 sizeof(zend_property_info *) * ce->parent->default_properties_count
1184 );
1185
1186 /* Child did not add any new properties, we are done */
1187 if (ce->default_properties_count == ce->parent->default_properties_count) {
1188 return;
1189 }
1190 }
1191
1192 ZEND_HASH_FOREACH_PTR(&ce->properties_info, prop) {
1193 if (prop->ce == ce && (prop->flags & ZEND_ACC_STATIC) == 0) {
1194 table[OBJ_PROP_TO_NUM(prop->offset)] = prop;
1195 }
1196 } ZEND_HASH_FOREACH_END();
1197 }
1198
zend_do_inheritance_ex(zend_class_entry * ce,zend_class_entry * parent_ce,zend_bool checked)1199 ZEND_API void zend_do_inheritance_ex(zend_class_entry *ce, zend_class_entry *parent_ce, zend_bool checked) /* {{{ */
1200 {
1201 zend_property_info *property_info;
1202 zend_function *func;
1203 zend_string *key;
1204
1205 if (UNEXPECTED(ce->ce_flags & ZEND_ACC_INTERFACE)) {
1206 /* Interface can only inherit other interfaces */
1207 if (UNEXPECTED(!(parent_ce->ce_flags & ZEND_ACC_INTERFACE))) {
1208 zend_error_noreturn(E_COMPILE_ERROR, "Interface %s may not inherit from class (%s)", ZSTR_VAL(ce->name), ZSTR_VAL(parent_ce->name));
1209 }
1210 } else if (UNEXPECTED(parent_ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT|ZEND_ACC_FINAL))) {
1211 /* Class declaration must not extend traits or interfaces */
1212 if (parent_ce->ce_flags & ZEND_ACC_INTERFACE) {
1213 zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot extend from interface %s", ZSTR_VAL(ce->name), ZSTR_VAL(parent_ce->name));
1214 } else if (parent_ce->ce_flags & ZEND_ACC_TRAIT) {
1215 zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot extend from trait %s", ZSTR_VAL(ce->name), ZSTR_VAL(parent_ce->name));
1216 }
1217
1218 /* Class must not extend a final class */
1219 if (parent_ce->ce_flags & ZEND_ACC_FINAL) {
1220 zend_error_noreturn(E_COMPILE_ERROR, "Class %s may not inherit from final class (%s)", ZSTR_VAL(ce->name), ZSTR_VAL(parent_ce->name));
1221 }
1222 }
1223
1224 if (ce->parent_name) {
1225 zend_string_release_ex(ce->parent_name, 0);
1226 }
1227 ce->parent = parent_ce;
1228 ce->ce_flags |= ZEND_ACC_RESOLVED_PARENT;
1229
1230 /* Inherit properties */
1231 if (parent_ce->default_properties_count) {
1232 zval *src, *dst, *end;
1233
1234 if (ce->default_properties_count) {
1235 zval *table = pemalloc(sizeof(zval) * (ce->default_properties_count + parent_ce->default_properties_count), ce->type == ZEND_INTERNAL_CLASS);
1236 src = ce->default_properties_table + ce->default_properties_count;
1237 end = table + parent_ce->default_properties_count;
1238 dst = end + ce->default_properties_count;
1239 ce->default_properties_table = table;
1240 do {
1241 dst--;
1242 src--;
1243 ZVAL_COPY_VALUE_PROP(dst, src);
1244 } while (dst != end);
1245 pefree(src, ce->type == ZEND_INTERNAL_CLASS);
1246 end = ce->default_properties_table;
1247 } else {
1248 end = pemalloc(sizeof(zval) * parent_ce->default_properties_count, ce->type == ZEND_INTERNAL_CLASS);
1249 dst = end + parent_ce->default_properties_count;
1250 ce->default_properties_table = end;
1251 }
1252 src = parent_ce->default_properties_table + parent_ce->default_properties_count;
1253 if (UNEXPECTED(parent_ce->type != ce->type)) {
1254 /* User class extends internal */
1255 do {
1256 dst--;
1257 src--;
1258 ZVAL_COPY_OR_DUP_PROP(dst, src);
1259 if (Z_OPT_TYPE_P(dst) == IS_CONSTANT_AST) {
1260 ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
1261 }
1262 continue;
1263 } while (dst != end);
1264 } else {
1265 do {
1266 dst--;
1267 src--;
1268 ZVAL_COPY_PROP(dst, src);
1269 if (Z_OPT_TYPE_P(dst) == IS_CONSTANT_AST) {
1270 ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
1271 }
1272 continue;
1273 } while (dst != end);
1274 }
1275 ce->default_properties_count += parent_ce->default_properties_count;
1276 }
1277
1278 if (parent_ce->default_static_members_count) {
1279 zval *src, *dst, *end;
1280
1281 if (ce->default_static_members_count) {
1282 zval *table = pemalloc(sizeof(zval) * (ce->default_static_members_count + parent_ce->default_static_members_count), ce->type == ZEND_INTERNAL_CLASS);
1283 src = ce->default_static_members_table + ce->default_static_members_count;
1284 end = table + parent_ce->default_static_members_count;
1285 dst = end + ce->default_static_members_count;
1286 ce->default_static_members_table = table;
1287 do {
1288 dst--;
1289 src--;
1290 ZVAL_COPY_VALUE(dst, src);
1291 } while (dst != end);
1292 pefree(src, ce->type == ZEND_INTERNAL_CLASS);
1293 end = ce->default_static_members_table;
1294 } else {
1295 end = pemalloc(sizeof(zval) * parent_ce->default_static_members_count, ce->type == ZEND_INTERNAL_CLASS);
1296 dst = end + parent_ce->default_static_members_count;
1297 ce->default_static_members_table = end;
1298 }
1299 if (UNEXPECTED(parent_ce->type != ce->type)) {
1300 /* User class extends internal */
1301 if (CE_STATIC_MEMBERS(parent_ce) == NULL) {
1302 zend_class_init_statics(parent_ce);
1303 }
1304 if (UNEXPECTED(zend_update_class_constants(parent_ce) != SUCCESS)) {
1305 ZEND_UNREACHABLE();
1306 }
1307 src = CE_STATIC_MEMBERS(parent_ce) + parent_ce->default_static_members_count;
1308 do {
1309 dst--;
1310 src--;
1311 if (Z_TYPE_P(src) == IS_INDIRECT) {
1312 ZVAL_INDIRECT(dst, Z_INDIRECT_P(src));
1313 } else {
1314 ZVAL_INDIRECT(dst, src);
1315 }
1316 } while (dst != end);
1317 } else if (ce->type == ZEND_USER_CLASS) {
1318 if (CE_STATIC_MEMBERS(parent_ce) == NULL) {
1319 ZEND_ASSERT(parent_ce->ce_flags & (ZEND_ACC_IMMUTABLE|ZEND_ACC_PRELOADED));
1320 zend_class_init_statics(parent_ce);
1321 }
1322 src = CE_STATIC_MEMBERS(parent_ce) + parent_ce->default_static_members_count;
1323 do {
1324 dst--;
1325 src--;
1326 if (Z_TYPE_P(src) == IS_INDIRECT) {
1327 ZVAL_INDIRECT(dst, Z_INDIRECT_P(src));
1328 } else {
1329 ZVAL_INDIRECT(dst, src);
1330 }
1331 if (Z_TYPE_P(Z_INDIRECT_P(dst)) == IS_CONSTANT_AST) {
1332 ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
1333 }
1334 } while (dst != end);
1335 } else {
1336 src = parent_ce->default_static_members_table + parent_ce->default_static_members_count;
1337 do {
1338 dst--;
1339 src--;
1340 if (Z_TYPE_P(src) == IS_INDIRECT) {
1341 ZVAL_INDIRECT(dst, Z_INDIRECT_P(src));
1342 } else {
1343 ZVAL_INDIRECT(dst, src);
1344 }
1345 } while (dst != end);
1346 }
1347 ce->default_static_members_count += parent_ce->default_static_members_count;
1348 if (!ZEND_MAP_PTR(ce->static_members_table)) {
1349 ZEND_ASSERT(ce->type == ZEND_INTERNAL_CLASS);
1350 if (!EG(current_execute_data)) {
1351 ZEND_MAP_PTR_NEW(ce->static_members_table);
1352 } else {
1353 /* internal class loaded by dl() */
1354 ZEND_MAP_PTR_INIT(ce->static_members_table, &ce->default_static_members_table);
1355 }
1356 }
1357 }
1358
1359 ZEND_HASH_FOREACH_PTR(&ce->properties_info, property_info) {
1360 if (property_info->ce == ce) {
1361 if (property_info->flags & ZEND_ACC_STATIC) {
1362 property_info->offset += parent_ce->default_static_members_count;
1363 } else {
1364 property_info->offset += parent_ce->default_properties_count * sizeof(zval);
1365 }
1366 }
1367 } ZEND_HASH_FOREACH_END();
1368
1369 if (zend_hash_num_elements(&parent_ce->properties_info)) {
1370 zend_hash_extend(&ce->properties_info,
1371 zend_hash_num_elements(&ce->properties_info) +
1372 zend_hash_num_elements(&parent_ce->properties_info), 0);
1373
1374 ZEND_HASH_FOREACH_STR_KEY_PTR(&parent_ce->properties_info, key, property_info) {
1375 do_inherit_property(property_info, key, ce);
1376 } ZEND_HASH_FOREACH_END();
1377 }
1378
1379 if (zend_hash_num_elements(&parent_ce->constants_table)) {
1380 zend_class_constant *c;
1381
1382 zend_hash_extend(&ce->constants_table,
1383 zend_hash_num_elements(&ce->constants_table) +
1384 zend_hash_num_elements(&parent_ce->constants_table), 0);
1385
1386 ZEND_HASH_FOREACH_STR_KEY_PTR(&parent_ce->constants_table, key, c) {
1387 do_inherit_class_constant(key, c, ce);
1388 } ZEND_HASH_FOREACH_END();
1389 }
1390
1391 if (zend_hash_num_elements(&parent_ce->function_table)) {
1392 zend_hash_extend(&ce->function_table,
1393 zend_hash_num_elements(&ce->function_table) +
1394 zend_hash_num_elements(&parent_ce->function_table), 0);
1395
1396 if (checked) {
1397 ZEND_HASH_FOREACH_STR_KEY_PTR(&parent_ce->function_table, key, func) {
1398 do_inherit_method(key, func, ce, 0, 1);
1399 } ZEND_HASH_FOREACH_END();
1400 } else {
1401 ZEND_HASH_FOREACH_STR_KEY_PTR(&parent_ce->function_table, key, func) {
1402 do_inherit_method(key, func, ce, 0, 0);
1403 } ZEND_HASH_FOREACH_END();
1404 }
1405 }
1406
1407 do_inherit_parent_constructor(ce);
1408
1409 if (ce->type == ZEND_INTERNAL_CLASS) {
1410 if (parent_ce->num_interfaces) {
1411 zend_do_inherit_interfaces(ce, parent_ce);
1412 }
1413
1414 if (ce->ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) {
1415 ce->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS;
1416 }
1417 }
1418 ce->ce_flags |= parent_ce->ce_flags & (ZEND_HAS_STATIC_IN_METHODS | ZEND_ACC_HAS_TYPE_HINTS | ZEND_ACC_USE_GUARDS);
1419 }
1420 /* }}} */
1421
do_inherit_constant_check(HashTable * child_constants_table,zend_class_constant * parent_constant,zend_string * name,const zend_class_entry * iface)1422 static zend_bool do_inherit_constant_check(HashTable *child_constants_table, zend_class_constant *parent_constant, zend_string *name, const zend_class_entry *iface) /* {{{ */
1423 {
1424 zval *zv = zend_hash_find_ex(child_constants_table, name, 1);
1425 zend_class_constant *old_constant;
1426
1427 if (zv != NULL) {
1428 old_constant = (zend_class_constant*)Z_PTR_P(zv);
1429 if (old_constant->ce != parent_constant->ce) {
1430 zend_error_noreturn(E_COMPILE_ERROR, "Cannot inherit previously-inherited or override constant %s from interface %s", ZSTR_VAL(name), ZSTR_VAL(iface->name));
1431 }
1432 return 0;
1433 }
1434 return 1;
1435 }
1436 /* }}} */
1437
do_inherit_iface_constant(zend_string * name,zend_class_constant * c,zend_class_entry * ce,zend_class_entry * iface)1438 static void do_inherit_iface_constant(zend_string *name, zend_class_constant *c, zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
1439 {
1440 if (do_inherit_constant_check(&ce->constants_table, c, name, iface)) {
1441 zend_class_constant *ct;
1442 if (Z_TYPE(c->value) == IS_CONSTANT_AST) {
1443 ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
1444 }
1445 if (ce->type & ZEND_INTERNAL_CLASS) {
1446 ct = pemalloc(sizeof(zend_class_constant), 1);
1447 memcpy(ct, c, sizeof(zend_class_constant));
1448 c = ct;
1449 }
1450 zend_hash_update_ptr(&ce->constants_table, name, c);
1451 }
1452 }
1453 /* }}} */
1454
do_interface_implementation(zend_class_entry * ce,zend_class_entry * iface)1455 static void do_interface_implementation(zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
1456 {
1457 zend_function *func;
1458 zend_string *key;
1459 zend_class_constant *c;
1460
1461 ZEND_HASH_FOREACH_STR_KEY_PTR(&iface->constants_table, key, c) {
1462 do_inherit_iface_constant(key, c, ce, iface);
1463 } ZEND_HASH_FOREACH_END();
1464
1465 ZEND_HASH_FOREACH_STR_KEY_PTR(&iface->function_table, key, func) {
1466 do_inherit_method(key, func, ce, 1, 0);
1467 } ZEND_HASH_FOREACH_END();
1468
1469 do_implement_interface(ce, iface);
1470 if (iface->num_interfaces) {
1471 zend_do_inherit_interfaces(ce, iface);
1472 }
1473 }
1474 /* }}} */
1475
zend_do_implement_interface(zend_class_entry * ce,zend_class_entry * iface)1476 ZEND_API void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry *iface) /* {{{ */
1477 {
1478 uint32_t i, ignore = 0;
1479 uint32_t current_iface_num = ce->num_interfaces;
1480 uint32_t parent_iface_num = ce->parent ? ce->parent->num_interfaces : 0;
1481 zend_string *key;
1482 zend_class_constant *c;
1483
1484 ZEND_ASSERT(ce->ce_flags & ZEND_ACC_LINKED);
1485
1486 for (i = 0; i < ce->num_interfaces; i++) {
1487 if (ce->interfaces[i] == NULL) {
1488 memmove(ce->interfaces + i, ce->interfaces + i + 1, sizeof(zend_class_entry*) * (--ce->num_interfaces - i));
1489 i--;
1490 } else if (ce->interfaces[i] == iface) {
1491 if (EXPECTED(i < parent_iface_num)) {
1492 ignore = 1;
1493 } else {
1494 zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot implement previously implemented interface %s", ZSTR_VAL(ce->name), ZSTR_VAL(iface->name));
1495 }
1496 }
1497 }
1498 if (ignore) {
1499 /* Check for attempt to redeclare interface constants */
1500 ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->constants_table, key, c) {
1501 do_inherit_constant_check(&iface->constants_table, c, key, iface);
1502 } ZEND_HASH_FOREACH_END();
1503 } else {
1504 if (ce->num_interfaces >= current_iface_num) {
1505 if (ce->type == ZEND_INTERNAL_CLASS) {
1506 ce->interfaces = (zend_class_entry **) realloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num));
1507 } else {
1508 ce->interfaces = (zend_class_entry **) erealloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num));
1509 }
1510 }
1511 ce->interfaces[ce->num_interfaces++] = iface;
1512
1513 do_interface_implementation(ce, iface);
1514 }
1515 }
1516 /* }}} */
1517
zend_do_implement_interfaces(zend_class_entry * ce,zend_class_entry ** interfaces)1518 static void zend_do_implement_interfaces(zend_class_entry *ce, zend_class_entry **interfaces) /* {{{ */
1519 {
1520 zend_class_entry *iface;
1521 uint32_t num_parent_interfaces = ce->parent ? ce->parent->num_interfaces : 0;
1522 uint32_t num_interfaces = num_parent_interfaces;
1523 zend_string *key;
1524 zend_class_constant *c;
1525 uint32_t i, j;
1526
1527 for (i = 0; i < ce->num_interfaces; i++) {
1528 iface = interfaces[num_parent_interfaces + i];
1529 if (!(iface->ce_flags & ZEND_ACC_LINKED)) {
1530 add_dependency_obligation(ce, iface);
1531 }
1532 if (UNEXPECTED(!(iface->ce_flags & ZEND_ACC_INTERFACE))) {
1533 efree(interfaces);
1534 zend_error_noreturn(E_ERROR, "%s cannot implement %s - it is not an interface", ZSTR_VAL(ce->name), ZSTR_VAL(iface->name));
1535 return;
1536 }
1537 for (j = 0; j < num_interfaces; j++) {
1538 if (interfaces[j] == iface) {
1539 if (j >= num_parent_interfaces) {
1540 efree(interfaces);
1541 zend_error_noreturn(E_COMPILE_ERROR, "Class %s cannot implement previously implemented interface %s", ZSTR_VAL(ce->name), ZSTR_VAL(iface->name));
1542 return;
1543 }
1544 /* skip duplications */
1545 ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->constants_table, key, c) {
1546 do_inherit_constant_check(&iface->constants_table, c, key, iface);
1547 } ZEND_HASH_FOREACH_END();
1548
1549 iface = NULL;
1550 break;
1551 }
1552 }
1553 if (iface) {
1554 interfaces[num_interfaces] = iface;
1555 num_interfaces++;
1556 }
1557 }
1558
1559 for (i = 0; i < ce->num_interfaces; i++) {
1560 zend_string_release_ex(ce->interface_names[i].name, 0);
1561 zend_string_release_ex(ce->interface_names[i].lc_name, 0);
1562 }
1563 efree(ce->interface_names);
1564
1565 ce->num_interfaces = num_interfaces;
1566 ce->interfaces = interfaces;
1567 ce->ce_flags |= ZEND_ACC_RESOLVED_INTERFACES;
1568
1569 for (i = 0; i < num_parent_interfaces; i++) {
1570 do_implement_interface(ce, ce->interfaces[i]);
1571 }
1572 /* Note that new interfaces can be added during this loop due to interface inheritance.
1573 * Use num_interfaces rather than ce->num_interfaces to not re-process the new ones. */
1574 for (; i < num_interfaces; i++) {
1575 do_interface_implementation(ce, ce->interfaces[i]);
1576 }
1577 }
1578 /* }}} */
1579
fixup_trait_scope(const zend_function * fn,zend_class_entry * ce)1580 static zend_class_entry *fixup_trait_scope(const zend_function *fn, zend_class_entry *ce)
1581 {
1582 /* self in trait methods should be resolved to the using class, not the trait. */
1583 return fn->common.scope->ce_flags & ZEND_ACC_TRAIT ? ce : fn->common.scope;
1584 }
1585
zend_add_trait_method(zend_class_entry * ce,zend_string * name,zend_string * key,zend_function * fn)1586 static void zend_add_trait_method(zend_class_entry *ce, zend_string *name, zend_string *key, zend_function *fn) /* {{{ */
1587 {
1588 zend_function *existing_fn = NULL;
1589 zend_function *new_fn;
1590
1591 if ((existing_fn = zend_hash_find_ptr(&ce->function_table, key)) != NULL) {
1592 /* if it is the same function with the same visibility and has not been assigned a class scope yet, regardless
1593 * of where it is coming from there is no conflict and we do not need to add it again */
1594 if (existing_fn->op_array.opcodes == fn->op_array.opcodes &&
1595 (existing_fn->common.fn_flags & ZEND_ACC_PPP_MASK) == (fn->common.fn_flags & ZEND_ACC_PPP_MASK) &&
1596 (existing_fn->common.scope->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) {
1597 return;
1598 }
1599
1600 /* Abstract method signatures from the trait must be satisfied. */
1601 if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
1602 /* "abstract private" methods in traits were not available prior to PHP 8.
1603 * As such, "abstract protected" was sometimes used to indicate trait requirements,
1604 * even though the "implementing" method was private. Do not check visibility
1605 * requirements to maintain backwards-compatibility with such usage.
1606 */
1607 do_inheritance_check_on_method(
1608 existing_fn, fixup_trait_scope(existing_fn, ce), fn, fixup_trait_scope(fn, ce),
1609 ce, NULL, /* check_visibility */ 0);
1610 return;
1611 }
1612
1613 if (existing_fn->common.scope == ce) {
1614 /* members from the current class override trait methods */
1615 return;
1616 } else if (UNEXPECTED((existing_fn->common.scope->ce_flags & ZEND_ACC_TRAIT)
1617 && !(existing_fn->common.fn_flags & ZEND_ACC_ABSTRACT))) {
1618 /* two traits can't define the same non-abstract method */
1619 zend_error_noreturn(E_COMPILE_ERROR, "Trait method %s::%s has not been applied as %s::%s, because of collision with %s::%s",
1620 ZSTR_VAL(fn->common.scope->name), ZSTR_VAL(fn->common.function_name),
1621 ZSTR_VAL(ce->name), ZSTR_VAL(name),
1622 ZSTR_VAL(existing_fn->common.scope->name), ZSTR_VAL(existing_fn->common.function_name));
1623 } else {
1624 /* Inherited members are overridden by members inserted by traits.
1625 * Check whether the trait method fulfills the inheritance requirements. */
1626 do_inheritance_check_on_method(
1627 fn, fixup_trait_scope(fn, ce), existing_fn, fixup_trait_scope(existing_fn, ce),
1628 ce, NULL, /* check_visibility */ 1);
1629 }
1630 }
1631
1632 if (UNEXPECTED(fn->type == ZEND_INTERNAL_FUNCTION)) {
1633 new_fn = zend_arena_alloc(&CG(arena), sizeof(zend_internal_function));
1634 memcpy(new_fn, fn, sizeof(zend_internal_function));
1635 new_fn->common.fn_flags |= ZEND_ACC_ARENA_ALLOCATED;
1636 } else {
1637 new_fn = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
1638 memcpy(new_fn, fn, sizeof(zend_op_array));
1639 new_fn->op_array.fn_flags |= ZEND_ACC_TRAIT_CLONE;
1640 new_fn->op_array.fn_flags &= ~ZEND_ACC_IMMUTABLE;
1641 }
1642
1643 /* Reassign method name, in case it is an alias. */
1644 new_fn->common.function_name = name;
1645 function_add_ref(new_fn);
1646 fn = zend_hash_update_ptr(&ce->function_table, key, new_fn);
1647 zend_add_magic_method(ce, fn, key);
1648 }
1649 /* }}} */
1650
zend_fixup_trait_method(zend_function * fn,zend_class_entry * ce)1651 static void zend_fixup_trait_method(zend_function *fn, zend_class_entry *ce) /* {{{ */
1652 {
1653 if ((fn->common.scope->ce_flags & ZEND_ACC_TRAIT) == ZEND_ACC_TRAIT) {
1654
1655 fn->common.scope = ce;
1656
1657 if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
1658 ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
1659 }
1660 if (fn->type == ZEND_USER_FUNCTION && fn->op_array.static_variables) {
1661 ce->ce_flags |= ZEND_HAS_STATIC_IN_METHODS;
1662 }
1663 }
1664 }
1665 /* }}} */
1666
zend_traits_copy_functions(zend_string * fnname,zend_function * fn,zend_class_entry * ce,HashTable * exclude_table,zend_class_entry ** aliases)1667 static void zend_traits_copy_functions(zend_string *fnname, zend_function *fn, zend_class_entry *ce, HashTable *exclude_table, zend_class_entry **aliases) /* {{{ */
1668 {
1669 zend_trait_alias *alias, **alias_ptr;
1670 zend_string *lcname;
1671 zend_function fn_copy;
1672 int i;
1673
1674 /* apply aliases which are qualified with a class name, there should not be any ambiguity */
1675 if (ce->trait_aliases) {
1676 alias_ptr = ce->trait_aliases;
1677 alias = *alias_ptr;
1678 i = 0;
1679 while (alias) {
1680 /* Scope unset or equal to the function we compare to, and the alias applies to fn */
1681 if (alias->alias != NULL
1682 && fn->common.scope == aliases[i]
1683 && zend_string_equals_ci(alias->trait_method.method_name, fnname)
1684 ) {
1685 fn_copy = *fn;
1686
1687 /* if it is 0, no modifieres has been changed */
1688 if (alias->modifiers) {
1689 fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags & ~ZEND_ACC_PPP_MASK);
1690 }
1691
1692 lcname = zend_string_tolower(alias->alias);
1693 zend_add_trait_method(ce, alias->alias, lcname, &fn_copy);
1694 zend_string_release_ex(lcname, 0);
1695 }
1696 alias_ptr++;
1697 alias = *alias_ptr;
1698 i++;
1699 }
1700 }
1701
1702 if (exclude_table == NULL || zend_hash_find(exclude_table, fnname) == NULL) {
1703 /* is not in hashtable, thus, function is not to be excluded */
1704 memcpy(&fn_copy, fn, fn->type == ZEND_USER_FUNCTION ? sizeof(zend_op_array) : sizeof(zend_internal_function));
1705
1706 /* apply aliases which have not alias name, just setting visibility */
1707 if (ce->trait_aliases) {
1708 alias_ptr = ce->trait_aliases;
1709 alias = *alias_ptr;
1710 i = 0;
1711 while (alias) {
1712 /* Scope unset or equal to the function we compare to, and the alias applies to fn */
1713 if (alias->alias == NULL && alias->modifiers != 0
1714 && fn->common.scope == aliases[i]
1715 && zend_string_equals_ci(alias->trait_method.method_name, fnname)
1716 ) {
1717 fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags & ~ZEND_ACC_PPP_MASK);
1718 }
1719 alias_ptr++;
1720 alias = *alias_ptr;
1721 i++;
1722 }
1723 }
1724
1725 zend_add_trait_method(ce, fn->common.function_name, fnname, &fn_copy);
1726 }
1727 }
1728 /* }}} */
1729
zend_check_trait_usage(zend_class_entry * ce,zend_class_entry * trait,zend_class_entry ** traits)1730 static uint32_t zend_check_trait_usage(zend_class_entry *ce, zend_class_entry *trait, zend_class_entry **traits) /* {{{ */
1731 {
1732 uint32_t i;
1733
1734 if (UNEXPECTED((trait->ce_flags & ZEND_ACC_TRAIT) != ZEND_ACC_TRAIT)) {
1735 zend_error_noreturn(E_COMPILE_ERROR, "Class %s is not a trait, Only traits may be used in 'as' and 'insteadof' statements", ZSTR_VAL(trait->name));
1736 return 0;
1737 }
1738
1739 for (i = 0; i < ce->num_traits; i++) {
1740 if (traits[i] == trait) {
1741 return i;
1742 }
1743 }
1744 zend_error_noreturn(E_COMPILE_ERROR, "Required Trait %s wasn't added to %s", ZSTR_VAL(trait->name), ZSTR_VAL(ce->name));
1745 return 0;
1746 }
1747 /* }}} */
1748
zend_traits_init_trait_structures(zend_class_entry * ce,zend_class_entry ** traits,HashTable *** exclude_tables_ptr,zend_class_entry *** aliases_ptr)1749 static void zend_traits_init_trait_structures(zend_class_entry *ce, zend_class_entry **traits, HashTable ***exclude_tables_ptr, zend_class_entry ***aliases_ptr) /* {{{ */
1750 {
1751 size_t i, j = 0;
1752 zend_trait_precedence **precedences;
1753 zend_trait_precedence *cur_precedence;
1754 zend_trait_method_reference *cur_method_ref;
1755 zend_string *lcname;
1756 HashTable **exclude_tables = NULL;
1757 zend_class_entry **aliases = NULL;
1758 zend_class_entry *trait;
1759
1760 /* resolve class references */
1761 if (ce->trait_precedences) {
1762 exclude_tables = ecalloc(ce->num_traits, sizeof(HashTable*));
1763 i = 0;
1764 precedences = ce->trait_precedences;
1765 ce->trait_precedences = NULL;
1766 while ((cur_precedence = precedences[i])) {
1767 /** Resolve classes for all precedence operations. */
1768 cur_method_ref = &cur_precedence->trait_method;
1769 trait = zend_fetch_class(cur_method_ref->class_name,
1770 ZEND_FETCH_CLASS_TRAIT|ZEND_FETCH_CLASS_NO_AUTOLOAD);
1771 if (!trait) {
1772 zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", ZSTR_VAL(cur_method_ref->class_name));
1773 }
1774 zend_check_trait_usage(ce, trait, traits);
1775
1776 /** Ensure that the preferred method is actually available. */
1777 lcname = zend_string_tolower(cur_method_ref->method_name);
1778 if (!zend_hash_exists(&trait->function_table, lcname)) {
1779 zend_error_noreturn(E_COMPILE_ERROR,
1780 "A precedence rule was defined for %s::%s but this method does not exist",
1781 ZSTR_VAL(trait->name),
1782 ZSTR_VAL(cur_method_ref->method_name));
1783 }
1784
1785 /** With the other traits, we are more permissive.
1786 We do not give errors for those. This allows to be more
1787 defensive in such definitions.
1788 However, we want to make sure that the insteadof declaration
1789 is consistent in itself.
1790 */
1791
1792 for (j = 0; j < cur_precedence->num_excludes; j++) {
1793 zend_string* class_name = cur_precedence->exclude_class_names[j];
1794 zend_class_entry *exclude_ce = zend_fetch_class(class_name, ZEND_FETCH_CLASS_TRAIT |ZEND_FETCH_CLASS_NO_AUTOLOAD);
1795 uint32_t trait_num;
1796
1797 if (!exclude_ce) {
1798 zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", ZSTR_VAL(class_name));
1799 }
1800 trait_num = zend_check_trait_usage(ce, exclude_ce, traits);
1801 if (!exclude_tables[trait_num]) {
1802 ALLOC_HASHTABLE(exclude_tables[trait_num]);
1803 zend_hash_init(exclude_tables[trait_num], 0, NULL, NULL, 0);
1804 }
1805 if (zend_hash_add_empty_element(exclude_tables[trait_num], lcname) == NULL) {
1806 zend_error_noreturn(E_COMPILE_ERROR, "Failed to evaluate a trait precedence (%s). Method of trait %s was defined to be excluded multiple times", ZSTR_VAL(precedences[i]->trait_method.method_name), ZSTR_VAL(exclude_ce->name));
1807 }
1808
1809 /* make sure that the trait method is not from a class mentioned in
1810 exclude_from_classes, for consistency */
1811 if (trait == exclude_ce) {
1812 zend_error_noreturn(E_COMPILE_ERROR,
1813 "Inconsistent insteadof definition. "
1814 "The method %s is to be used from %s, but %s is also on the exclude list",
1815 ZSTR_VAL(cur_method_ref->method_name),
1816 ZSTR_VAL(trait->name),
1817 ZSTR_VAL(trait->name));
1818 }
1819 }
1820 zend_string_release_ex(lcname, 0);
1821 i++;
1822 }
1823 ce->trait_precedences = precedences;
1824 }
1825
1826 if (ce->trait_aliases) {
1827 i = 0;
1828 while (ce->trait_aliases[i]) {
1829 i++;
1830 }
1831 aliases = ecalloc(i, sizeof(zend_class_entry*));
1832 i = 0;
1833 while (ce->trait_aliases[i]) {
1834 zend_trait_alias *cur_alias = ce->trait_aliases[i];
1835 cur_method_ref = &ce->trait_aliases[i]->trait_method;
1836 lcname = zend_string_tolower(cur_method_ref->method_name);
1837 if (cur_method_ref->class_name) {
1838 /* For all aliases with an explicit class name, resolve the class now. */
1839 trait = zend_fetch_class(cur_method_ref->class_name, ZEND_FETCH_CLASS_TRAIT|ZEND_FETCH_CLASS_NO_AUTOLOAD);
1840 if (!trait) {
1841 zend_error_noreturn(E_COMPILE_ERROR, "Could not find trait %s", ZSTR_VAL(cur_method_ref->class_name));
1842 }
1843 zend_check_trait_usage(ce, trait, traits);
1844 aliases[i] = trait;
1845
1846 /* And, ensure that the referenced method is resolvable, too. */
1847 if (!zend_hash_exists(&trait->function_table, lcname)) {
1848 zend_error_noreturn(E_COMPILE_ERROR, "An alias was defined for %s::%s but this method does not exist", ZSTR_VAL(trait->name), ZSTR_VAL(cur_method_ref->method_name));
1849 }
1850 } else {
1851 /* Find out which trait this method refers to. */
1852 trait = NULL;
1853 for (j = 0; j < ce->num_traits; j++) {
1854 if (traits[j]) {
1855 if (zend_hash_exists(&traits[j]->function_table, lcname)) {
1856 if (!trait) {
1857 trait = traits[j];
1858 continue;
1859 }
1860
1861 zend_error_noreturn(E_COMPILE_ERROR,
1862 "An alias was defined for method %s(), which exists in both %s and %s. Use %s::%s or %s::%s to resolve the ambiguity",
1863 ZSTR_VAL(cur_method_ref->method_name),
1864 ZSTR_VAL(trait->name), ZSTR_VAL(traits[j]->name),
1865 ZSTR_VAL(trait->name), ZSTR_VAL(cur_method_ref->method_name),
1866 ZSTR_VAL(traits[j]->name), ZSTR_VAL(cur_method_ref->method_name));
1867 }
1868 }
1869 }
1870
1871 /* Non-absolute method reference refers to method that does not exist. */
1872 if (!trait) {
1873 if (cur_alias->alias) {
1874 zend_error_noreturn(E_COMPILE_ERROR,
1875 "An alias (%s) was defined for method %s(), but this method does not exist",
1876 ZSTR_VAL(cur_alias->alias),
1877 ZSTR_VAL(cur_alias->trait_method.method_name));
1878 } else {
1879 zend_error_noreturn(E_COMPILE_ERROR,
1880 "The modifiers of the trait method %s() are changed, but this method does not exist. Error",
1881 ZSTR_VAL(cur_alias->trait_method.method_name));
1882 }
1883 }
1884
1885 aliases[i] = trait;
1886
1887 /* TODO: try to avoid this assignment (it's necessary only for reflection) */
1888 cur_method_ref->class_name = zend_string_copy(trait->name);
1889 }
1890 zend_string_release_ex(lcname, 0);
1891 i++;
1892 }
1893 }
1894
1895 *exclude_tables_ptr = exclude_tables;
1896 *aliases_ptr = aliases;
1897 }
1898 /* }}} */
1899
zend_do_traits_method_binding(zend_class_entry * ce,zend_class_entry ** traits,HashTable ** exclude_tables,zend_class_entry ** aliases)1900 static void zend_do_traits_method_binding(zend_class_entry *ce, zend_class_entry **traits, HashTable **exclude_tables, zend_class_entry **aliases) /* {{{ */
1901 {
1902 uint32_t i;
1903 zend_string *key;
1904 zend_function *fn;
1905
1906 if (exclude_tables) {
1907 for (i = 0; i < ce->num_traits; i++) {
1908 if (traits[i]) {
1909 /* copies functions, applies defined aliasing, and excludes unused trait methods */
1910 ZEND_HASH_FOREACH_STR_KEY_PTR(&traits[i]->function_table, key, fn) {
1911 zend_traits_copy_functions(key, fn, ce, exclude_tables[i], aliases);
1912 } ZEND_HASH_FOREACH_END();
1913
1914 if (exclude_tables[i]) {
1915 zend_hash_destroy(exclude_tables[i]);
1916 FREE_HASHTABLE(exclude_tables[i]);
1917 exclude_tables[i] = NULL;
1918 }
1919 }
1920 }
1921 } else {
1922 for (i = 0; i < ce->num_traits; i++) {
1923 if (traits[i]) {
1924 ZEND_HASH_FOREACH_STR_KEY_PTR(&traits[i]->function_table, key, fn) {
1925 zend_traits_copy_functions(key, fn, ce, NULL, aliases);
1926 } ZEND_HASH_FOREACH_END();
1927 }
1928 }
1929 }
1930
1931 ZEND_HASH_FOREACH_PTR(&ce->function_table, fn) {
1932 zend_fixup_trait_method(fn, ce);
1933 } ZEND_HASH_FOREACH_END();
1934 }
1935 /* }}} */
1936
find_first_definition(zend_class_entry * ce,zend_class_entry ** traits,size_t current_trait,zend_string * prop_name,zend_class_entry * coliding_ce)1937 static zend_class_entry* find_first_definition(zend_class_entry *ce, zend_class_entry **traits, size_t current_trait, zend_string *prop_name, zend_class_entry *coliding_ce) /* {{{ */
1938 {
1939 size_t i;
1940
1941 if (coliding_ce == ce) {
1942 for (i = 0; i < current_trait; i++) {
1943 if (traits[i]
1944 && zend_hash_exists(&traits[i]->properties_info, prop_name)) {
1945 return traits[i];
1946 }
1947 }
1948 }
1949
1950 return coliding_ce;
1951 }
1952 /* }}} */
1953
zend_do_traits_property_binding(zend_class_entry * ce,zend_class_entry ** traits)1954 static void zend_do_traits_property_binding(zend_class_entry *ce, zend_class_entry **traits) /* {{{ */
1955 {
1956 size_t i;
1957 zend_property_info *property_info;
1958 zend_property_info *coliding_prop;
1959 zend_property_info *new_prop;
1960 zend_string* prop_name;
1961 const char* class_name_unused;
1962 zend_bool not_compatible;
1963 zval* prop_value;
1964 uint32_t flags;
1965 zend_string *doc_comment;
1966
1967 /* In the following steps the properties are inserted into the property table
1968 * for that, a very strict approach is applied:
1969 * - check for compatibility, if not compatible with any property in class -> fatal
1970 * - if compatible, then strict notice
1971 */
1972 for (i = 0; i < ce->num_traits; i++) {
1973 if (!traits[i]) {
1974 continue;
1975 }
1976 ZEND_HASH_FOREACH_PTR(&traits[i]->properties_info, property_info) {
1977 /* first get the unmangeld name if necessary,
1978 * then check whether the property is already there
1979 */
1980 flags = property_info->flags;
1981 if (flags & ZEND_ACC_PUBLIC) {
1982 prop_name = zend_string_copy(property_info->name);
1983 } else {
1984 const char *pname;
1985 size_t pname_len;
1986
1987 /* for private and protected we need to unmangle the names */
1988 zend_unmangle_property_name_ex(property_info->name,
1989 &class_name_unused, &pname, &pname_len);
1990 prop_name = zend_string_init(pname, pname_len, 0);
1991 }
1992
1993 /* next: check for conflicts with current class */
1994 if ((coliding_prop = zend_hash_find_ptr(&ce->properties_info, prop_name)) != NULL) {
1995 if ((coliding_prop->flags & ZEND_ACC_PRIVATE) && coliding_prop->ce != ce) {
1996 zend_hash_del(&ce->properties_info, prop_name);
1997 flags |= ZEND_ACC_CHANGED;
1998 } else {
1999 not_compatible = 1;
2000
2001 if ((coliding_prop->flags & (ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC))
2002 == (flags & (ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC)) &&
2003 property_types_compatible(property_info, coliding_prop) == INHERITANCE_SUCCESS
2004 ) {
2005 /* the flags are identical, thus, the properties may be compatible */
2006 zval *op1, *op2;
2007 zval op1_tmp, op2_tmp;
2008
2009 if (flags & ZEND_ACC_STATIC) {
2010 op1 = &ce->default_static_members_table[coliding_prop->offset];
2011 op2 = &traits[i]->default_static_members_table[property_info->offset];
2012 ZVAL_DEINDIRECT(op1);
2013 ZVAL_DEINDIRECT(op2);
2014 } else {
2015 op1 = &ce->default_properties_table[OBJ_PROP_TO_NUM(coliding_prop->offset)];
2016 op2 = &traits[i]->default_properties_table[OBJ_PROP_TO_NUM(property_info->offset)];
2017 }
2018
2019 /* if any of the values is a constant, we try to resolve it */
2020 if (UNEXPECTED(Z_TYPE_P(op1) == IS_CONSTANT_AST)) {
2021 ZVAL_COPY_OR_DUP(&op1_tmp, op1);
2022 zval_update_constant_ex(&op1_tmp, ce);
2023 op1 = &op1_tmp;
2024 }
2025 if (UNEXPECTED(Z_TYPE_P(op2) == IS_CONSTANT_AST)) {
2026 ZVAL_COPY_OR_DUP(&op2_tmp, op2);
2027 zval_update_constant_ex(&op2_tmp, ce);
2028 op2 = &op2_tmp;
2029 }
2030
2031 not_compatible = fast_is_not_identical_function(op1, op2);
2032
2033 if (op1 == &op1_tmp) {
2034 zval_ptr_dtor_nogc(&op1_tmp);
2035 }
2036 if (op2 == &op2_tmp) {
2037 zval_ptr_dtor_nogc(&op2_tmp);
2038 }
2039 }
2040
2041 if (not_compatible) {
2042 zend_error_noreturn(E_COMPILE_ERROR,
2043 "%s and %s define the same property ($%s) in the composition of %s. However, the definition differs and is considered incompatible. Class was composed",
2044 ZSTR_VAL(find_first_definition(ce, traits, i, prop_name, coliding_prop->ce)->name),
2045 ZSTR_VAL(property_info->ce->name),
2046 ZSTR_VAL(prop_name),
2047 ZSTR_VAL(ce->name));
2048 }
2049
2050 zend_string_release_ex(prop_name, 0);
2051 continue;
2052 }
2053 }
2054
2055 /* property not found, so lets add it */
2056 if (flags & ZEND_ACC_STATIC) {
2057 prop_value = &traits[i]->default_static_members_table[property_info->offset];
2058 ZEND_ASSERT(Z_TYPE_P(prop_value) != IS_INDIRECT);
2059 } else {
2060 prop_value = &traits[i]->default_properties_table[OBJ_PROP_TO_NUM(property_info->offset)];
2061 }
2062
2063 Z_TRY_ADDREF_P(prop_value);
2064 doc_comment = property_info->doc_comment ? zend_string_copy(property_info->doc_comment) : NULL;
2065
2066 zend_type type = property_info->type;
2067 zend_type_copy_ctor(&type, /* persistent */ 0);
2068 new_prop = zend_declare_typed_property(ce, prop_name, prop_value, flags, doc_comment, type);
2069
2070 if (property_info->attributes) {
2071 new_prop->attributes = property_info->attributes;
2072
2073 if (!(GC_FLAGS(new_prop->attributes) & IS_ARRAY_IMMUTABLE)) {
2074 GC_ADDREF(new_prop->attributes);
2075 }
2076 }
2077
2078 zend_string_release_ex(prop_name, 0);
2079 } ZEND_HASH_FOREACH_END();
2080 }
2081 }
2082 /* }}} */
2083
zend_do_bind_traits(zend_class_entry * ce)2084 static void zend_do_bind_traits(zend_class_entry *ce) /* {{{ */
2085 {
2086 HashTable **exclude_tables;
2087 zend_class_entry **aliases;
2088 zend_class_entry **traits, *trait;
2089 uint32_t i, j;
2090
2091 ZEND_ASSERT(ce->num_traits > 0);
2092
2093 traits = emalloc(sizeof(zend_class_entry*) * ce->num_traits);
2094
2095 for (i = 0; i < ce->num_traits; i++) {
2096 trait = zend_fetch_class_by_name(ce->trait_names[i].name,
2097 ce->trait_names[i].lc_name, ZEND_FETCH_CLASS_TRAIT);
2098 if (UNEXPECTED(trait == NULL)) {
2099 return;
2100 }
2101 if (UNEXPECTED(!(trait->ce_flags & ZEND_ACC_TRAIT))) {
2102 zend_error_noreturn(E_ERROR, "%s cannot use %s - it is not a trait", ZSTR_VAL(ce->name), ZSTR_VAL(trait->name));
2103 return;
2104 }
2105 for (j = 0; j < i; j++) {
2106 if (traits[j] == trait) {
2107 /* skip duplications */
2108 trait = NULL;
2109 break;
2110 }
2111 }
2112 traits[i] = trait;
2113 }
2114
2115 /* complete initialization of trait strutures in ce */
2116 zend_traits_init_trait_structures(ce, traits, &exclude_tables, &aliases);
2117
2118 /* first care about all methods to be flattened into the class */
2119 zend_do_traits_method_binding(ce, traits, exclude_tables, aliases);
2120
2121 if (aliases) {
2122 efree(aliases);
2123 }
2124
2125 if (exclude_tables) {
2126 efree(exclude_tables);
2127 }
2128
2129 /* then flatten the properties into it, to, mostly to notfiy developer about problems */
2130 zend_do_traits_property_binding(ce, traits);
2131
2132 efree(traits);
2133 }
2134 /* }}} */
2135
2136 #define MAX_ABSTRACT_INFO_CNT 3
2137 #define MAX_ABSTRACT_INFO_FMT "%s%s%s%s"
2138 #define DISPLAY_ABSTRACT_FN(idx) \
2139 ai.afn[idx] ? ZEND_FN_SCOPE_NAME(ai.afn[idx]) : "", \
2140 ai.afn[idx] ? "::" : "", \
2141 ai.afn[idx] ? ZSTR_VAL(ai.afn[idx]->common.function_name) : "", \
2142 ai.afn[idx] && ai.afn[idx + 1] ? ", " : (ai.afn[idx] && ai.cnt > MAX_ABSTRACT_INFO_CNT ? ", ..." : "")
2143
2144 typedef struct _zend_abstract_info {
2145 zend_function *afn[MAX_ABSTRACT_INFO_CNT + 1];
2146 int cnt;
2147 int ctor;
2148 } zend_abstract_info;
2149
zend_verify_abstract_class_function(zend_function * fn,zend_abstract_info * ai)2150 static void zend_verify_abstract_class_function(zend_function *fn, zend_abstract_info *ai) /* {{{ */
2151 {
2152 if (ai->cnt < MAX_ABSTRACT_INFO_CNT) {
2153 ai->afn[ai->cnt] = fn;
2154 }
2155 if (fn->common.fn_flags & ZEND_ACC_CTOR) {
2156 if (!ai->ctor) {
2157 ai->cnt++;
2158 ai->ctor = 1;
2159 } else {
2160 ai->afn[ai->cnt] = NULL;
2161 }
2162 } else {
2163 ai->cnt++;
2164 }
2165 }
2166 /* }}} */
2167
zend_verify_abstract_class(zend_class_entry * ce)2168 void zend_verify_abstract_class(zend_class_entry *ce) /* {{{ */
2169 {
2170 zend_function *func;
2171 zend_abstract_info ai;
2172 zend_bool is_explicit_abstract = (ce->ce_flags & ZEND_ACC_EXPLICIT_ABSTRACT_CLASS) != 0;
2173 memset(&ai, 0, sizeof(ai));
2174
2175 ZEND_HASH_FOREACH_PTR(&ce->function_table, func) {
2176 if (func->common.fn_flags & ZEND_ACC_ABSTRACT) {
2177 /* If the class is explicitly abstract, we only check private abstract methods,
2178 * because only they must be declared in the same class. */
2179 if (!is_explicit_abstract || (func->common.fn_flags & ZEND_ACC_PRIVATE)) {
2180 zend_verify_abstract_class_function(func, &ai);
2181 }
2182 }
2183 } ZEND_HASH_FOREACH_END();
2184
2185 if (ai.cnt) {
2186 zend_error_noreturn(E_ERROR, !is_explicit_abstract
2187 ? "Class %s contains %d abstract method%s and must therefore be declared abstract or implement the remaining methods (" MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT ")"
2188 : "Class %s must implement %d abstract private method%s (" MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT MAX_ABSTRACT_INFO_FMT ")",
2189 ZSTR_VAL(ce->name), ai.cnt,
2190 ai.cnt > 1 ? "s" : "",
2191 DISPLAY_ABSTRACT_FN(0),
2192 DISPLAY_ABSTRACT_FN(1),
2193 DISPLAY_ABSTRACT_FN(2)
2194 );
2195 } else {
2196 /* now everything should be fine and an added ZEND_ACC_IMPLICIT_ABSTRACT_CLASS should be removed */
2197 ce->ce_flags &= ~ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
2198 }
2199 }
2200 /* }}} */
2201
2202 typedef struct {
2203 enum {
2204 OBLIGATION_DEPENDENCY,
2205 OBLIGATION_COMPATIBILITY,
2206 OBLIGATION_PROPERTY_COMPATIBILITY
2207 } type;
2208 union {
2209 zend_class_entry *dependency_ce;
2210 struct {
2211 /* Traits may use temporary on-stack functions during inheritance checks,
2212 * so use copies of functions here as well. */
2213 zend_function parent_fn;
2214 zend_function child_fn;
2215 zend_class_entry *child_scope;
2216 zend_class_entry *parent_scope;
2217 };
2218 struct {
2219 const zend_property_info *parent_prop;
2220 const zend_property_info *child_prop;
2221 };
2222 };
2223 } variance_obligation;
2224
variance_obligation_dtor(zval * zv)2225 static void variance_obligation_dtor(zval *zv) {
2226 efree(Z_PTR_P(zv));
2227 }
2228
variance_obligation_ht_dtor(zval * zv)2229 static void variance_obligation_ht_dtor(zval *zv) {
2230 zend_hash_destroy(Z_PTR_P(zv));
2231 FREE_HASHTABLE(Z_PTR_P(zv));
2232 }
2233
get_or_init_obligations_for_class(zend_class_entry * ce)2234 static HashTable *get_or_init_obligations_for_class(zend_class_entry *ce) {
2235 HashTable *ht;
2236 zend_ulong key;
2237 if (!CG(delayed_variance_obligations)) {
2238 ALLOC_HASHTABLE(CG(delayed_variance_obligations));
2239 zend_hash_init(CG(delayed_variance_obligations), 0, NULL, variance_obligation_ht_dtor, 0);
2240 }
2241
2242 key = (zend_ulong) (uintptr_t) ce;
2243 ht = zend_hash_index_find_ptr(CG(delayed_variance_obligations), key);
2244 if (ht) {
2245 return ht;
2246 }
2247
2248 ALLOC_HASHTABLE(ht);
2249 zend_hash_init(ht, 0, NULL, variance_obligation_dtor, 0);
2250 zend_hash_index_add_new_ptr(CG(delayed_variance_obligations), key, ht);
2251 ce->ce_flags |= ZEND_ACC_UNRESOLVED_VARIANCE;
2252 return ht;
2253 }
2254
add_dependency_obligation(zend_class_entry * ce,zend_class_entry * dependency_ce)2255 static void add_dependency_obligation(zend_class_entry *ce, zend_class_entry *dependency_ce) {
2256 HashTable *obligations = get_or_init_obligations_for_class(ce);
2257 variance_obligation *obligation = emalloc(sizeof(variance_obligation));
2258 obligation->type = OBLIGATION_DEPENDENCY;
2259 obligation->dependency_ce = dependency_ce;
2260 zend_hash_next_index_insert_ptr(obligations, obligation);
2261 }
2262
add_compatibility_obligation(zend_class_entry * ce,const zend_function * child_fn,zend_class_entry * child_scope,const zend_function * parent_fn,zend_class_entry * parent_scope)2263 static void add_compatibility_obligation(
2264 zend_class_entry *ce,
2265 const zend_function *child_fn, zend_class_entry *child_scope,
2266 const zend_function *parent_fn, zend_class_entry *parent_scope) {
2267 HashTable *obligations = get_or_init_obligations_for_class(ce);
2268 variance_obligation *obligation = emalloc(sizeof(variance_obligation));
2269 obligation->type = OBLIGATION_COMPATIBILITY;
2270 /* Copy functions, because they may be stack-allocated in the case of traits. */
2271 if (child_fn->common.type == ZEND_INTERNAL_FUNCTION) {
2272 memcpy(&obligation->child_fn, child_fn, sizeof(zend_internal_function));
2273 } else {
2274 memcpy(&obligation->child_fn, child_fn, sizeof(zend_op_array));
2275 }
2276 if (parent_fn->common.type == ZEND_INTERNAL_FUNCTION) {
2277 memcpy(&obligation->parent_fn, parent_fn, sizeof(zend_internal_function));
2278 } else {
2279 memcpy(&obligation->parent_fn, parent_fn, sizeof(zend_op_array));
2280 }
2281 obligation->child_scope = child_scope;
2282 obligation->parent_scope = parent_scope;
2283 zend_hash_next_index_insert_ptr(obligations, obligation);
2284 }
2285
add_property_compatibility_obligation(zend_class_entry * ce,const zend_property_info * child_prop,const zend_property_info * parent_prop)2286 static void add_property_compatibility_obligation(
2287 zend_class_entry *ce, const zend_property_info *child_prop,
2288 const zend_property_info *parent_prop) {
2289 HashTable *obligations = get_or_init_obligations_for_class(ce);
2290 variance_obligation *obligation = emalloc(sizeof(variance_obligation));
2291 obligation->type = OBLIGATION_PROPERTY_COMPATIBILITY;
2292 obligation->child_prop = child_prop;
2293 obligation->parent_prop = parent_prop;
2294 zend_hash_next_index_insert_ptr(obligations, obligation);
2295 }
2296
2297 static void resolve_delayed_variance_obligations(zend_class_entry *ce);
2298
check_variance_obligation(zval * zv)2299 static int check_variance_obligation(zval *zv) {
2300 variance_obligation *obligation = Z_PTR_P(zv);
2301 if (obligation->type == OBLIGATION_DEPENDENCY) {
2302 zend_class_entry *dependency_ce = obligation->dependency_ce;
2303 if (dependency_ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE) {
2304 resolve_delayed_variance_obligations(dependency_ce);
2305 }
2306 if (!(dependency_ce->ce_flags & ZEND_ACC_LINKED)) {
2307 return ZEND_HASH_APPLY_KEEP;
2308 }
2309 } else if (obligation->type == OBLIGATION_COMPATIBILITY) {
2310 inheritance_status status = zend_do_perform_implementation_check(
2311 &obligation->child_fn, obligation->child_scope,
2312 &obligation->parent_fn, obligation->parent_scope);
2313 if (UNEXPECTED(status != INHERITANCE_SUCCESS)) {
2314 if (EXPECTED(status == INHERITANCE_UNRESOLVED)) {
2315 return ZEND_HASH_APPLY_KEEP;
2316 }
2317 ZEND_ASSERT(status == INHERITANCE_ERROR);
2318 emit_incompatible_method_error(
2319 &obligation->child_fn, obligation->child_scope,
2320 &obligation->parent_fn, obligation->parent_scope, status);
2321 }
2322 /* Either the compatibility check was successful or only threw a warning. */
2323 } else {
2324 ZEND_ASSERT(obligation->type == OBLIGATION_PROPERTY_COMPATIBILITY);
2325 inheritance_status status =
2326 property_types_compatible(obligation->parent_prop, obligation->child_prop);
2327 if (status != INHERITANCE_SUCCESS) {
2328 if (status == INHERITANCE_UNRESOLVED) {
2329 return ZEND_HASH_APPLY_KEEP;
2330 }
2331 ZEND_ASSERT(status == INHERITANCE_ERROR);
2332 emit_incompatible_property_error(obligation->child_prop, obligation->parent_prop);
2333 }
2334 }
2335 return ZEND_HASH_APPLY_REMOVE;
2336 }
2337
load_delayed_classes()2338 static void load_delayed_classes() {
2339 HashTable *delayed_autoloads = CG(delayed_autoloads);
2340 zend_string *name;
2341
2342 if (!delayed_autoloads) {
2343 return;
2344 }
2345
2346 /* Take ownership of this HT, to avoid concurrent modification during autoloading. */
2347 CG(delayed_autoloads) = NULL;
2348
2349 ZEND_HASH_FOREACH_STR_KEY(delayed_autoloads, name) {
2350 zend_lookup_class(name);
2351 if (EG(exception)) {
2352 break;
2353 }
2354 } ZEND_HASH_FOREACH_END();
2355
2356 zend_hash_destroy(delayed_autoloads);
2357 FREE_HASHTABLE(delayed_autoloads);
2358 }
2359
resolve_delayed_variance_obligations(zend_class_entry * ce)2360 static void resolve_delayed_variance_obligations(zend_class_entry *ce) {
2361 HashTable *all_obligations = CG(delayed_variance_obligations), *obligations;
2362 zend_ulong num_key = (zend_ulong) (uintptr_t) ce;
2363
2364 ZEND_ASSERT(all_obligations != NULL);
2365 obligations = zend_hash_index_find_ptr(all_obligations, num_key);
2366 ZEND_ASSERT(obligations != NULL);
2367
2368 zend_hash_apply(obligations, check_variance_obligation);
2369 if (zend_hash_num_elements(obligations) == 0) {
2370 ce->ce_flags &= ~ZEND_ACC_UNRESOLVED_VARIANCE;
2371 ce->ce_flags |= ZEND_ACC_LINKED;
2372 zend_hash_index_del(all_obligations, num_key);
2373 }
2374 }
2375
report_variance_errors(zend_class_entry * ce)2376 static void report_variance_errors(zend_class_entry *ce) {
2377 HashTable *all_obligations = CG(delayed_variance_obligations), *obligations;
2378 variance_obligation *obligation;
2379 zend_ulong num_key = (zend_ulong) (uintptr_t) ce;
2380
2381 ZEND_ASSERT(all_obligations != NULL);
2382 obligations = zend_hash_index_find_ptr(all_obligations, num_key);
2383 ZEND_ASSERT(obligations != NULL);
2384
2385 ZEND_HASH_FOREACH_PTR(obligations, obligation) {
2386 if (obligation->type == OBLIGATION_COMPATIBILITY) {
2387 /* Just used to populate the delayed_autoloads table,
2388 * which will be used when printing the "unresolved" error. */
2389 inheritance_status status = zend_do_perform_implementation_check(
2390 &obligation->child_fn, obligation->child_scope,
2391 &obligation->parent_fn, obligation->parent_scope);
2392 ZEND_ASSERT(status == INHERITANCE_UNRESOLVED);
2393 emit_incompatible_method_error(
2394 &obligation->child_fn, obligation->child_scope,
2395 &obligation->parent_fn, obligation->parent_scope, status);
2396 } else if (obligation->type == OBLIGATION_PROPERTY_COMPATIBILITY) {
2397 emit_incompatible_property_error(obligation->child_prop, obligation->parent_prop);
2398 } else {
2399 zend_error_noreturn(E_CORE_ERROR, "Bug #78647");
2400 }
2401 } ZEND_HASH_FOREACH_END();
2402
2403 /* Only warnings were thrown above -- that means that there are incompatibilities, but only
2404 * ones that we permit. Mark all classes with open obligations as fully linked. */
2405 ce->ce_flags &= ~ZEND_ACC_UNRESOLVED_VARIANCE;
2406 ce->ce_flags |= ZEND_ACC_LINKED;
2407 zend_hash_index_del(all_obligations, num_key);
2408 }
2409
check_unrecoverable_load_failure(zend_class_entry * ce)2410 static void check_unrecoverable_load_failure(zend_class_entry *ce) {
2411 /* If this class has been used while unlinked through a variance obligation, it is not legal
2412 * to remove the class from the class table and throw an exception, because there is already
2413 * a dependence on the inheritance hierarchy of this specific class. Instead we fall back to
2414 * a fatal error, as would happen if we did not allow exceptions in the first place. */
2415 if (ce->ce_flags & ZEND_ACC_HAS_UNLINKED_USES) {
2416 zend_string *exception_str;
2417 zval exception_zv;
2418 ZEND_ASSERT(EG(exception) && "Exception must have been thrown");
2419 ZVAL_OBJ_COPY(&exception_zv, EG(exception));
2420 zend_clear_exception();
2421 exception_str = zval_get_string(&exception_zv);
2422 zend_error_noreturn(E_ERROR,
2423 "During inheritance of %s with variance dependencies: Uncaught %s", ZSTR_VAL(ce->name), ZSTR_VAL(exception_str));
2424 }
2425 }
2426
zend_do_link_class(zend_class_entry * ce,zend_string * lc_parent_name)2427 ZEND_API zend_result zend_do_link_class(zend_class_entry *ce, zend_string *lc_parent_name) /* {{{ */
2428 {
2429 /* Load parent/interface dependencies first, so we can still gracefully abort linking
2430 * with an exception and remove the class from the class table. This is only possible
2431 * if no variance obligations on the current class have been added during autoloading. */
2432 zend_class_entry *parent = NULL;
2433 zend_class_entry **interfaces = NULL;
2434
2435 if (ce->parent_name) {
2436 parent = zend_fetch_class_by_name(
2437 ce->parent_name, lc_parent_name,
2438 ZEND_FETCH_CLASS_ALLOW_NEARLY_LINKED | ZEND_FETCH_CLASS_EXCEPTION);
2439 if (!parent) {
2440 check_unrecoverable_load_failure(ce);
2441 return FAILURE;
2442 }
2443 }
2444
2445 if (ce->num_interfaces) {
2446 /* Also copy the parent interfaces here, so we don't need to reallocate later. */
2447 uint32_t i, num_parent_interfaces = parent ? parent->num_interfaces : 0;
2448 interfaces = emalloc(
2449 sizeof(zend_class_entry *) * (ce->num_interfaces + num_parent_interfaces));
2450 if (num_parent_interfaces) {
2451 memcpy(interfaces, parent->interfaces,
2452 sizeof(zend_class_entry *) * num_parent_interfaces);
2453 }
2454 for (i = 0; i < ce->num_interfaces; i++) {
2455 zend_class_entry *iface = zend_fetch_class_by_name(
2456 ce->interface_names[i].name, ce->interface_names[i].lc_name,
2457 ZEND_FETCH_CLASS_INTERFACE |
2458 ZEND_FETCH_CLASS_ALLOW_NEARLY_LINKED | ZEND_FETCH_CLASS_EXCEPTION);
2459 if (!iface) {
2460 check_unrecoverable_load_failure(ce);
2461 efree(interfaces);
2462 return FAILURE;
2463 }
2464 interfaces[num_parent_interfaces + i] = iface;
2465 }
2466 }
2467
2468 if (parent) {
2469 if (!(parent->ce_flags & ZEND_ACC_LINKED)) {
2470 add_dependency_obligation(ce, parent);
2471 }
2472 zend_do_inheritance(ce, parent);
2473 }
2474 if (ce->num_traits) {
2475 zend_do_bind_traits(ce);
2476 }
2477 if (interfaces) {
2478 zend_do_implement_interfaces(ce, interfaces);
2479 } else if (parent && parent->num_interfaces) {
2480 zend_do_inherit_interfaces(ce, parent);
2481 }
2482 if (!(ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT))
2483 && (ce->ce_flags & (ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS))
2484 ) {
2485 zend_verify_abstract_class(ce);
2486 }
2487
2488 /* Normally Stringable is added during compilation. However, if it is imported from a trait,
2489 * we need to explicilty add the interface here. */
2490 if (ce->__tostring && !(ce->ce_flags & ZEND_ACC_TRAIT)
2491 && !zend_class_implements_interface(ce, zend_ce_stringable)) {
2492 ZEND_ASSERT(ce->__tostring->common.fn_flags & ZEND_ACC_TRAIT_CLONE);
2493 ce->ce_flags |= ZEND_ACC_RESOLVED_INTERFACES;
2494 ce->num_interfaces++;
2495 ce->interfaces = perealloc(ce->interfaces,
2496 sizeof(zend_class_entry *) * ce->num_interfaces, ce->type == ZEND_INTERNAL_CLASS);
2497 ce->interfaces[ce->num_interfaces - 1] = zend_ce_stringable;
2498 do_interface_implementation(ce, zend_ce_stringable);
2499 }
2500
2501 zend_build_properties_info_table(ce);
2502
2503 if (!(ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE)) {
2504 ce->ce_flags |= ZEND_ACC_LINKED;
2505 return SUCCESS;
2506 }
2507
2508 ce->ce_flags |= ZEND_ACC_NEARLY_LINKED;
2509 load_delayed_classes();
2510 if (ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE) {
2511 resolve_delayed_variance_obligations(ce);
2512 if (!(ce->ce_flags & ZEND_ACC_LINKED)) {
2513 report_variance_errors(ce);
2514 }
2515 }
2516
2517 return SUCCESS;
2518 }
2519 /* }}} */
2520
2521 /* Check whether early binding is prevented due to unresolved types in inheritance checks. */
zend_can_early_bind(zend_class_entry * ce,zend_class_entry * parent_ce)2522 static inheritance_status zend_can_early_bind(zend_class_entry *ce, zend_class_entry *parent_ce) /* {{{ */
2523 {
2524 zend_string *key;
2525 zend_function *parent_func;
2526 zend_property_info *parent_info;
2527
2528 ZEND_HASH_FOREACH_STR_KEY_PTR(&parent_ce->function_table, key, parent_func) {
2529 zval *zv = zend_hash_find_ex(&ce->function_table, key, 1);
2530 if (zv) {
2531 zend_function *child_func = Z_FUNC_P(zv);
2532 inheritance_status status =
2533 do_inheritance_check_on_method_ex(
2534 child_func, child_func->common.scope,
2535 parent_func, parent_func->common.scope,
2536 ce, NULL, /* check_visibility */ 1, 1, 0);
2537
2538 if (UNEXPECTED(status != INHERITANCE_SUCCESS)) {
2539 return status;
2540 }
2541 }
2542 } ZEND_HASH_FOREACH_END();
2543
2544 ZEND_HASH_FOREACH_STR_KEY_PTR(&parent_ce->properties_info, key, parent_info) {
2545 zval *zv;
2546 if ((parent_info->flags & ZEND_ACC_PRIVATE) || !ZEND_TYPE_IS_SET(parent_info->type)) {
2547 continue;
2548 }
2549
2550 zv = zend_hash_find_ex(&ce->properties_info, key, 1);
2551 if (zv) {
2552 zend_property_info *child_info = Z_PTR_P(zv);
2553 if (ZEND_TYPE_IS_SET(child_info->type)) {
2554 inheritance_status status = property_types_compatible(parent_info, child_info);
2555 if (UNEXPECTED(status != INHERITANCE_SUCCESS)) {
2556 return status;
2557 }
2558 }
2559 }
2560 } ZEND_HASH_FOREACH_END();
2561
2562 return INHERITANCE_SUCCESS;
2563 }
2564 /* }}} */
2565
zend_try_early_bind(zend_class_entry * ce,zend_class_entry * parent_ce,zend_string * lcname,zval * delayed_early_binding)2566 zend_bool zend_try_early_bind(zend_class_entry *ce, zend_class_entry *parent_ce, zend_string *lcname, zval *delayed_early_binding) /* {{{ */
2567 {
2568 inheritance_status status = zend_can_early_bind(ce, parent_ce);
2569
2570 if (EXPECTED(status != INHERITANCE_UNRESOLVED)) {
2571 if (delayed_early_binding) {
2572 if (UNEXPECTED(zend_hash_set_bucket_key(EG(class_table), (Bucket*)delayed_early_binding, lcname) == NULL)) {
2573 zend_error_noreturn(E_COMPILE_ERROR, "Cannot declare %s %s, because the name is already in use", zend_get_object_type(ce), ZSTR_VAL(ce->name));
2574 return 0;
2575 }
2576 } else {
2577 if (UNEXPECTED(zend_hash_add_ptr(CG(class_table), lcname, ce) == NULL)) {
2578 return 0;
2579 }
2580 }
2581 zend_do_inheritance_ex(ce, parent_ce, status == INHERITANCE_SUCCESS);
2582 if (parent_ce && parent_ce->num_interfaces) {
2583 zend_do_inherit_interfaces(ce, parent_ce);
2584 }
2585 zend_build_properties_info_table(ce);
2586 if ((ce->ce_flags & (ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) == ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) {
2587 zend_verify_abstract_class(ce);
2588 }
2589 ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_UNRESOLVED_VARIANCE));
2590 ce->ce_flags |= ZEND_ACC_LINKED;
2591 return 1;
2592 }
2593 return 0;
2594 }
2595 /* }}} */
2596