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