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 | Andrei Zmievski <andrei@php.net> |
18 | Dmitry Stogov <dmitry@php.net> |
19 +----------------------------------------------------------------------+
20 */
21
22 #include "zend.h"
23 #include "zend_execute.h"
24 #include "zend_API.h"
25 #include "zend_modules.h"
26 #include "zend_extensions.h"
27 #include "zend_constants.h"
28 #include "zend_interfaces.h"
29 #include "zend_exceptions.h"
30 #include "zend_closures.h"
31 #include "zend_inheritance.h"
32 #include "zend_ini.h"
33 #include "zend_enum.h"
34 #include "zend_observer.h"
35
36 #include <stdarg.h>
37
38 /* these variables are true statics/globals, and have to be mutex'ed on every access */
39 ZEND_API HashTable module_registry;
40
41 static zend_module_entry **module_request_startup_handlers;
42 static zend_module_entry **module_request_shutdown_handlers;
43 static zend_module_entry **module_post_deactivate_handlers;
44 static zend_module_entry **modules_dl_loaded;
45
46 static zend_class_entry **class_cleanup_handlers;
47
zend_get_parameters_array_ex(uint32_t param_count,zval * argument_array)48 ZEND_API zend_result zend_get_parameters_array_ex(uint32_t param_count, zval *argument_array) /* {{{ */
49 {
50 zval *param_ptr;
51 uint32_t arg_count;
52
53 param_ptr = ZEND_CALL_ARG(EG(current_execute_data), 1);
54 arg_count = ZEND_CALL_NUM_ARGS(EG(current_execute_data));
55
56 if (param_count>arg_count) {
57 return FAILURE;
58 }
59
60 while (param_count-->0) {
61 ZVAL_COPY_VALUE(argument_array, param_ptr);
62 argument_array++;
63 param_ptr++;
64 }
65
66 return SUCCESS;
67 }
68 /* }}} */
69
zend_copy_parameters_array(uint32_t param_count,zval * argument_array)70 ZEND_API zend_result zend_copy_parameters_array(uint32_t param_count, zval *argument_array) /* {{{ */
71 {
72 zval *param_ptr;
73 uint32_t arg_count;
74
75 param_ptr = ZEND_CALL_ARG(EG(current_execute_data), 1);
76 arg_count = ZEND_CALL_NUM_ARGS(EG(current_execute_data));
77
78 if (param_count>arg_count) {
79 return FAILURE;
80 }
81
82 while (param_count-->0) {
83 Z_TRY_ADDREF_P(param_ptr);
84 zend_hash_next_index_insert_new(Z_ARRVAL_P(argument_array), param_ptr);
85 param_ptr++;
86 }
87
88 return SUCCESS;
89 }
90 /* }}} */
91
zend_wrong_param_count(void)92 ZEND_API ZEND_COLD void zend_wrong_param_count(void) /* {{{ */
93 {
94 const char *space;
95 const char *class_name = get_active_class_name(&space);
96
97 zend_argument_count_error("Wrong parameter count for %s%s%s()", class_name, space, get_active_function_name());
98 }
99 /* }}} */
100
zend_wrong_property_read(zval * object,zval * property)101 ZEND_API ZEND_COLD void zend_wrong_property_read(zval *object, zval *property)
102 {
103 zend_string *tmp_property_name;
104 zend_string *property_name = zval_get_tmp_string(property, &tmp_property_name);
105 zend_error(E_WARNING, "Attempt to read property \"%s\" on %s", ZSTR_VAL(property_name), zend_zval_value_name(object));
106 zend_tmp_string_release(tmp_property_name);
107 }
108
109 /* Argument parsing API -- andrei */
zend_get_type_by_const(int type)110 ZEND_API const char *zend_get_type_by_const(int type) /* {{{ */
111 {
112 switch(type) {
113 case IS_FALSE:
114 case IS_TRUE:
115 case _IS_BOOL:
116 return "bool";
117 case IS_LONG:
118 return "int";
119 case IS_DOUBLE:
120 return "float";
121 case IS_STRING:
122 return "string";
123 case IS_OBJECT:
124 return "object";
125 case IS_RESOURCE:
126 return "resource";
127 case IS_NULL:
128 return "null";
129 case IS_CALLABLE:
130 return "callable";
131 case IS_ITERABLE:
132 return "iterable";
133 case IS_ARRAY:
134 return "array";
135 case IS_VOID:
136 return "void";
137 case IS_MIXED:
138 return "mixed";
139 case _IS_NUMBER:
140 return "int|float";
141 EMPTY_SWITCH_DEFAULT_CASE()
142 }
143 }
144 /* }}} */
145
zend_zval_value_name(const zval * arg)146 ZEND_API const char *zend_zval_value_name(const zval *arg)
147 {
148 ZVAL_DEREF(arg);
149
150 if (Z_ISUNDEF_P(arg)) {
151 return "null";
152 }
153
154 if (Z_TYPE_P(arg) == IS_OBJECT) {
155 return ZSTR_VAL(Z_OBJCE_P(arg)->name);
156 } else if (Z_TYPE_P(arg) == IS_FALSE) {
157 return "false";
158 } else if (Z_TYPE_P(arg) == IS_TRUE) {
159 return "true";
160 }
161
162 return zend_get_type_by_const(Z_TYPE_P(arg));
163 }
164
zend_zval_type_name(const zval * arg)165 ZEND_API const char *zend_zval_type_name(const zval *arg)
166 {
167 ZVAL_DEREF(arg);
168
169 if (Z_ISUNDEF_P(arg)) {
170 return "null";
171 }
172
173 if (Z_TYPE_P(arg) == IS_OBJECT) {
174 return ZSTR_VAL(Z_OBJCE_P(arg)->name);
175 }
176
177 return zend_get_type_by_const(Z_TYPE_P(arg));
178 }
179
180 /* This API exists *only* for use in gettype().
181 * For anything else, you likely want zend_zval_type_name(). */
zend_zval_get_legacy_type(const zval * arg)182 ZEND_API zend_string *zend_zval_get_legacy_type(const zval *arg) /* {{{ */
183 {
184 switch (Z_TYPE_P(arg)) {
185 case IS_NULL:
186 return ZSTR_KNOWN(ZEND_STR_NULL);
187 case IS_FALSE:
188 case IS_TRUE:
189 return ZSTR_KNOWN(ZEND_STR_BOOLEAN);
190 case IS_LONG:
191 return ZSTR_KNOWN(ZEND_STR_INTEGER);
192 case IS_DOUBLE:
193 return ZSTR_KNOWN(ZEND_STR_DOUBLE);
194 case IS_STRING:
195 return ZSTR_KNOWN(ZEND_STR_STRING);
196 case IS_ARRAY:
197 return ZSTR_KNOWN(ZEND_STR_ARRAY);
198 case IS_OBJECT:
199 return ZSTR_KNOWN(ZEND_STR_OBJECT);
200 case IS_RESOURCE:
201 if (zend_rsrc_list_get_rsrc_type(Z_RES_P(arg))) {
202 return ZSTR_KNOWN(ZEND_STR_RESOURCE);
203 } else {
204 return ZSTR_KNOWN(ZEND_STR_CLOSED_RESOURCE);
205 }
206 default:
207 return NULL;
208 }
209 }
210 /* }}} */
211
zend_wrong_parameters_none_error(void)212 ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameters_none_error(void) /* {{{ */
213 {
214 int num_args = ZEND_CALL_NUM_ARGS(EG(current_execute_data));
215 zend_string *func_name = get_active_function_or_method_name();
216
217 zend_argument_count_error("%s() expects exactly 0 arguments, %d given", ZSTR_VAL(func_name), num_args);
218
219 zend_string_release(func_name);
220 }
221 /* }}} */
222
zend_wrong_parameters_count_error(uint32_t min_num_args,uint32_t max_num_args)223 ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameters_count_error(uint32_t min_num_args, uint32_t max_num_args) /* {{{ */
224 {
225 uint32_t num_args = ZEND_CALL_NUM_ARGS(EG(current_execute_data));
226 zend_string *func_name = get_active_function_or_method_name();
227
228 zend_argument_count_error(
229 "%s() expects %s %d argument%s, %d given",
230 ZSTR_VAL(func_name),
231 min_num_args == max_num_args ? "exactly" : num_args < min_num_args ? "at least" : "at most",
232 num_args < min_num_args ? min_num_args : max_num_args,
233 (num_args < min_num_args ? min_num_args : max_num_args) == 1 ? "" : "s",
234 num_args
235 );
236
237 zend_string_release(func_name);
238 }
239 /* }}} */
240
zend_wrong_parameter_error(int error_code,uint32_t num,char * name,zend_expected_type expected_type,zval * arg)241 ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_error(int error_code, uint32_t num, char *name, zend_expected_type expected_type, zval *arg) /* {{{ */
242 {
243 switch (error_code) {
244 case ZPP_ERROR_WRONG_CALLBACK:
245 zend_wrong_callback_error(num, name);
246 break;
247 case ZPP_ERROR_WRONG_CALLBACK_OR_NULL:
248 zend_wrong_callback_or_null_error(num, name);
249 break;
250 case ZPP_ERROR_WRONG_CLASS:
251 zend_wrong_parameter_class_error(num, name, arg);
252 break;
253 case ZPP_ERROR_WRONG_CLASS_OR_NULL:
254 zend_wrong_parameter_class_or_null_error(num, name, arg);
255 break;
256 case ZPP_ERROR_WRONG_CLASS_OR_STRING:
257 zend_wrong_parameter_class_or_string_error(num, name, arg);
258 break;
259 case ZPP_ERROR_WRONG_CLASS_OR_STRING_OR_NULL:
260 zend_wrong_parameter_class_or_string_or_null_error(num, name, arg);
261 break;
262 case ZPP_ERROR_WRONG_CLASS_OR_LONG:
263 zend_wrong_parameter_class_or_long_error(num, name, arg);
264 break;
265 case ZPP_ERROR_WRONG_CLASS_OR_LONG_OR_NULL:
266 zend_wrong_parameter_class_or_long_or_null_error(num, name, arg);
267 break;
268 case ZPP_ERROR_WRONG_ARG:
269 zend_wrong_parameter_type_error(num, expected_type, arg);
270 break;
271 case ZPP_ERROR_UNEXPECTED_EXTRA_NAMED:
272 zend_unexpected_extra_named_error();
273 break;
274 case ZPP_ERROR_FAILURE:
275 ZEND_ASSERT(EG(exception) && "Should have produced an error already");
276 break;
277 EMPTY_SWITCH_DEFAULT_CASE()
278 }
279 }
280 /* }}} */
281
zend_wrong_parameter_type_error(uint32_t num,zend_expected_type expected_type,zval * arg)282 ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_type_error(uint32_t num, zend_expected_type expected_type, zval *arg) /* {{{ */
283 {
284 static const char * const expected_error[] = {
285 Z_EXPECTED_TYPES(Z_EXPECTED_TYPE_STR)
286 NULL
287 };
288
289 if (EG(exception)) {
290 return;
291 }
292
293 if ((expected_type == Z_EXPECTED_PATH || expected_type == Z_EXPECTED_PATH_OR_NULL)
294 && Z_TYPE_P(arg) == IS_STRING) {
295 zend_argument_value_error(num, "must not contain any null bytes");
296 return;
297 }
298
299 zend_argument_type_error(num, "must be %s, %s given", expected_error[expected_type], zend_zval_value_name(arg));
300 }
301 /* }}} */
302
zend_wrong_parameter_class_error(uint32_t num,const char * name,zval * arg)303 ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_class_error(uint32_t num, const char *name, zval *arg) /* {{{ */
304 {
305 if (EG(exception)) {
306 return;
307 }
308
309 zend_argument_type_error(num, "must be of type %s, %s given", name, zend_zval_value_name(arg));
310 }
311 /* }}} */
312
zend_wrong_parameter_class_or_null_error(uint32_t num,const char * name,zval * arg)313 ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_class_or_null_error(uint32_t num, const char *name, zval *arg) /* {{{ */
314 {
315 if (EG(exception)) {
316 return;
317 }
318
319 zend_argument_type_error(num, "must be of type ?%s, %s given", name, zend_zval_value_name(arg));
320 }
321 /* }}} */
322
zend_wrong_parameter_class_or_long_error(uint32_t num,const char * name,zval * arg)323 ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_class_or_long_error(uint32_t num, const char *name, zval *arg) /* {{{ */
324 {
325 if (EG(exception)) {
326 return;
327 }
328
329 zend_argument_type_error(num, "must be of type %s|int, %s given", name, zend_zval_value_name(arg));
330 }
331 /* }}} */
332
zend_wrong_parameter_class_or_long_or_null_error(uint32_t num,const char * name,zval * arg)333 ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_class_or_long_or_null_error(uint32_t num, const char *name, zval *arg) /* {{{ */
334 {
335 if (EG(exception)) {
336 return;
337 }
338
339 zend_argument_type_error(num, "must be of type %s|int|null, %s given", name, zend_zval_value_name(arg));
340 }
341 /* }}} */
342
zend_wrong_parameter_class_or_string_error(uint32_t num,const char * name,zval * arg)343 ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_class_or_string_error(uint32_t num, const char *name, zval *arg) /* {{{ */
344 {
345 if (EG(exception)) {
346 return;
347 }
348
349 zend_argument_type_error(num, "must be of type %s|string, %s given", name, zend_zval_value_name(arg));
350 }
351 /* }}} */
352
zend_wrong_parameter_class_or_string_or_null_error(uint32_t num,const char * name,zval * arg)353 ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_parameter_class_or_string_or_null_error(uint32_t num, const char *name, zval *arg) /* {{{ */
354 {
355 if (EG(exception)) {
356 return;
357 }
358
359 zend_argument_type_error(num, "must be of type %s|string|null, %s given", name, zend_zval_value_name(arg));
360 }
361 /* }}} */
362
zend_wrong_callback_error(uint32_t num,char * error)363 ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_callback_error(uint32_t num, char *error) /* {{{ */
364 {
365 if (!EG(exception)) {
366 zend_argument_type_error(num, "must be a valid callback, %s", error);
367 }
368 efree(error);
369 }
370 /* }}} */
371
zend_wrong_callback_or_null_error(uint32_t num,char * error)372 ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_callback_or_null_error(uint32_t num, char *error) /* {{{ */
373 {
374 if (!EG(exception)) {
375 zend_argument_type_error(num, "must be a valid callback or null, %s", error);
376 }
377 efree(error);
378 }
379 /* }}} */
380
zend_unexpected_extra_named_error(void)381 ZEND_API ZEND_COLD void ZEND_FASTCALL zend_unexpected_extra_named_error(void)
382 {
383 const char *space;
384 const char *class_name = get_active_class_name(&space);
385 zend_argument_count_error("%s%s%s() does not accept unknown named parameters",
386 class_name, space, get_active_function_name());
387 }
388
zend_argument_error_variadic(zend_class_entry * error_ce,uint32_t arg_num,const char * format,va_list va)389 ZEND_API ZEND_COLD void ZEND_FASTCALL zend_argument_error_variadic(zend_class_entry *error_ce, uint32_t arg_num, const char *format, va_list va) /* {{{ */
390 {
391 zend_string *func_name;
392 const char *arg_name;
393 char *message = NULL;
394 if (EG(exception)) {
395 return;
396 }
397
398 func_name = get_active_function_or_method_name();
399 arg_name = get_active_function_arg_name(arg_num);
400
401 zend_vspprintf(&message, 0, format, va);
402 zend_throw_error(error_ce, "%s(): Argument #%d%s%s%s %s",
403 ZSTR_VAL(func_name), arg_num,
404 arg_name ? " ($" : "", arg_name ? arg_name : "", arg_name ? ")" : "", message
405 );
406 efree(message);
407 zend_string_release(func_name);
408 }
409 /* }}} */
410
zend_argument_error(zend_class_entry * error_ce,uint32_t arg_num,const char * format,...)411 ZEND_API ZEND_COLD void zend_argument_error(zend_class_entry *error_ce, uint32_t arg_num, const char *format, ...) /* {{{ */
412 {
413 va_list va;
414
415 va_start(va, format);
416 zend_argument_error_variadic(error_ce, arg_num, format, va);
417 va_end(va);
418 }
419 /* }}} */
420
zend_argument_type_error(uint32_t arg_num,const char * format,...)421 ZEND_API ZEND_COLD void zend_argument_type_error(uint32_t arg_num, const char *format, ...) /* {{{ */
422 {
423 va_list va;
424
425 va_start(va, format);
426 zend_argument_error_variadic(zend_ce_type_error, arg_num, format, va);
427 va_end(va);
428 }
429 /* }}} */
430
zend_argument_value_error(uint32_t arg_num,const char * format,...)431 ZEND_API ZEND_COLD void zend_argument_value_error(uint32_t arg_num, const char *format, ...) /* {{{ */
432 {
433 va_list va;
434
435 va_start(va, format);
436 zend_argument_error_variadic(zend_ce_value_error, arg_num, format, va);
437 va_end(va);
438 }
439 /* }}} */
440
zend_parse_arg_class(zval * arg,zend_class_entry ** pce,uint32_t num,bool check_null)441 ZEND_API bool ZEND_FASTCALL zend_parse_arg_class(zval *arg, zend_class_entry **pce, uint32_t num, bool check_null) /* {{{ */
442 {
443 zend_class_entry *ce_base = *pce;
444
445 if (check_null && Z_TYPE_P(arg) == IS_NULL) {
446 *pce = NULL;
447 return 1;
448 }
449 if (!try_convert_to_string(arg)) {
450 *pce = NULL;
451 return 0;
452 }
453
454 *pce = zend_lookup_class(Z_STR_P(arg));
455 if (ce_base) {
456 if ((!*pce || !instanceof_function(*pce, ce_base))) {
457 zend_argument_type_error(num, "must be a class name derived from %s, %s given", ZSTR_VAL(ce_base->name), Z_STRVAL_P(arg));
458 *pce = NULL;
459 return 0;
460 }
461 }
462 if (!*pce) {
463 zend_argument_type_error(num, "must be a valid class name, %s given", Z_STRVAL_P(arg));
464 return 0;
465 }
466 return 1;
467 }
468 /* }}} */
469
zend_null_arg_deprecated(const char * fallback_type,uint32_t arg_num)470 static ZEND_COLD bool zend_null_arg_deprecated(const char *fallback_type, uint32_t arg_num) {
471 zend_function *func = EG(current_execute_data)->func;
472 ZEND_ASSERT(arg_num > 0);
473 uint32_t arg_offset = arg_num - 1;
474 if (arg_offset >= func->common.num_args) {
475 ZEND_ASSERT(func->common.fn_flags & ZEND_ACC_VARIADIC);
476 arg_offset = func->common.num_args;
477 }
478
479 zend_arg_info *arg_info = &func->common.arg_info[arg_offset];
480 zend_string *func_name = get_active_function_or_method_name();
481 const char *arg_name = get_active_function_arg_name(arg_num);
482
483 /* If no type is specified in arginfo, use the specified fallback_type determined through
484 * zend_parse_parameters instead. */
485 zend_string *type_str = zend_type_to_string(arg_info->type);
486 const char *type = type_str ? ZSTR_VAL(type_str) : fallback_type;
487 zend_error(E_DEPRECATED,
488 "%s(): Passing null to parameter #%" PRIu32 "%s%s%s of type %s is deprecated",
489 ZSTR_VAL(func_name), arg_num,
490 arg_name ? " ($" : "", arg_name ? arg_name : "", arg_name ? ")" : "",
491 type);
492 zend_string_release(func_name);
493 if (type_str) {
494 zend_string_release(type_str);
495 }
496 return !EG(exception);
497 }
498
zend_parse_arg_bool_weak(const zval * arg,bool * dest,uint32_t arg_num)499 ZEND_API bool ZEND_FASTCALL zend_parse_arg_bool_weak(const zval *arg, bool *dest, uint32_t arg_num) /* {{{ */
500 {
501 if (EXPECTED(Z_TYPE_P(arg) <= IS_STRING)) {
502 if (UNEXPECTED(Z_TYPE_P(arg) == IS_NULL) && !zend_null_arg_deprecated("bool", arg_num)) {
503 return 0;
504 }
505 *dest = zend_is_true(arg);
506 } else {
507 return 0;
508 }
509 return 1;
510 }
511 /* }}} */
512
zend_parse_arg_bool_slow(const zval * arg,bool * dest,uint32_t arg_num)513 ZEND_API bool ZEND_FASTCALL zend_parse_arg_bool_slow(const zval *arg, bool *dest, uint32_t arg_num) /* {{{ */
514 {
515 if (UNEXPECTED(ZEND_ARG_USES_STRICT_TYPES())) {
516 return 0;
517 }
518 return zend_parse_arg_bool_weak(arg, dest, arg_num);
519 }
520 /* }}} */
521
zend_parse_arg_long_weak(const zval * arg,zend_long * dest,uint32_t arg_num)522 ZEND_API bool ZEND_FASTCALL zend_parse_arg_long_weak(const zval *arg, zend_long *dest, uint32_t arg_num) /* {{{ */
523 {
524 if (EXPECTED(Z_TYPE_P(arg) == IS_DOUBLE)) {
525 if (UNEXPECTED(zend_isnan(Z_DVAL_P(arg)))) {
526 return 0;
527 }
528 if (UNEXPECTED(!ZEND_DOUBLE_FITS_LONG(Z_DVAL_P(arg)))) {
529 return 0;
530 } else {
531 zend_long lval = zend_dval_to_lval(Z_DVAL_P(arg));
532 if (UNEXPECTED(!zend_is_long_compatible(Z_DVAL_P(arg), lval))) {
533 /* Check arg_num is not (uint32_t)-1, as otherwise its called by
534 * zend_verify_weak_scalar_type_hint_no_sideeffect() */
535 if (arg_num != (uint32_t)-1) {
536 zend_incompatible_double_to_long_error(Z_DVAL_P(arg));
537 }
538 if (UNEXPECTED(EG(exception))) {
539 return 0;
540 }
541 }
542 *dest = lval;
543 }
544 } else if (EXPECTED(Z_TYPE_P(arg) == IS_STRING)) {
545 double d;
546 uint8_t type;
547
548 if (UNEXPECTED((type = is_numeric_str_function(Z_STR_P(arg), dest, &d)) != IS_LONG)) {
549 if (EXPECTED(type != 0)) {
550 zend_long lval;
551 if (UNEXPECTED(zend_isnan(d))) {
552 return 0;
553 }
554 if (UNEXPECTED(!ZEND_DOUBLE_FITS_LONG(d))) {
555 return 0;
556 }
557
558 lval = zend_dval_to_lval(d);
559 /* This only checks for a fractional part as if doesn't fit it already throws a TypeError */
560 if (UNEXPECTED(!zend_is_long_compatible(d, lval))) {
561 /* Check arg_num is not (uint32_t)-1, as otherwise its called by
562 * zend_verify_weak_scalar_type_hint_no_sideeffect() */
563 if (arg_num != (uint32_t)-1) {
564 zend_incompatible_string_to_long_error(Z_STR_P(arg));
565 }
566 if (UNEXPECTED(EG(exception))) {
567 return 0;
568 }
569 }
570 *dest = lval;
571 } else {
572 return 0;
573 }
574 }
575 if (UNEXPECTED(EG(exception))) {
576 return 0;
577 }
578 } else if (EXPECTED(Z_TYPE_P(arg) < IS_TRUE)) {
579 if (UNEXPECTED(Z_TYPE_P(arg) == IS_NULL) && !zend_null_arg_deprecated("int", arg_num)) {
580 return 0;
581 }
582 *dest = 0;
583 } else if (EXPECTED(Z_TYPE_P(arg) == IS_TRUE)) {
584 *dest = 1;
585 } else {
586 return 0;
587 }
588 return 1;
589 }
590 /* }}} */
591
zend_parse_arg_long_slow(const zval * arg,zend_long * dest,uint32_t arg_num)592 ZEND_API bool ZEND_FASTCALL zend_parse_arg_long_slow(const zval *arg, zend_long *dest, uint32_t arg_num) /* {{{ */
593 {
594 if (UNEXPECTED(ZEND_ARG_USES_STRICT_TYPES())) {
595 return 0;
596 }
597 return zend_parse_arg_long_weak(arg, dest, arg_num);
598 }
599 /* }}} */
600
zend_parse_arg_double_weak(const zval * arg,double * dest,uint32_t arg_num)601 ZEND_API bool ZEND_FASTCALL zend_parse_arg_double_weak(const zval *arg, double *dest, uint32_t arg_num) /* {{{ */
602 {
603 if (EXPECTED(Z_TYPE_P(arg) == IS_LONG)) {
604 *dest = (double)Z_LVAL_P(arg);
605 } else if (EXPECTED(Z_TYPE_P(arg) == IS_STRING)) {
606 zend_long l;
607 uint8_t type;
608
609 if (UNEXPECTED((type = is_numeric_str_function(Z_STR_P(arg), &l, dest)) != IS_DOUBLE)) {
610 if (EXPECTED(type != 0)) {
611 *dest = (double)(l);
612 } else {
613 return 0;
614 }
615 }
616 if (UNEXPECTED(EG(exception))) {
617 return 0;
618 }
619 } else if (EXPECTED(Z_TYPE_P(arg) < IS_TRUE)) {
620 if (UNEXPECTED(Z_TYPE_P(arg) == IS_NULL) && !zend_null_arg_deprecated("float", arg_num)) {
621 return 0;
622 }
623 *dest = 0.0;
624 } else if (EXPECTED(Z_TYPE_P(arg) == IS_TRUE)) {
625 *dest = 1.0;
626 } else {
627 return 0;
628 }
629 return 1;
630 }
631 /* }}} */
632
zend_parse_arg_double_slow(const zval * arg,double * dest,uint32_t arg_num)633 ZEND_API bool ZEND_FASTCALL zend_parse_arg_double_slow(const zval *arg, double *dest, uint32_t arg_num) /* {{{ */
634 {
635 if (EXPECTED(Z_TYPE_P(arg) == IS_LONG)) {
636 /* SSTH Exception: IS_LONG may be accepted instead as IS_DOUBLE */
637 *dest = (double)Z_LVAL_P(arg);
638 } else if (UNEXPECTED(ZEND_ARG_USES_STRICT_TYPES())) {
639 return 0;
640 }
641 return zend_parse_arg_double_weak(arg, dest, arg_num);
642 }
643 /* }}} */
644
zend_parse_arg_number_slow(zval * arg,zval ** dest,uint32_t arg_num)645 ZEND_API bool ZEND_FASTCALL zend_parse_arg_number_slow(zval *arg, zval **dest, uint32_t arg_num) /* {{{ */
646 {
647 if (UNEXPECTED(ZEND_ARG_USES_STRICT_TYPES())) {
648 return 0;
649 }
650 if (Z_TYPE_P(arg) == IS_STRING) {
651 zend_string *str = Z_STR_P(arg);
652 zend_long lval;
653 double dval;
654 uint8_t type = is_numeric_str_function(str, &lval, &dval);
655 if (type == IS_LONG) {
656 ZVAL_LONG(arg, lval);
657 } else if (type == IS_DOUBLE) {
658 ZVAL_DOUBLE(arg, dval);
659 } else {
660 return 0;
661 }
662 zend_string_release(str);
663 } else if (Z_TYPE_P(arg) < IS_TRUE) {
664 if (UNEXPECTED(Z_TYPE_P(arg) == IS_NULL) && !zend_null_arg_deprecated("int|float", arg_num)) {
665 return 0;
666 }
667 ZVAL_LONG(arg, 0);
668 } else if (Z_TYPE_P(arg) == IS_TRUE) {
669 ZVAL_LONG(arg, 1);
670 } else {
671 return 0;
672 }
673 *dest = arg;
674 return 1;
675 }
676 /* }}} */
677
678
zend_parse_arg_number_or_str_slow(zval * arg,zval ** dest,uint32_t arg_num)679 ZEND_API bool ZEND_FASTCALL zend_parse_arg_number_or_str_slow(zval *arg, zval **dest, uint32_t arg_num) /* {{{ */
680 {
681 if (UNEXPECTED(ZEND_ARG_USES_STRICT_TYPES())) {
682 return false;
683 }
684 if (Z_TYPE_P(arg) < IS_TRUE) {
685 if (UNEXPECTED(Z_TYPE_P(arg) == IS_NULL) && !zend_null_arg_deprecated("string|int|float", arg_num)) {
686 return false;
687 }
688 ZVAL_LONG(arg, 0);
689 } else if (Z_TYPE_P(arg) == IS_TRUE) {
690 ZVAL_LONG(arg, 1);
691 } else if (UNEXPECTED(Z_TYPE_P(arg) == IS_OBJECT)) {
692 zend_object *zobj = Z_OBJ_P(arg);
693 zval obj;
694 if (zobj->handlers->cast_object(zobj, &obj, IS_STRING) == SUCCESS) {
695 OBJ_RELEASE(zobj);
696 ZVAL_COPY_VALUE(arg, &obj);
697 *dest = arg;
698 return true;
699 }
700 return false;
701 } else {
702 return false;
703 }
704 *dest = arg;
705 return true;
706 }
707
zend_parse_arg_str_weak(zval * arg,zend_string ** dest,uint32_t arg_num)708 ZEND_API bool ZEND_FASTCALL zend_parse_arg_str_weak(zval *arg, zend_string **dest, uint32_t arg_num) /* {{{ */
709 {
710 if (EXPECTED(Z_TYPE_P(arg) < IS_STRING)) {
711 if (UNEXPECTED(Z_TYPE_P(arg) == IS_NULL) && !zend_null_arg_deprecated("string", arg_num)) {
712 return 0;
713 }
714 convert_to_string(arg);
715 *dest = Z_STR_P(arg);
716 } else if (UNEXPECTED(Z_TYPE_P(arg) == IS_OBJECT)) {
717 zend_object *zobj = Z_OBJ_P(arg);
718 zval obj;
719 if (zobj->handlers->cast_object(zobj, &obj, IS_STRING) == SUCCESS) {
720 OBJ_RELEASE(zobj);
721 ZVAL_COPY_VALUE(arg, &obj);
722 *dest = Z_STR_P(arg);
723 return 1;
724 }
725 return 0;
726 } else {
727 return 0;
728 }
729 return 1;
730 }
731 /* }}} */
732
zend_parse_arg_str_slow(zval * arg,zend_string ** dest,uint32_t arg_num)733 ZEND_API bool ZEND_FASTCALL zend_parse_arg_str_slow(zval *arg, zend_string **dest, uint32_t arg_num) /* {{{ */
734 {
735 if (UNEXPECTED(ZEND_ARG_USES_STRICT_TYPES())) {
736 return 0;
737 }
738 return zend_parse_arg_str_weak(arg, dest, arg_num);
739 }
740 /* }}} */
741
zend_parse_arg_str_or_long_slow(zval * arg,zend_string ** dest_str,zend_long * dest_long,uint32_t arg_num)742 ZEND_API bool ZEND_FASTCALL zend_parse_arg_str_or_long_slow(zval *arg, zend_string **dest_str, zend_long *dest_long, uint32_t arg_num) /* {{{ */
743 {
744 if (UNEXPECTED(ZEND_ARG_USES_STRICT_TYPES())) {
745 return 0;
746 }
747 if (zend_parse_arg_long_weak(arg, dest_long, arg_num)) {
748 *dest_str = NULL;
749 return 1;
750 } else if (zend_parse_arg_str_weak(arg, dest_str, arg_num)) {
751 *dest_long = 0;
752 return 1;
753 } else {
754 return 0;
755 }
756 }
757 /* }}} */
758
zend_parse_arg_impl(zval * arg,va_list * va,const char ** spec,char ** error,uint32_t arg_num)759 static const char *zend_parse_arg_impl(zval *arg, va_list *va, const char **spec, char **error, uint32_t arg_num) /* {{{ */
760 {
761 const char *spec_walk = *spec;
762 char c = *spec_walk++;
763 bool check_null = 0;
764 bool separate = 0;
765 zval *real_arg = arg;
766
767 /* scan through modifiers */
768 ZVAL_DEREF(arg);
769 while (1) {
770 if (*spec_walk == '/') {
771 SEPARATE_ZVAL_NOREF(arg);
772 real_arg = arg;
773 separate = 1;
774 } else if (*spec_walk == '!') {
775 check_null = 1;
776 } else {
777 break;
778 }
779 spec_walk++;
780 }
781
782 switch (c) {
783 case 'l':
784 {
785 zend_long *p = va_arg(*va, zend_long *);
786 bool *is_null = NULL;
787
788 if (check_null) {
789 is_null = va_arg(*va, bool *);
790 }
791
792 if (!zend_parse_arg_long(arg, p, is_null, check_null, arg_num)) {
793 return check_null ? "?int" : "int";
794 }
795 }
796 break;
797
798 case 'd':
799 {
800 double *p = va_arg(*va, double *);
801 bool *is_null = NULL;
802
803 if (check_null) {
804 is_null = va_arg(*va, bool *);
805 }
806
807 if (!zend_parse_arg_double(arg, p, is_null, check_null, arg_num)) {
808 return check_null ? "?float" : "float";
809 }
810 }
811 break;
812
813 case 'n':
814 {
815 zval **p = va_arg(*va, zval **);
816
817 if (!zend_parse_arg_number(arg, p, check_null, arg_num)) {
818 return check_null ? "int|float|null" : "int|float";
819 }
820 }
821 break;
822
823 case 's':
824 {
825 char **p = va_arg(*va, char **);
826 size_t *pl = va_arg(*va, size_t *);
827 if (!zend_parse_arg_string(arg, p, pl, check_null, arg_num)) {
828 return check_null ? "?string" : "string";
829 }
830 }
831 break;
832
833 case 'p':
834 {
835 char **p = va_arg(*va, char **);
836 size_t *pl = va_arg(*va, size_t *);
837 if (!zend_parse_arg_path(arg, p, pl, check_null, arg_num)) {
838 if (Z_TYPE_P(arg) == IS_STRING) {
839 zend_spprintf(error, 0, "must not contain any null bytes");
840 return "";
841 } else {
842 return check_null ? "?string" : "string";
843 }
844 }
845 }
846 break;
847
848 case 'P':
849 {
850 zend_string **str = va_arg(*va, zend_string **);
851 if (!zend_parse_arg_path_str(arg, str, check_null, arg_num)) {
852 if (Z_TYPE_P(arg) == IS_STRING) {
853 zend_spprintf(error, 0, "must not contain any null bytes");
854 return "";
855 } else {
856 return check_null ? "?string" : "string";
857 }
858 }
859 }
860 break;
861
862 case 'S':
863 {
864 zend_string **str = va_arg(*va, zend_string **);
865 if (!zend_parse_arg_str(arg, str, check_null, arg_num)) {
866 return check_null ? "?string" : "string";
867 }
868 }
869 break;
870
871 case 'b':
872 {
873 bool *p = va_arg(*va, bool *);
874 bool *is_null = NULL;
875
876 if (check_null) {
877 is_null = va_arg(*va, bool *);
878 }
879
880 if (!zend_parse_arg_bool(arg, p, is_null, check_null, arg_num)) {
881 return check_null ? "?bool" : "bool";
882 }
883 }
884 break;
885
886 case 'r':
887 {
888 zval **p = va_arg(*va, zval **);
889
890 if (!zend_parse_arg_resource(arg, p, check_null)) {
891 return check_null ? "resource or null" : "resource";
892 }
893 }
894 break;
895
896 case 'A':
897 case 'a':
898 {
899 zval **p = va_arg(*va, zval **);
900
901 if (!zend_parse_arg_array(arg, p, check_null, c == 'A')) {
902 return check_null ? "?array" : "array";
903 }
904 }
905 break;
906
907 case 'H':
908 case 'h':
909 {
910 HashTable **p = va_arg(*va, HashTable **);
911
912 if (!zend_parse_arg_array_ht(arg, p, check_null, c == 'H', separate)) {
913 return check_null ? "?array" : "array";
914 }
915 }
916 break;
917
918 case 'o':
919 {
920 zval **p = va_arg(*va, zval **);
921
922 if (!zend_parse_arg_object(arg, p, NULL, check_null)) {
923 return check_null ? "?object" : "object";
924 }
925 }
926 break;
927
928 case 'O':
929 {
930 zval **p = va_arg(*va, zval **);
931 zend_class_entry *ce = va_arg(*va, zend_class_entry *);
932
933 if (!zend_parse_arg_object(arg, p, ce, check_null)) {
934 if (ce) {
935 if (check_null) {
936 zend_spprintf(error, 0, "must be of type ?%s, %s given", ZSTR_VAL(ce->name), zend_zval_value_name(arg));
937 return "";
938 } else {
939 return ZSTR_VAL(ce->name);
940 }
941 } else {
942 return check_null ? "?object" : "object";
943 }
944 }
945 }
946 break;
947
948 case 'C':
949 {
950 zend_class_entry *lookup, **pce = va_arg(*va, zend_class_entry **);
951 zend_class_entry *ce_base = *pce;
952
953 if (check_null && Z_TYPE_P(arg) == IS_NULL) {
954 *pce = NULL;
955 break;
956 }
957 if (!try_convert_to_string(arg)) {
958 *pce = NULL;
959 return ""; /* try_convert_to_string() throws an exception */
960 }
961
962 if ((lookup = zend_lookup_class(Z_STR_P(arg))) == NULL) {
963 *pce = NULL;
964 } else {
965 *pce = lookup;
966 }
967 if (ce_base) {
968 if ((!*pce || !instanceof_function(*pce, ce_base))) {
969 zend_spprintf(error, 0, "must be a class name derived from %s%s, %s given",
970 ZSTR_VAL(ce_base->name), check_null ? " or null" : "", Z_STRVAL_P(arg));
971 *pce = NULL;
972 return "";
973 }
974 }
975 if (!*pce) {
976 zend_spprintf(error, 0, "must be a valid class name%s, %s given",
977 check_null ? " or null" : "", Z_STRVAL_P(arg));
978 return "";
979 }
980 break;
981
982 }
983 break;
984
985 case 'f':
986 {
987 zend_fcall_info *fci = va_arg(*va, zend_fcall_info *);
988 zend_fcall_info_cache *fcc = va_arg(*va, zend_fcall_info_cache *);
989 char *is_callable_error = NULL;
990
991 if (check_null && Z_TYPE_P(arg) == IS_NULL) {
992 fci->size = 0;
993 fcc->function_handler = 0;
994 break;
995 }
996
997 if (zend_fcall_info_init(arg, 0, fci, fcc, NULL, &is_callable_error) == SUCCESS) {
998 ZEND_ASSERT(!is_callable_error);
999 /* Release call trampolines: The function may not get called, in which case
1000 * the trampoline will leak. Force it to be refetched during
1001 * zend_call_function instead. */
1002 zend_release_fcall_info_cache(fcc);
1003 break;
1004 }
1005
1006 if (is_callable_error) {
1007 zend_spprintf(error, 0, "must be a valid callback%s, %s", check_null ? " or null" : "", is_callable_error);
1008 efree(is_callable_error);
1009 return "";
1010 } else {
1011 return check_null ? "a valid callback or null" : "a valid callback";
1012 }
1013 }
1014
1015 case 'z':
1016 {
1017 zval **p = va_arg(*va, zval **);
1018
1019 zend_parse_arg_zval_deref(real_arg, p, check_null);
1020 }
1021 break;
1022
1023 case 'Z': /* replace with 'z' */
1024 case 'L': /* replace with 'l' */
1025 ZEND_ASSERT(0 && "ZPP modifier no longer supported");
1026 ZEND_FALLTHROUGH;
1027 default:
1028 return "unknown";
1029 }
1030
1031 *spec = spec_walk;
1032
1033 return NULL;
1034 }
1035 /* }}} */
1036
zend_parse_arg(uint32_t arg_num,zval * arg,va_list * va,const char ** spec,int flags)1037 static zend_result zend_parse_arg(uint32_t arg_num, zval *arg, va_list *va, const char **spec, int flags) /* {{{ */
1038 {
1039 const char *expected_type = NULL;
1040 char *error = NULL;
1041
1042 expected_type = zend_parse_arg_impl(arg, va, spec, &error, arg_num);
1043 if (expected_type) {
1044 if (EG(exception)) {
1045 return FAILURE;
1046 }
1047 if (!(flags & ZEND_PARSE_PARAMS_QUIET) && (*expected_type || error)) {
1048 if (error) {
1049 if (strcmp(error, "must not contain any null bytes") == 0) {
1050 zend_argument_value_error(arg_num, "%s", error);
1051 } else {
1052 zend_argument_type_error(arg_num, "%s", error);
1053 }
1054 efree(error);
1055 } else {
1056 zend_argument_type_error(arg_num, "must be of type %s, %s given", expected_type, zend_zval_value_name(arg));
1057 }
1058 } else if (error) {
1059 efree(error);
1060 }
1061
1062 return FAILURE;
1063 }
1064
1065 return SUCCESS;
1066 }
1067 /* }}} */
1068
zend_parse_parameter(int flags,uint32_t arg_num,zval * arg,const char * spec,...)1069 ZEND_API zend_result zend_parse_parameter(int flags, uint32_t arg_num, zval *arg, const char *spec, ...)
1070 {
1071 va_list va;
1072 zend_result ret;
1073
1074 va_start(va, spec);
1075 ret = zend_parse_arg(arg_num, arg, &va, &spec, flags);
1076 va_end(va);
1077
1078 return ret;
1079 }
1080
zend_parse_parameters_debug_error(const char * msg)1081 static ZEND_COLD void zend_parse_parameters_debug_error(const char *msg) {
1082 zend_function *active_function = EG(current_execute_data)->func;
1083 const char *class_name = active_function->common.scope
1084 ? ZSTR_VAL(active_function->common.scope->name) : "";
1085 zend_error_noreturn(E_CORE_ERROR, "%s%s%s(): %s",
1086 class_name, class_name[0] ? "::" : "",
1087 ZSTR_VAL(active_function->common.function_name), msg);
1088 }
1089
zend_parse_va_args(uint32_t num_args,const char * type_spec,va_list * va,int flags)1090 static zend_result zend_parse_va_args(uint32_t num_args, const char *type_spec, va_list *va, int flags) /* {{{ */
1091 {
1092 const char *spec_walk;
1093 char c;
1094 uint32_t i;
1095 uint32_t min_num_args = 0;
1096 uint32_t max_num_args = 0;
1097 uint32_t post_varargs = 0;
1098 zval *arg;
1099 bool have_varargs = 0;
1100 bool have_optional_args = 0;
1101 zval **varargs = NULL;
1102 uint32_t *n_varargs = NULL;
1103
1104 for (spec_walk = type_spec; *spec_walk; spec_walk++) {
1105 c = *spec_walk;
1106 switch (c) {
1107 case 'l': case 'd':
1108 case 's': case 'b':
1109 case 'r': case 'a':
1110 case 'o': case 'O':
1111 case 'z': case 'Z':
1112 case 'C': case 'h':
1113 case 'f': case 'A':
1114 case 'H': case 'p':
1115 case 'S': case 'P':
1116 case 'L': case 'n':
1117 max_num_args++;
1118 break;
1119
1120 case '|':
1121 min_num_args = max_num_args;
1122 have_optional_args = 1;
1123 break;
1124
1125 case '/':
1126 case '!':
1127 /* Pass */
1128 break;
1129
1130 case '*':
1131 case '+':
1132 if (have_varargs) {
1133 zend_parse_parameters_debug_error(
1134 "only one varargs specifier (* or +) is permitted");
1135 return FAILURE;
1136 }
1137 have_varargs = 1;
1138 /* we expect at least one parameter in varargs */
1139 if (c == '+') {
1140 max_num_args++;
1141 }
1142 /* mark the beginning of varargs */
1143 post_varargs = max_num_args;
1144
1145 if (ZEND_CALL_INFO(EG(current_execute_data)) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS) {
1146 zend_unexpected_extra_named_error();
1147 return FAILURE;
1148 }
1149 break;
1150
1151 default:
1152 zend_parse_parameters_debug_error("bad type specifier while parsing parameters");
1153 return FAILURE;
1154 }
1155 }
1156
1157 /* with no optional arguments the minimum number of arguments must be the same as the maximum */
1158 if (!have_optional_args) {
1159 min_num_args = max_num_args;
1160 }
1161
1162 if (have_varargs) {
1163 /* calculate how many required args are at the end of the specifier list */
1164 post_varargs = max_num_args - post_varargs;
1165 max_num_args = UINT32_MAX;
1166 }
1167
1168 if (num_args < min_num_args || num_args > max_num_args) {
1169 if (!(flags & ZEND_PARSE_PARAMS_QUIET)) {
1170 zend_string *func_name = get_active_function_or_method_name();
1171
1172 zend_argument_count_error("%s() expects %s %d argument%s, %d given",
1173 ZSTR_VAL(func_name),
1174 min_num_args == max_num_args ? "exactly" : num_args < min_num_args ? "at least" : "at most",
1175 num_args < min_num_args ? min_num_args : max_num_args,
1176 (num_args < min_num_args ? min_num_args : max_num_args) == 1 ? "" : "s",
1177 num_args
1178 );
1179
1180 zend_string_release(func_name);
1181 }
1182 return FAILURE;
1183 }
1184
1185 if (num_args > ZEND_CALL_NUM_ARGS(EG(current_execute_data))) {
1186 zend_parse_parameters_debug_error("could not obtain parameters for parsing");
1187 return FAILURE;
1188 }
1189
1190 i = 0;
1191 while (num_args-- > 0) {
1192 if (*type_spec == '|') {
1193 type_spec++;
1194 }
1195
1196 if (*type_spec == '*' || *type_spec == '+') {
1197 uint32_t num_varargs = num_args + 1 - post_varargs;
1198
1199 /* eat up the passed in storage even if it won't be filled in with varargs */
1200 varargs = va_arg(*va, zval **);
1201 n_varargs = va_arg(*va, uint32_t *);
1202 type_spec++;
1203
1204 if (num_varargs > 0) {
1205 *n_varargs = num_varargs;
1206 *varargs = ZEND_CALL_ARG(EG(current_execute_data), i + 1);
1207 /* adjust how many args we have left and restart loop */
1208 num_args += 1 - num_varargs;
1209 i += num_varargs;
1210 continue;
1211 } else {
1212 *varargs = NULL;
1213 *n_varargs = 0;
1214 }
1215 }
1216
1217 arg = ZEND_CALL_ARG(EG(current_execute_data), i + 1);
1218
1219 if (zend_parse_arg(i+1, arg, va, &type_spec, flags) == FAILURE) {
1220 /* clean up varargs array if it was used */
1221 if (varargs && *varargs) {
1222 *varargs = NULL;
1223 }
1224 return FAILURE;
1225 }
1226 i++;
1227 }
1228
1229 return SUCCESS;
1230 }
1231 /* }}} */
1232
zend_parse_parameters_ex(int flags,uint32_t num_args,const char * type_spec,...)1233 ZEND_API zend_result zend_parse_parameters_ex(int flags, uint32_t num_args, const char *type_spec, ...) /* {{{ */
1234 {
1235 va_list va;
1236 zend_result retval;
1237
1238 va_start(va, type_spec);
1239 retval = zend_parse_va_args(num_args, type_spec, &va, flags);
1240 va_end(va);
1241
1242 return retval;
1243 }
1244 /* }}} */
1245
zend_parse_parameters(uint32_t num_args,const char * type_spec,...)1246 ZEND_API zend_result zend_parse_parameters(uint32_t num_args, const char *type_spec, ...) /* {{{ */
1247 {
1248 va_list va;
1249 zend_result retval;
1250 int flags = 0;
1251
1252 va_start(va, type_spec);
1253 retval = zend_parse_va_args(num_args, type_spec, &va, flags);
1254 va_end(va);
1255
1256 return retval;
1257 }
1258 /* }}} */
1259
zend_parse_method_parameters(uint32_t num_args,zval * this_ptr,const char * type_spec,...)1260 ZEND_API zend_result zend_parse_method_parameters(uint32_t num_args, zval *this_ptr, const char *type_spec, ...) /* {{{ */
1261 {
1262 va_list va;
1263 zend_result retval;
1264 int flags = 0;
1265 const char *p = type_spec;
1266 zval **object;
1267 zend_class_entry *ce;
1268
1269 /* Just checking this_ptr is not enough, because fcall_common_helper does not set
1270 * Z_OBJ(EG(This)) to NULL when calling an internal function with common.scope == NULL.
1271 * In that case EG(This) would still be the $this from the calling code and we'd take the
1272 * wrong branch here. */
1273 bool is_method = EG(current_execute_data)->func->common.scope != NULL;
1274
1275 if (!is_method || !this_ptr || Z_TYPE_P(this_ptr) != IS_OBJECT) {
1276 va_start(va, type_spec);
1277 retval = zend_parse_va_args(num_args, type_spec, &va, flags);
1278 va_end(va);
1279 } else {
1280 p++;
1281
1282 va_start(va, type_spec);
1283
1284 object = va_arg(va, zval **);
1285 ce = va_arg(va, zend_class_entry *);
1286 *object = this_ptr;
1287
1288 if (ce && !instanceof_function(Z_OBJCE_P(this_ptr), ce)) {
1289 zend_error_noreturn(E_CORE_ERROR, "%s::%s() must be derived from %s::%s()",
1290 ZSTR_VAL(Z_OBJCE_P(this_ptr)->name), get_active_function_name(), ZSTR_VAL(ce->name), get_active_function_name());
1291 }
1292
1293 retval = zend_parse_va_args(num_args, p, &va, flags);
1294 va_end(va);
1295 }
1296 return retval;
1297 }
1298 /* }}} */
1299
zend_parse_method_parameters_ex(int flags,uint32_t num_args,zval * this_ptr,const char * type_spec,...)1300 ZEND_API zend_result zend_parse_method_parameters_ex(int flags, uint32_t num_args, zval *this_ptr, const char *type_spec, ...) /* {{{ */
1301 {
1302 va_list va;
1303 zend_result retval;
1304 const char *p = type_spec;
1305 zval **object;
1306 zend_class_entry *ce;
1307
1308 if (!this_ptr) {
1309 va_start(va, type_spec);
1310 retval = zend_parse_va_args(num_args, type_spec, &va, flags);
1311 va_end(va);
1312 } else {
1313 p++;
1314 va_start(va, type_spec);
1315
1316 object = va_arg(va, zval **);
1317 ce = va_arg(va, zend_class_entry *);
1318 *object = this_ptr;
1319
1320 if (ce && !instanceof_function(Z_OBJCE_P(this_ptr), ce)) {
1321 if (!(flags & ZEND_PARSE_PARAMS_QUIET)) {
1322 zend_error_noreturn(E_CORE_ERROR, "%s::%s() must be derived from %s::%s()",
1323 ZSTR_VAL(ce->name), get_active_function_name(), ZSTR_VAL(Z_OBJCE_P(this_ptr)->name), get_active_function_name());
1324 }
1325 va_end(va);
1326 return FAILURE;
1327 }
1328
1329 retval = zend_parse_va_args(num_args, p, &va, flags);
1330 va_end(va);
1331 }
1332 return retval;
1333 }
1334 /* }}} */
1335
1336 /* This function should be called after the constructor has been called
1337 * because it may call __set from the uninitialized object otherwise. */
zend_merge_properties(zval * obj,HashTable * properties)1338 ZEND_API void zend_merge_properties(zval *obj, HashTable *properties) /* {{{ */
1339 {
1340 zend_object *zobj = Z_OBJ_P(obj);
1341 zend_object_write_property_t write_property = zobj->handlers->write_property;
1342 zend_class_entry *old_scope = EG(fake_scope);
1343 zend_string *key;
1344 zval *value;
1345
1346 if (HT_IS_PACKED(properties)) {
1347 return;
1348 }
1349 EG(fake_scope) = Z_OBJCE_P(obj);
1350 ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(properties, key, value) {
1351 if (key) {
1352 write_property(zobj, key, value, NULL);
1353 }
1354 } ZEND_HASH_FOREACH_END();
1355 EG(fake_scope) = old_scope;
1356 }
1357 /* }}} */
1358
zend_allocate_mutable_data(zend_class_entry * class_type)1359 static zend_class_mutable_data *zend_allocate_mutable_data(zend_class_entry *class_type) /* {{{ */
1360 {
1361 zend_class_mutable_data *mutable_data;
1362
1363 ZEND_ASSERT(ZEND_MAP_PTR(class_type->mutable_data) != NULL);
1364 ZEND_ASSERT(ZEND_MAP_PTR_GET_IMM(class_type->mutable_data) == NULL);
1365
1366 mutable_data = zend_arena_alloc(&CG(arena), sizeof(zend_class_mutable_data));
1367 memset(mutable_data, 0, sizeof(zend_class_mutable_data));
1368 mutable_data->ce_flags = class_type->ce_flags;
1369 ZEND_MAP_PTR_SET_IMM(class_type->mutable_data, mutable_data);
1370
1371 return mutable_data;
1372 }
1373 /* }}} */
1374
zend_separate_class_constants_table(zend_class_entry * class_type)1375 ZEND_API HashTable *zend_separate_class_constants_table(zend_class_entry *class_type) /* {{{ */
1376 {
1377 zend_class_mutable_data *mutable_data;
1378 HashTable *constants_table;
1379 zend_string *key;
1380 zend_class_constant *new_c, *c;
1381
1382 constants_table = zend_arena_alloc(&CG(arena), sizeof(HashTable));
1383 zend_hash_init(constants_table, zend_hash_num_elements(&class_type->constants_table), NULL, NULL, 0);
1384 zend_hash_extend(constants_table, zend_hash_num_elements(&class_type->constants_table), 0);
1385
1386 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&class_type->constants_table, key, c) {
1387 if (c->ce == class_type) {
1388 if (Z_TYPE(c->value) == IS_CONSTANT_AST) {
1389 new_c = zend_arena_alloc(&CG(arena), sizeof(zend_class_constant));
1390 memcpy(new_c, c, sizeof(zend_class_constant));
1391 c = new_c;
1392 }
1393 Z_TRY_ADDREF(c->value);
1394 } else {
1395 if (Z_TYPE(c->value) == IS_CONSTANT_AST) {
1396 c = zend_hash_find_ptr(CE_CONSTANTS_TABLE(c->ce), key);
1397 ZEND_ASSERT(c);
1398 }
1399 }
1400 _zend_hash_append_ptr(constants_table, key, c);
1401 } ZEND_HASH_FOREACH_END();
1402
1403 ZEND_ASSERT(ZEND_MAP_PTR(class_type->mutable_data) != NULL);
1404
1405 mutable_data = ZEND_MAP_PTR_GET_IMM(class_type->mutable_data);
1406 if (!mutable_data) {
1407 mutable_data = zend_allocate_mutable_data(class_type);
1408 }
1409
1410 mutable_data->constants_table = constants_table;
1411
1412 return constants_table;
1413 }
1414
update_property(zval * val,zend_property_info * prop_info)1415 static zend_result update_property(zval *val, zend_property_info *prop_info) {
1416 if (ZEND_TYPE_IS_SET(prop_info->type)) {
1417 zval tmp;
1418
1419 ZVAL_COPY(&tmp, val);
1420 if (UNEXPECTED(zval_update_constant_ex(&tmp, prop_info->ce) != SUCCESS)) {
1421 zval_ptr_dtor(&tmp);
1422 return FAILURE;
1423 }
1424 /* property initializers must always be evaluated with strict types */;
1425 if (UNEXPECTED(!zend_verify_property_type(prop_info, &tmp, /* strict */ 1))) {
1426 zval_ptr_dtor(&tmp);
1427 return FAILURE;
1428 }
1429 zval_ptr_dtor(val);
1430 ZVAL_COPY_VALUE(val, &tmp);
1431 return SUCCESS;
1432 }
1433 return zval_update_constant_ex(val, prop_info->ce);
1434 }
1435
zend_update_class_constant(zend_class_constant * c,const zend_string * name,zend_class_entry * scope)1436 ZEND_API zend_result zend_update_class_constant(zend_class_constant *c, const zend_string *name, zend_class_entry *scope)
1437 {
1438 ZEND_ASSERT(Z_TYPE(c->value) == IS_CONSTANT_AST);
1439
1440 if (EXPECTED(!ZEND_TYPE_IS_SET(c->type) || ZEND_TYPE_PURE_MASK(c->type) == MAY_BE_ANY)) {
1441 return zval_update_constant_ex(&c->value, scope);
1442 }
1443
1444 zval tmp;
1445
1446 ZVAL_COPY(&tmp, &c->value);
1447 zend_result result = zval_update_constant_ex(&tmp, scope);
1448 if (result == FAILURE) {
1449 zval_ptr_dtor(&tmp);
1450 return FAILURE;
1451 }
1452
1453 if (UNEXPECTED(!zend_verify_class_constant_type(c, name, &tmp))) {
1454 zval_ptr_dtor(&tmp);
1455 return FAILURE;
1456 }
1457
1458 zval_ptr_dtor(&c->value);
1459 ZVAL_COPY_VALUE(&c->value, &tmp);
1460
1461 return SUCCESS;
1462 }
1463
zend_update_class_constants(zend_class_entry * class_type)1464 ZEND_API zend_result zend_update_class_constants(zend_class_entry *class_type) /* {{{ */
1465 {
1466 zend_class_mutable_data *mutable_data = NULL;
1467 zval *default_properties_table = NULL;
1468 zval *static_members_table = NULL;
1469 zend_class_constant *c;
1470 zval *val;
1471 uint32_t ce_flags;
1472
1473 ce_flags = class_type->ce_flags;
1474
1475 if (ce_flags & ZEND_ACC_CONSTANTS_UPDATED) {
1476 return SUCCESS;
1477 }
1478
1479 bool uses_mutable_data = ZEND_MAP_PTR(class_type->mutable_data) != NULL;
1480 if (uses_mutable_data) {
1481 mutable_data = ZEND_MAP_PTR_GET_IMM(class_type->mutable_data);
1482 if (mutable_data) {
1483 ce_flags = mutable_data->ce_flags;
1484 if (ce_flags & ZEND_ACC_CONSTANTS_UPDATED) {
1485 return SUCCESS;
1486 }
1487 } else {
1488 mutable_data = zend_allocate_mutable_data(class_type);
1489 }
1490 }
1491
1492 if (class_type->parent) {
1493 if (UNEXPECTED(zend_update_class_constants(class_type->parent) != SUCCESS)) {
1494 return FAILURE;
1495 }
1496 }
1497
1498 if (ce_flags & ZEND_ACC_HAS_AST_CONSTANTS) {
1499 HashTable *constants_table;
1500
1501 if (uses_mutable_data) {
1502 constants_table = mutable_data->constants_table;
1503 if (!constants_table) {
1504 constants_table = zend_separate_class_constants_table(class_type);
1505 }
1506 } else {
1507 constants_table = &class_type->constants_table;
1508 }
1509
1510 zend_string *name;
1511 ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(constants_table, name, val) {
1512 c = Z_PTR_P(val);
1513 if (Z_TYPE(c->value) == IS_CONSTANT_AST) {
1514 if (c->ce != class_type) {
1515 Z_PTR_P(val) = c = zend_hash_find_ptr(CE_CONSTANTS_TABLE(c->ce), name);
1516 if (Z_TYPE(c->value) != IS_CONSTANT_AST) {
1517 continue;
1518 }
1519 }
1520
1521 val = &c->value;
1522 if (UNEXPECTED(zend_update_class_constant(c, name, c->ce) != SUCCESS)) {
1523 return FAILURE;
1524 }
1525 }
1526 } ZEND_HASH_FOREACH_END();
1527 }
1528
1529 if (class_type->default_static_members_count) {
1530 static_members_table = CE_STATIC_MEMBERS(class_type);
1531 if (!static_members_table) {
1532 zend_class_init_statics(class_type);
1533 static_members_table = CE_STATIC_MEMBERS(class_type);
1534 }
1535 }
1536
1537 default_properties_table = class_type->default_properties_table;
1538 if (uses_mutable_data && (ce_flags & ZEND_ACC_HAS_AST_PROPERTIES)) {
1539 zval *src, *dst, *end;
1540
1541 default_properties_table = mutable_data->default_properties_table;
1542 if (!default_properties_table) {
1543 default_properties_table = zend_arena_alloc(&CG(arena), sizeof(zval) * class_type->default_properties_count);
1544 src = class_type->default_properties_table;
1545 dst = default_properties_table;
1546 end = dst + class_type->default_properties_count;
1547 do {
1548 ZVAL_COPY_PROP(dst, src);
1549 src++;
1550 dst++;
1551 } while (dst != end);
1552 mutable_data->default_properties_table = default_properties_table;
1553 }
1554 }
1555
1556 if (ce_flags & (ZEND_ACC_HAS_AST_PROPERTIES|ZEND_ACC_HAS_AST_STATICS)) {
1557 zend_property_info *prop_info;
1558
1559 /* Use the default properties table to also update initializers of private properties
1560 * that have been shadowed in a child class. */
1561 for (uint32_t i = 0; i < class_type->default_properties_count; i++) {
1562 val = &default_properties_table[i];
1563 prop_info = class_type->properties_info_table[i];
1564 if (Z_TYPE_P(val) == IS_CONSTANT_AST
1565 && UNEXPECTED(update_property(val, prop_info) != SUCCESS)) {
1566 return FAILURE;
1567 }
1568 }
1569
1570 if (class_type->default_static_members_count) {
1571 ZEND_HASH_MAP_FOREACH_PTR(&class_type->properties_info, prop_info) {
1572 if (prop_info->flags & ZEND_ACC_STATIC) {
1573 val = static_members_table + prop_info->offset;
1574 if (Z_TYPE_P(val) == IS_CONSTANT_AST
1575 && UNEXPECTED(update_property(val, prop_info) != SUCCESS)) {
1576 return FAILURE;
1577 }
1578 }
1579 } ZEND_HASH_FOREACH_END();
1580 }
1581 }
1582
1583 if (class_type->type == ZEND_USER_CLASS && class_type->ce_flags & ZEND_ACC_ENUM && class_type->enum_backing_type != IS_UNDEF) {
1584 if (zend_enum_build_backed_enum_table(class_type) == FAILURE) {
1585 return FAILURE;
1586 }
1587 }
1588
1589 ce_flags |= ZEND_ACC_CONSTANTS_UPDATED;
1590 ce_flags &= ~ZEND_ACC_HAS_AST_CONSTANTS;
1591 ce_flags &= ~ZEND_ACC_HAS_AST_PROPERTIES;
1592 ce_flags &= ~ZEND_ACC_HAS_AST_STATICS;
1593 if (uses_mutable_data) {
1594 mutable_data->ce_flags = ce_flags;
1595 } else {
1596 class_type->ce_flags = ce_flags;
1597 }
1598
1599 return SUCCESS;
1600 }
1601 /* }}} */
1602
_object_properties_init(zend_object * object,zend_class_entry * class_type)1603 static zend_always_inline void _object_properties_init(zend_object *object, zend_class_entry *class_type) /* {{{ */
1604 {
1605 if (class_type->default_properties_count) {
1606 zval *src = CE_DEFAULT_PROPERTIES_TABLE(class_type);
1607 zval *dst = object->properties_table;
1608 zval *end = src + class_type->default_properties_count;
1609
1610 if (UNEXPECTED(class_type->type == ZEND_INTERNAL_CLASS)) {
1611 do {
1612 ZVAL_COPY_OR_DUP_PROP(dst, src);
1613 src++;
1614 dst++;
1615 } while (src != end);
1616 } else {
1617 do {
1618 ZVAL_COPY_PROP(dst, src);
1619 src++;
1620 dst++;
1621 } while (src != end);
1622 }
1623 }
1624 }
1625 /* }}} */
1626
object_properties_init(zend_object * object,zend_class_entry * class_type)1627 ZEND_API void object_properties_init(zend_object *object, zend_class_entry *class_type) /* {{{ */
1628 {
1629 object->properties = NULL;
1630 _object_properties_init(object, class_type);
1631 }
1632 /* }}} */
1633
object_properties_init_ex(zend_object * object,HashTable * properties)1634 ZEND_API void object_properties_init_ex(zend_object *object, HashTable *properties) /* {{{ */
1635 {
1636 object->properties = properties;
1637 if (object->ce->default_properties_count) {
1638 zval *prop;
1639 zend_string *key;
1640 zend_property_info *property_info;
1641
1642 ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(properties, key, prop) {
1643 property_info = zend_get_property_info(object->ce, key, 1);
1644 if (property_info != ZEND_WRONG_PROPERTY_INFO &&
1645 property_info &&
1646 (property_info->flags & ZEND_ACC_STATIC) == 0) {
1647 zval *slot = OBJ_PROP(object, property_info->offset);
1648
1649 if (UNEXPECTED(ZEND_TYPE_IS_SET(property_info->type))) {
1650 zval tmp;
1651
1652 ZVAL_COPY_VALUE(&tmp, prop);
1653 if (UNEXPECTED(!zend_verify_property_type(property_info, &tmp, 0))) {
1654 continue;
1655 }
1656 ZVAL_COPY_VALUE(slot, &tmp);
1657 } else {
1658 ZVAL_COPY_VALUE(slot, prop);
1659 }
1660 ZVAL_INDIRECT(prop, slot);
1661 }
1662 } ZEND_HASH_FOREACH_END();
1663 }
1664 }
1665 /* }}} */
1666
object_properties_load(zend_object * object,HashTable * properties)1667 ZEND_API void object_properties_load(zend_object *object, HashTable *properties) /* {{{ */
1668 {
1669 zval *prop, tmp;
1670 zend_string *key;
1671 zend_long h;
1672 zend_property_info *property_info;
1673
1674 ZEND_HASH_FOREACH_KEY_VAL(properties, h, key, prop) {
1675 if (key) {
1676 if (ZSTR_VAL(key)[0] == '\0') {
1677 const char *class_name, *prop_name;
1678 size_t prop_name_len;
1679 if (zend_unmangle_property_name_ex(key, &class_name, &prop_name, &prop_name_len) == SUCCESS) {
1680 zend_string *pname = zend_string_init(prop_name, prop_name_len, 0);
1681 zend_class_entry *prev_scope = EG(fake_scope);
1682 if (class_name && class_name[0] != '*') {
1683 zend_string *cname = zend_string_init(class_name, strlen(class_name), 0);
1684 EG(fake_scope) = zend_lookup_class(cname);
1685 zend_string_release_ex(cname, 0);
1686 }
1687 property_info = zend_get_property_info(object->ce, pname, 1);
1688 zend_string_release_ex(pname, 0);
1689 EG(fake_scope) = prev_scope;
1690 } else {
1691 property_info = ZEND_WRONG_PROPERTY_INFO;
1692 }
1693 } else {
1694 property_info = zend_get_property_info(object->ce, key, 1);
1695 }
1696 if (property_info != ZEND_WRONG_PROPERTY_INFO &&
1697 property_info &&
1698 (property_info->flags & ZEND_ACC_STATIC) == 0) {
1699 zval *slot = OBJ_PROP(object, property_info->offset);
1700 zval_ptr_dtor(slot);
1701 ZVAL_COPY_VALUE(slot, prop);
1702 zval_add_ref(slot);
1703 if (object->properties) {
1704 ZVAL_INDIRECT(&tmp, slot);
1705 zend_hash_update(object->properties, key, &tmp);
1706 }
1707 } else {
1708 if (UNEXPECTED(object->ce->ce_flags & ZEND_ACC_NO_DYNAMIC_PROPERTIES)) {
1709 zend_throw_error(NULL, "Cannot create dynamic property %s::$%s",
1710 ZSTR_VAL(object->ce->name), property_info != ZEND_WRONG_PROPERTY_INFO ? zend_get_unmangled_property_name(key): "");
1711 return;
1712 } else if (!(object->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) {
1713 zend_error(E_DEPRECATED, "Creation of dynamic property %s::$%s is deprecated",
1714 ZSTR_VAL(object->ce->name), property_info != ZEND_WRONG_PROPERTY_INFO ? zend_get_unmangled_property_name(key): "");
1715 }
1716
1717 if (!object->properties) {
1718 rebuild_object_properties(object);
1719 }
1720 prop = zend_hash_update(object->properties, key, prop);
1721 zval_add_ref(prop);
1722 }
1723 } else {
1724 if (UNEXPECTED(object->ce->ce_flags & ZEND_ACC_NO_DYNAMIC_PROPERTIES)) {
1725 zend_throw_error(NULL, "Cannot create dynamic property %s::$" ZEND_LONG_FMT, ZSTR_VAL(object->ce->name), h);
1726 return;
1727 } else if (!(object->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) {
1728 zend_error(E_DEPRECATED, "Creation of dynamic property %s::$" ZEND_LONG_FMT " is deprecated",
1729 ZSTR_VAL(object->ce->name), h);
1730 }
1731
1732 if (!object->properties) {
1733 rebuild_object_properties(object);
1734 }
1735 prop = zend_hash_index_update(object->properties, h, prop);
1736 zval_add_ref(prop);
1737 }
1738 } ZEND_HASH_FOREACH_END();
1739 }
1740 /* }}} */
1741
1742 /* This function requires 'properties' to contain all props declared in the
1743 * class and all props being public. If only a subset is given or the class
1744 * has protected members then you need to merge the properties separately by
1745 * calling zend_merge_properties(). */
_object_and_properties_init(zval * arg,zend_class_entry * class_type,HashTable * properties)1746 static zend_always_inline zend_result _object_and_properties_init(zval *arg, zend_class_entry *class_type, HashTable *properties) /* {{{ */
1747 {
1748 if (UNEXPECTED(class_type->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT|ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS|ZEND_ACC_ENUM))) {
1749 if (class_type->ce_flags & ZEND_ACC_INTERFACE) {
1750 zend_throw_error(NULL, "Cannot instantiate interface %s", ZSTR_VAL(class_type->name));
1751 } else if (class_type->ce_flags & ZEND_ACC_TRAIT) {
1752 zend_throw_error(NULL, "Cannot instantiate trait %s", ZSTR_VAL(class_type->name));
1753 } else if (class_type->ce_flags & ZEND_ACC_ENUM) {
1754 zend_throw_error(NULL, "Cannot instantiate enum %s", ZSTR_VAL(class_type->name));
1755 } else {
1756 zend_throw_error(NULL, "Cannot instantiate abstract class %s", ZSTR_VAL(class_type->name));
1757 }
1758 ZVAL_NULL(arg);
1759 Z_OBJ_P(arg) = NULL;
1760 return FAILURE;
1761 }
1762
1763 if (UNEXPECTED(!(class_type->ce_flags & ZEND_ACC_CONSTANTS_UPDATED))) {
1764 if (UNEXPECTED(zend_update_class_constants(class_type) != SUCCESS)) {
1765 ZVAL_NULL(arg);
1766 Z_OBJ_P(arg) = NULL;
1767 return FAILURE;
1768 }
1769 }
1770
1771 if (class_type->create_object == NULL) {
1772 zend_object *obj = zend_objects_new(class_type);
1773
1774 ZVAL_OBJ(arg, obj);
1775 if (properties) {
1776 object_properties_init_ex(obj, properties);
1777 } else {
1778 _object_properties_init(obj, class_type);
1779 }
1780 } else {
1781 ZVAL_OBJ(arg, class_type->create_object(class_type));
1782 }
1783 return SUCCESS;
1784 }
1785 /* }}} */
1786
object_and_properties_init(zval * arg,zend_class_entry * class_type,HashTable * properties)1787 ZEND_API zend_result object_and_properties_init(zval *arg, zend_class_entry *class_type, HashTable *properties) /* {{{ */
1788 {
1789 return _object_and_properties_init(arg, class_type, properties);
1790 }
1791 /* }}} */
1792
object_init_ex(zval * arg,zend_class_entry * class_type)1793 ZEND_API zend_result object_init_ex(zval *arg, zend_class_entry *class_type) /* {{{ */
1794 {
1795 return _object_and_properties_init(arg, class_type, NULL);
1796 }
1797 /* }}} */
1798
object_init(zval * arg)1799 ZEND_API void object_init(zval *arg) /* {{{ */
1800 {
1801 ZVAL_OBJ(arg, zend_objects_new(zend_standard_class_def));
1802 }
1803 /* }}} */
1804
add_assoc_long_ex(zval * arg,const char * key,size_t key_len,zend_long n)1805 ZEND_API void add_assoc_long_ex(zval *arg, const char *key, size_t key_len, zend_long n) /* {{{ */
1806 {
1807 zval tmp;
1808
1809 ZVAL_LONG(&tmp, n);
1810 zend_symtable_str_update(Z_ARRVAL_P(arg), key, key_len, &tmp);
1811 }
1812 /* }}} */
1813
add_assoc_null_ex(zval * arg,const char * key,size_t key_len)1814 ZEND_API void add_assoc_null_ex(zval *arg, const char *key, size_t key_len) /* {{{ */
1815 {
1816 zval tmp;
1817
1818 ZVAL_NULL(&tmp);
1819 zend_symtable_str_update(Z_ARRVAL_P(arg), key, key_len, &tmp);
1820 }
1821 /* }}} */
1822
add_assoc_bool_ex(zval * arg,const char * key,size_t key_len,bool b)1823 ZEND_API void add_assoc_bool_ex(zval *arg, const char *key, size_t key_len, bool b) /* {{{ */
1824 {
1825 zval tmp;
1826
1827 ZVAL_BOOL(&tmp, b);
1828 zend_symtable_str_update(Z_ARRVAL_P(arg), key, key_len, &tmp);
1829 }
1830 /* }}} */
1831
add_assoc_resource_ex(zval * arg,const char * key,size_t key_len,zend_resource * r)1832 ZEND_API void add_assoc_resource_ex(zval *arg, const char *key, size_t key_len, zend_resource *r) /* {{{ */
1833 {
1834 zval tmp;
1835
1836 ZVAL_RES(&tmp, r);
1837 zend_symtable_str_update(Z_ARRVAL_P(arg), key, key_len, &tmp);
1838 }
1839 /* }}} */
1840
add_assoc_double_ex(zval * arg,const char * key,size_t key_len,double d)1841 ZEND_API void add_assoc_double_ex(zval *arg, const char *key, size_t key_len, double d) /* {{{ */
1842 {
1843 zval tmp;
1844
1845 ZVAL_DOUBLE(&tmp, d);
1846 zend_symtable_str_update(Z_ARRVAL_P(arg), key, key_len, &tmp);
1847 }
1848 /* }}} */
1849
add_assoc_str_ex(zval * arg,const char * key,size_t key_len,zend_string * str)1850 ZEND_API void add_assoc_str_ex(zval *arg, const char *key, size_t key_len, zend_string *str) /* {{{ */
1851 {
1852 zval tmp;
1853
1854 ZVAL_STR(&tmp, str);
1855 zend_symtable_str_update(Z_ARRVAL_P(arg), key, key_len, &tmp);
1856 }
1857 /* }}} */
1858
add_assoc_string_ex(zval * arg,const char * key,size_t key_len,const char * str)1859 ZEND_API void add_assoc_string_ex(zval *arg, const char *key, size_t key_len, const char *str) /* {{{ */
1860 {
1861 zval tmp;
1862
1863 ZVAL_STRING(&tmp, str);
1864 zend_symtable_str_update(Z_ARRVAL_P(arg), key, key_len, &tmp);
1865 }
1866 /* }}} */
1867
add_assoc_stringl_ex(zval * arg,const char * key,size_t key_len,const char * str,size_t length)1868 ZEND_API void add_assoc_stringl_ex(zval *arg, const char *key, size_t key_len, const char *str, size_t length) /* {{{ */
1869 {
1870 zval tmp;
1871
1872 ZVAL_STRINGL(&tmp, str, length);
1873 zend_symtable_str_update(Z_ARRVAL_P(arg), key, key_len, &tmp);
1874 }
1875 /* }}} */
1876
add_assoc_array_ex(zval * arg,const char * key,size_t key_len,zend_array * arr)1877 ZEND_API void add_assoc_array_ex(zval *arg, const char *key, size_t key_len, zend_array *arr) /* {{{ */
1878 {
1879 zval tmp;
1880
1881 ZVAL_ARR(&tmp, arr);
1882 zend_symtable_str_update(Z_ARRVAL_P(arg), key, key_len, &tmp);
1883 }
1884 /* }}} */
1885
add_assoc_object_ex(zval * arg,const char * key,size_t key_len,zend_object * obj)1886 ZEND_API void add_assoc_object_ex(zval *arg, const char *key, size_t key_len, zend_object *obj) /* {{{ */
1887 {
1888 zval tmp;
1889
1890 ZVAL_OBJ(&tmp, obj);
1891 zend_symtable_str_update(Z_ARRVAL_P(arg), key, key_len, &tmp);
1892 }
1893 /* }}} */
1894
add_assoc_reference_ex(zval * arg,const char * key,size_t key_len,zend_reference * ref)1895 ZEND_API void add_assoc_reference_ex(zval *arg, const char *key, size_t key_len, zend_reference *ref) /* {{{ */
1896 {
1897 zval tmp;
1898
1899 ZVAL_REF(&tmp, ref);
1900 zend_symtable_str_update(Z_ARRVAL_P(arg), key, key_len, &tmp);
1901 }
1902 /* }}} */
1903
add_assoc_zval_ex(zval * arg,const char * key,size_t key_len,zval * value)1904 ZEND_API void add_assoc_zval_ex(zval *arg, const char *key, size_t key_len, zval *value) /* {{{ */
1905 {
1906 zend_symtable_str_update(Z_ARRVAL_P(arg), key, key_len, value);
1907 }
1908 /* }}} */
1909
add_index_long(zval * arg,zend_ulong index,zend_long n)1910 ZEND_API void add_index_long(zval *arg, zend_ulong index, zend_long n) /* {{{ */
1911 {
1912 zval tmp;
1913
1914 ZVAL_LONG(&tmp, n);
1915 zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp);
1916 }
1917 /* }}} */
1918
add_index_null(zval * arg,zend_ulong index)1919 ZEND_API void add_index_null(zval *arg, zend_ulong index) /* {{{ */
1920 {
1921 zval tmp;
1922
1923 ZVAL_NULL(&tmp);
1924 zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp);
1925 }
1926 /* }}} */
1927
add_index_bool(zval * arg,zend_ulong index,bool b)1928 ZEND_API void add_index_bool(zval *arg, zend_ulong index, bool b) /* {{{ */
1929 {
1930 zval tmp;
1931
1932 ZVAL_BOOL(&tmp, b);
1933 zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp);
1934 }
1935 /* }}} */
1936
add_index_resource(zval * arg,zend_ulong index,zend_resource * r)1937 ZEND_API void add_index_resource(zval *arg, zend_ulong index, zend_resource *r) /* {{{ */
1938 {
1939 zval tmp;
1940
1941 ZVAL_RES(&tmp, r);
1942 zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp);
1943 }
1944 /* }}} */
1945
add_index_double(zval * arg,zend_ulong index,double d)1946 ZEND_API void add_index_double(zval *arg, zend_ulong index, double d) /* {{{ */
1947 {
1948 zval tmp;
1949
1950 ZVAL_DOUBLE(&tmp, d);
1951 zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp);
1952 }
1953 /* }}} */
1954
add_index_str(zval * arg,zend_ulong index,zend_string * str)1955 ZEND_API void add_index_str(zval *arg, zend_ulong index, zend_string *str) /* {{{ */
1956 {
1957 zval tmp;
1958
1959 ZVAL_STR(&tmp, str);
1960 zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp);
1961 }
1962 /* }}} */
1963
add_index_string(zval * arg,zend_ulong index,const char * str)1964 ZEND_API void add_index_string(zval *arg, zend_ulong index, const char *str) /* {{{ */
1965 {
1966 zval tmp;
1967
1968 ZVAL_STRING(&tmp, str);
1969 zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp);
1970 }
1971 /* }}} */
1972
add_index_stringl(zval * arg,zend_ulong index,const char * str,size_t length)1973 ZEND_API void add_index_stringl(zval *arg, zend_ulong index, const char *str, size_t length) /* {{{ */
1974 {
1975 zval tmp;
1976
1977 ZVAL_STRINGL(&tmp, str, length);
1978 zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp);
1979 }
1980 /* }}} */
1981
add_index_array(zval * arg,zend_ulong index,zend_array * arr)1982 ZEND_API void add_index_array(zval *arg, zend_ulong index, zend_array *arr) /* {{{ */
1983 {
1984 zval tmp;
1985
1986 ZVAL_ARR(&tmp, arr);
1987 zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp);
1988 }
1989 /* }}} */
1990
add_index_object(zval * arg,zend_ulong index,zend_object * obj)1991 ZEND_API void add_index_object(zval *arg, zend_ulong index, zend_object *obj) /* {{{ */
1992 {
1993 zval tmp;
1994
1995 ZVAL_OBJ(&tmp, obj);
1996 zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp);
1997 }
1998 /* }}} */
1999
add_index_reference(zval * arg,zend_ulong index,zend_reference * ref)2000 ZEND_API void add_index_reference(zval *arg, zend_ulong index, zend_reference *ref) /* {{{ */
2001 {
2002 zval tmp;
2003
2004 ZVAL_REF(&tmp, ref);
2005 zend_hash_index_update(Z_ARRVAL_P(arg), index, &tmp);
2006 }
2007 /* }}} */
2008
add_next_index_long(zval * arg,zend_long n)2009 ZEND_API zend_result add_next_index_long(zval *arg, zend_long n) /* {{{ */
2010 {
2011 zval tmp;
2012
2013 ZVAL_LONG(&tmp, n);
2014 return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &tmp) ? SUCCESS : FAILURE;
2015 }
2016 /* }}} */
2017
add_next_index_null(zval * arg)2018 ZEND_API zend_result add_next_index_null(zval *arg) /* {{{ */
2019 {
2020 zval tmp;
2021
2022 ZVAL_NULL(&tmp);
2023 return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &tmp) ? SUCCESS : FAILURE;
2024 }
2025 /* }}} */
2026
add_next_index_bool(zval * arg,bool b)2027 ZEND_API zend_result add_next_index_bool(zval *arg, bool b) /* {{{ */
2028 {
2029 zval tmp;
2030
2031 ZVAL_BOOL(&tmp, b);
2032 return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &tmp) ? SUCCESS : FAILURE;
2033 }
2034 /* }}} */
2035
add_next_index_resource(zval * arg,zend_resource * r)2036 ZEND_API zend_result add_next_index_resource(zval *arg, zend_resource *r) /* {{{ */
2037 {
2038 zval tmp;
2039
2040 ZVAL_RES(&tmp, r);
2041 return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &tmp) ? SUCCESS : FAILURE;
2042 }
2043 /* }}} */
2044
add_next_index_double(zval * arg,double d)2045 ZEND_API zend_result add_next_index_double(zval *arg, double d) /* {{{ */
2046 {
2047 zval tmp;
2048
2049 ZVAL_DOUBLE(&tmp, d);
2050 return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &tmp) ? SUCCESS : FAILURE;
2051 }
2052 /* }}} */
2053
add_next_index_str(zval * arg,zend_string * str)2054 ZEND_API zend_result add_next_index_str(zval *arg, zend_string *str) /* {{{ */
2055 {
2056 zval tmp;
2057
2058 ZVAL_STR(&tmp, str);
2059 return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &tmp) ? SUCCESS : FAILURE;
2060 }
2061 /* }}} */
2062
add_next_index_string(zval * arg,const char * str)2063 ZEND_API zend_result add_next_index_string(zval *arg, const char *str) /* {{{ */
2064 {
2065 zval tmp;
2066
2067 ZVAL_STRING(&tmp, str);
2068 return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &tmp) ? SUCCESS : FAILURE;
2069 }
2070 /* }}} */
2071
add_next_index_stringl(zval * arg,const char * str,size_t length)2072 ZEND_API zend_result add_next_index_stringl(zval *arg, const char *str, size_t length) /* {{{ */
2073 {
2074 zval tmp;
2075
2076 ZVAL_STRINGL(&tmp, str, length);
2077 return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &tmp) ? SUCCESS : FAILURE;
2078 }
2079 /* }}} */
2080
add_next_index_array(zval * arg,zend_array * arr)2081 ZEND_API zend_result add_next_index_array(zval *arg, zend_array *arr) /* {{{ */
2082 {
2083 zval tmp;
2084
2085 ZVAL_ARR(&tmp, arr);
2086 return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &tmp) ? SUCCESS : FAILURE;
2087 }
2088 /* }}} */
2089
add_next_index_object(zval * arg,zend_object * obj)2090 ZEND_API zend_result add_next_index_object(zval *arg, zend_object *obj) /* {{{ */
2091 {
2092 zval tmp;
2093
2094 ZVAL_OBJ(&tmp, obj);
2095 return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &tmp) ? SUCCESS : FAILURE;
2096 }
2097 /* }}} */
2098
add_next_index_reference(zval * arg,zend_reference * ref)2099 ZEND_API zend_result add_next_index_reference(zval *arg, zend_reference *ref) /* {{{ */
2100 {
2101 zval tmp;
2102
2103 ZVAL_REF(&tmp, ref);
2104 return zend_hash_next_index_insert(Z_ARRVAL_P(arg), &tmp) ? SUCCESS : FAILURE;
2105 }
2106 /* }}} */
2107
array_set_zval_key(HashTable * ht,zval * key,zval * value)2108 ZEND_API zend_result array_set_zval_key(HashTable *ht, zval *key, zval *value) /* {{{ */
2109 {
2110 zval *result;
2111
2112 switch (Z_TYPE_P(key)) {
2113 case IS_STRING:
2114 result = zend_symtable_update(ht, Z_STR_P(key), value);
2115 break;
2116 case IS_NULL:
2117 result = zend_hash_update(ht, ZSTR_EMPTY_ALLOC(), value);
2118 break;
2119 case IS_RESOURCE:
2120 zend_use_resource_as_offset(key);
2121 result = zend_hash_index_update(ht, Z_RES_HANDLE_P(key), value);
2122 break;
2123 case IS_FALSE:
2124 result = zend_hash_index_update(ht, 0, value);
2125 break;
2126 case IS_TRUE:
2127 result = zend_hash_index_update(ht, 1, value);
2128 break;
2129 case IS_LONG:
2130 result = zend_hash_index_update(ht, Z_LVAL_P(key), value);
2131 break;
2132 case IS_DOUBLE:
2133 result = zend_hash_index_update(ht, zend_dval_to_lval_safe(Z_DVAL_P(key)), value);
2134 break;
2135 default:
2136 zend_illegal_container_offset(ZSTR_KNOWN(ZEND_STR_ARRAY), key, BP_VAR_W);
2137 result = NULL;
2138 }
2139
2140 if (result) {
2141 Z_TRY_ADDREF_P(result);
2142 return SUCCESS;
2143 } else {
2144 return FAILURE;
2145 }
2146 }
2147 /* }}} */
2148
add_property_long_ex(zval * arg,const char * key,size_t key_len,zend_long n)2149 ZEND_API void add_property_long_ex(zval *arg, const char *key, size_t key_len, zend_long n) /* {{{ */
2150 {
2151 zval tmp;
2152
2153 ZVAL_LONG(&tmp, n);
2154 add_property_zval_ex(arg, key, key_len, &tmp);
2155 }
2156 /* }}} */
2157
add_property_bool_ex(zval * arg,const char * key,size_t key_len,zend_long b)2158 ZEND_API void add_property_bool_ex(zval *arg, const char *key, size_t key_len, zend_long b) /* {{{ */
2159 {
2160 zval tmp;
2161
2162 ZVAL_BOOL(&tmp, b);
2163 add_property_zval_ex(arg, key, key_len, &tmp);
2164 }
2165 /* }}} */
2166
add_property_null_ex(zval * arg,const char * key,size_t key_len)2167 ZEND_API void add_property_null_ex(zval *arg, const char *key, size_t key_len) /* {{{ */
2168 {
2169 zval tmp;
2170
2171 ZVAL_NULL(&tmp);
2172 add_property_zval_ex(arg, key, key_len, &tmp);
2173 }
2174 /* }}} */
2175
add_property_resource_ex(zval * arg,const char * key,size_t key_len,zend_resource * r)2176 ZEND_API void add_property_resource_ex(zval *arg, const char *key, size_t key_len, zend_resource *r) /* {{{ */
2177 {
2178 zval tmp;
2179
2180 ZVAL_RES(&tmp, r);
2181 add_property_zval_ex(arg, key, key_len, &tmp);
2182 zval_ptr_dtor(&tmp); /* write_property will add 1 to refcount */
2183 }
2184 /* }}} */
2185
add_property_double_ex(zval * arg,const char * key,size_t key_len,double d)2186 ZEND_API void add_property_double_ex(zval *arg, const char *key, size_t key_len, double d) /* {{{ */
2187 {
2188 zval tmp;
2189
2190 ZVAL_DOUBLE(&tmp, d);
2191 add_property_zval_ex(arg, key, key_len, &tmp);
2192 }
2193 /* }}} */
2194
add_property_str_ex(zval * arg,const char * key,size_t key_len,zend_string * str)2195 ZEND_API void add_property_str_ex(zval *arg, const char *key, size_t key_len, zend_string *str) /* {{{ */
2196 {
2197 zval tmp;
2198
2199 ZVAL_STR(&tmp, str);
2200 add_property_zval_ex(arg, key, key_len, &tmp);
2201 zval_ptr_dtor(&tmp); /* write_property will add 1 to refcount */
2202 }
2203 /* }}} */
2204
add_property_string_ex(zval * arg,const char * key,size_t key_len,const char * str)2205 ZEND_API void add_property_string_ex(zval *arg, const char *key, size_t key_len, const char *str) /* {{{ */
2206 {
2207 zval tmp;
2208
2209 ZVAL_STRING(&tmp, str);
2210 add_property_zval_ex(arg, key, key_len, &tmp);
2211 zval_ptr_dtor(&tmp); /* write_property will add 1 to refcount */
2212 }
2213 /* }}} */
2214
add_property_stringl_ex(zval * arg,const char * key,size_t key_len,const char * str,size_t length)2215 ZEND_API void add_property_stringl_ex(zval *arg, const char *key, size_t key_len, const char *str, size_t length) /* {{{ */
2216 {
2217 zval tmp;
2218
2219 ZVAL_STRINGL(&tmp, str, length);
2220 add_property_zval_ex(arg, key, key_len, &tmp);
2221 zval_ptr_dtor(&tmp); /* write_property will add 1 to refcount */
2222 }
2223 /* }}} */
2224
add_property_array_ex(zval * arg,const char * key,size_t key_len,zend_array * arr)2225 ZEND_API void add_property_array_ex(zval *arg, const char *key, size_t key_len, zend_array *arr) /* {{{ */
2226 {
2227 zval tmp;
2228
2229 ZVAL_ARR(&tmp, arr);
2230 add_property_zval_ex(arg, key, key_len, &tmp);
2231 zval_ptr_dtor(&tmp); /* write_property will add 1 to refcount */
2232 }
2233 /* }}} */
2234
add_property_object_ex(zval * arg,const char * key,size_t key_len,zend_object * obj)2235 ZEND_API void add_property_object_ex(zval *arg, const char *key, size_t key_len, zend_object *obj) /* {{{ */
2236 {
2237 zval tmp;
2238
2239 ZVAL_OBJ(&tmp, obj);
2240 add_property_zval_ex(arg, key, key_len, &tmp);
2241 zval_ptr_dtor(&tmp); /* write_property will add 1 to refcount */
2242 }
2243 /* }}} */
2244
add_property_reference_ex(zval * arg,const char * key,size_t key_len,zend_reference * ref)2245 ZEND_API void add_property_reference_ex(zval *arg, const char *key, size_t key_len, zend_reference *ref) /* {{{ */
2246 {
2247 zval tmp;
2248
2249 ZVAL_REF(&tmp, ref);
2250 add_property_zval_ex(arg, key, key_len, &tmp);
2251 zval_ptr_dtor(&tmp); /* write_property will add 1 to refcount */
2252 }
2253 /* }}} */
2254
add_property_zval_ex(zval * arg,const char * key,size_t key_len,zval * value)2255 ZEND_API void add_property_zval_ex(zval *arg, const char *key, size_t key_len, zval *value) /* {{{ */
2256 {
2257 zend_string *str;
2258
2259 str = zend_string_init(key, key_len, 0);
2260 Z_OBJ_HANDLER_P(arg, write_property)(Z_OBJ_P(arg), str, value, NULL);
2261 zend_string_release_ex(str, 0);
2262 }
2263 /* }}} */
2264
zend_startup_module_ex(zend_module_entry * module)2265 ZEND_API zend_result zend_startup_module_ex(zend_module_entry *module) /* {{{ */
2266 {
2267 size_t name_len;
2268 zend_string *lcname;
2269
2270 if (module->module_started) {
2271 return SUCCESS;
2272 }
2273 module->module_started = 1;
2274
2275 /* Check module dependencies */
2276 if (module->deps) {
2277 const zend_module_dep *dep = module->deps;
2278
2279 while (dep->name) {
2280 if (dep->type == MODULE_DEP_REQUIRED) {
2281 zend_module_entry *req_mod;
2282
2283 name_len = strlen(dep->name);
2284 lcname = zend_string_alloc(name_len, 0);
2285 zend_str_tolower_copy(ZSTR_VAL(lcname), dep->name, name_len);
2286
2287 if ((req_mod = zend_hash_find_ptr(&module_registry, lcname)) == NULL || !req_mod->module_started) {
2288 zend_string_efree(lcname);
2289 /* TODO: Check version relationship */
2290 zend_error(E_CORE_WARNING, "Cannot load module \"%s\" because required module \"%s\" is not loaded", module->name, dep->name);
2291 module->module_started = 0;
2292 return FAILURE;
2293 }
2294 zend_string_efree(lcname);
2295 }
2296 ++dep;
2297 }
2298 }
2299
2300 /* Initialize module globals */
2301 if (module->globals_size) {
2302 #ifdef ZTS
2303 ts_allocate_id(module->globals_id_ptr, module->globals_size, (ts_allocate_ctor) module->globals_ctor, (ts_allocate_dtor) module->globals_dtor);
2304 #else
2305 if (module->globals_ctor) {
2306 module->globals_ctor(module->globals_ptr);
2307 }
2308 #endif
2309 }
2310 if (module->module_startup_func) {
2311 EG(current_module) = module;
2312 if (module->module_startup_func(module->type, module->module_number)==FAILURE) {
2313 zend_error_noreturn(E_CORE_ERROR,"Unable to start %s module", module->name);
2314 EG(current_module) = NULL;
2315 return FAILURE;
2316 }
2317 EG(current_module) = NULL;
2318 }
2319 return SUCCESS;
2320 }
2321 /* }}} */
2322
zend_startup_module_zval(zval * zv)2323 static int zend_startup_module_zval(zval *zv) /* {{{ */
2324 {
2325 zend_module_entry *module = Z_PTR_P(zv);
2326
2327 return (zend_startup_module_ex(module) == SUCCESS) ? ZEND_HASH_APPLY_KEEP : ZEND_HASH_APPLY_REMOVE;
2328 }
2329 /* }}} */
2330
zend_sort_modules(void * base,size_t count,size_t siz,compare_func_t compare,swap_func_t swp)2331 static void zend_sort_modules(void *base, size_t count, size_t siz, compare_func_t compare, swap_func_t swp) /* {{{ */
2332 {
2333 Bucket *b1 = base;
2334 Bucket *b2;
2335 Bucket *end = b1 + count;
2336 Bucket tmp;
2337 zend_module_entry *m, *r;
2338
2339 while (b1 < end) {
2340 try_again:
2341 m = (zend_module_entry*)Z_PTR(b1->val);
2342 if (!m->module_started && m->deps) {
2343 const zend_module_dep *dep = m->deps;
2344 while (dep->name) {
2345 if (dep->type == MODULE_DEP_REQUIRED || dep->type == MODULE_DEP_OPTIONAL) {
2346 b2 = b1 + 1;
2347 while (b2 < end) {
2348 r = (zend_module_entry*)Z_PTR(b2->val);
2349 if (strcasecmp(dep->name, r->name) == 0) {
2350 tmp = *b1;
2351 *b1 = *b2;
2352 *b2 = tmp;
2353 goto try_again;
2354 }
2355 b2++;
2356 }
2357 }
2358 dep++;
2359 }
2360 }
2361 b1++;
2362 }
2363 }
2364 /* }}} */
2365
zend_collect_module_handlers(void)2366 ZEND_API void zend_collect_module_handlers(void) /* {{{ */
2367 {
2368 zend_module_entry *module;
2369 int startup_count = 0;
2370 int shutdown_count = 0;
2371 int post_deactivate_count = 0;
2372 int dl_loaded_count = 0;
2373 zend_class_entry *ce;
2374 int class_count = 0;
2375
2376 /* Collect extensions with request startup/shutdown handlers */
2377 ZEND_HASH_MAP_FOREACH_PTR(&module_registry, module) {
2378 if (module->request_startup_func) {
2379 startup_count++;
2380 }
2381 if (module->request_shutdown_func) {
2382 shutdown_count++;
2383 }
2384 if (module->post_deactivate_func) {
2385 post_deactivate_count++;
2386 }
2387 if (module->handle) {
2388 dl_loaded_count++;
2389 }
2390 } ZEND_HASH_FOREACH_END();
2391 module_request_startup_handlers = (zend_module_entry**)realloc(
2392 module_request_startup_handlers,
2393 sizeof(zend_module_entry*) *
2394 (startup_count + 1 +
2395 shutdown_count + 1 +
2396 post_deactivate_count + 1));
2397 module_request_startup_handlers[startup_count] = NULL;
2398 module_request_shutdown_handlers = module_request_startup_handlers + startup_count + 1;
2399 module_request_shutdown_handlers[shutdown_count] = NULL;
2400 module_post_deactivate_handlers = module_request_shutdown_handlers + shutdown_count + 1;
2401 module_post_deactivate_handlers[post_deactivate_count] = NULL;
2402 /* Cannot reuse module_request_startup_handlers because it is freed in zend_destroy_modules, which happens before zend_unload_modules. */
2403 modules_dl_loaded = realloc(modules_dl_loaded, sizeof(zend_module_entry*) * (dl_loaded_count + 1));
2404 modules_dl_loaded[dl_loaded_count] = NULL;
2405 startup_count = 0;
2406
2407 ZEND_HASH_MAP_FOREACH_PTR(&module_registry, module) {
2408 if (module->request_startup_func) {
2409 module_request_startup_handlers[startup_count++] = module;
2410 }
2411 if (module->request_shutdown_func) {
2412 module_request_shutdown_handlers[--shutdown_count] = module;
2413 }
2414 if (module->post_deactivate_func) {
2415 module_post_deactivate_handlers[--post_deactivate_count] = module;
2416 }
2417 if (module->handle) {
2418 modules_dl_loaded[--dl_loaded_count] = module;
2419 }
2420 } ZEND_HASH_FOREACH_END();
2421
2422 /* Collect internal classes with static members */
2423 ZEND_HASH_MAP_FOREACH_PTR(CG(class_table), ce) {
2424 if (ce->type == ZEND_INTERNAL_CLASS &&
2425 ce->default_static_members_count > 0) {
2426 class_count++;
2427 }
2428 } ZEND_HASH_FOREACH_END();
2429
2430 class_cleanup_handlers = (zend_class_entry**)realloc(
2431 class_cleanup_handlers,
2432 sizeof(zend_class_entry*) *
2433 (class_count + 1));
2434 class_cleanup_handlers[class_count] = NULL;
2435
2436 if (class_count) {
2437 ZEND_HASH_MAP_FOREACH_PTR(CG(class_table), ce) {
2438 if (ce->type == ZEND_INTERNAL_CLASS &&
2439 ce->default_static_members_count > 0) {
2440 class_cleanup_handlers[--class_count] = ce;
2441 }
2442 } ZEND_HASH_FOREACH_END();
2443 }
2444 }
2445 /* }}} */
2446
zend_startup_modules(void)2447 ZEND_API void zend_startup_modules(void) /* {{{ */
2448 {
2449 zend_hash_sort_ex(&module_registry, zend_sort_modules, NULL, 0);
2450 zend_hash_apply(&module_registry, zend_startup_module_zval);
2451 }
2452 /* }}} */
2453
zend_destroy_modules(void)2454 ZEND_API void zend_destroy_modules(void) /* {{{ */
2455 {
2456 free(class_cleanup_handlers);
2457 class_cleanup_handlers = NULL;
2458 free(module_request_startup_handlers);
2459 module_request_startup_handlers = NULL;
2460 zend_hash_graceful_reverse_destroy(&module_registry);
2461 }
2462 /* }}} */
2463
zend_register_module_ex(zend_module_entry * module)2464 ZEND_API zend_module_entry* zend_register_module_ex(zend_module_entry *module) /* {{{ */
2465 {
2466 size_t name_len;
2467 zend_string *lcname;
2468 zend_module_entry *module_ptr;
2469
2470 if (!module) {
2471 return NULL;
2472 }
2473
2474 #if 0
2475 zend_printf("%s: Registering module %d\n", module->name, module->module_number);
2476 #endif
2477
2478 /* Check module dependencies */
2479 if (module->deps) {
2480 const zend_module_dep *dep = module->deps;
2481
2482 while (dep->name) {
2483 if (dep->type == MODULE_DEP_CONFLICTS) {
2484 name_len = strlen(dep->name);
2485 lcname = zend_string_alloc(name_len, 0);
2486 zend_str_tolower_copy(ZSTR_VAL(lcname), dep->name, name_len);
2487
2488 if (zend_hash_exists(&module_registry, lcname) || zend_get_extension(dep->name)) {
2489 zend_string_efree(lcname);
2490 /* TODO: Check version relationship */
2491 zend_error(E_CORE_WARNING, "Cannot load module \"%s\" because conflicting module \"%s\" is already loaded", module->name, dep->name);
2492 return NULL;
2493 }
2494 zend_string_efree(lcname);
2495 }
2496 ++dep;
2497 }
2498 }
2499
2500 name_len = strlen(module->name);
2501 lcname = zend_string_alloc(name_len, module->type == MODULE_PERSISTENT);
2502 zend_str_tolower_copy(ZSTR_VAL(lcname), module->name, name_len);
2503
2504 lcname = zend_new_interned_string(lcname);
2505 if ((module_ptr = zend_hash_add_ptr(&module_registry, lcname, module)) == NULL) {
2506 zend_error(E_CORE_WARNING, "Module \"%s\" is already loaded", module->name);
2507 zend_string_release(lcname);
2508 return NULL;
2509 }
2510 module = module_ptr;
2511 EG(current_module) = module;
2512
2513 if (module->functions && zend_register_functions(NULL, module->functions, NULL, module->type)==FAILURE) {
2514 zend_hash_del(&module_registry, lcname);
2515 zend_string_release(lcname);
2516 EG(current_module) = NULL;
2517 zend_error(E_CORE_WARNING,"%s: Unable to register functions, unable to load", module->name);
2518 return NULL;
2519 }
2520
2521 EG(current_module) = NULL;
2522 zend_string_release(lcname);
2523 return module;
2524 }
2525 /* }}} */
2526
zend_register_internal_module(zend_module_entry * module)2527 ZEND_API zend_module_entry* zend_register_internal_module(zend_module_entry *module) /* {{{ */
2528 {
2529 module->module_number = zend_next_free_module();
2530 module->type = MODULE_PERSISTENT;
2531 return zend_register_module_ex(module);
2532 }
2533 /* }}} */
2534
zend_check_magic_method_args(uint32_t num_args,const zend_class_entry * ce,const zend_function * fptr,int error_type)2535 static void zend_check_magic_method_args(
2536 uint32_t num_args, const zend_class_entry *ce, const zend_function *fptr, int error_type)
2537 {
2538 if (fptr->common.num_args != num_args) {
2539 if (num_args == 0) {
2540 zend_error(error_type, "Method %s::%s() cannot take arguments",
2541 ZSTR_VAL(ce->name), ZSTR_VAL(fptr->common.function_name));
2542 } else if (num_args == 1) {
2543 zend_error(error_type, "Method %s::%s() must take exactly 1 argument",
2544 ZSTR_VAL(ce->name), ZSTR_VAL(fptr->common.function_name));
2545 } else {
2546 zend_error(error_type, "Method %s::%s() must take exactly %" PRIu32 " arguments",
2547 ZSTR_VAL(ce->name), ZSTR_VAL(fptr->common.function_name), num_args);
2548 }
2549 return;
2550 }
2551 for (uint32_t i = 0; i < num_args; i++) {
2552 if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(fptr, i + 1)) {
2553 zend_error(error_type, "Method %s::%s() cannot take arguments by reference",
2554 ZSTR_VAL(ce->name), ZSTR_VAL(fptr->common.function_name));
2555 return;
2556 }
2557 }
2558 }
2559
zend_check_magic_method_arg_type(uint32_t arg_num,const zend_class_entry * ce,const zend_function * fptr,int error_type,int arg_type)2560 static void zend_check_magic_method_arg_type(uint32_t arg_num, const zend_class_entry *ce, const zend_function *fptr, int error_type, int arg_type)
2561 {
2562 if (
2563 ZEND_TYPE_IS_SET(fptr->common.arg_info[arg_num].type)
2564 && !(ZEND_TYPE_FULL_MASK(fptr->common.arg_info[arg_num].type) & arg_type)
2565 ) {
2566 zend_error(error_type, "%s::%s(): Parameter #%d ($%s) must be of type %s when declared",
2567 ZSTR_VAL(ce->name), ZSTR_VAL(fptr->common.function_name),
2568 arg_num + 1, ZSTR_VAL(fptr->common.arg_info[arg_num].name),
2569 ZSTR_VAL(zend_type_to_string((zend_type) ZEND_TYPE_INIT_MASK(arg_type))));
2570 }
2571 }
2572
zend_check_magic_method_return_type(const zend_class_entry * ce,const zend_function * fptr,int error_type,int return_type)2573 static void zend_check_magic_method_return_type(const zend_class_entry *ce, const zend_function *fptr, int error_type, int return_type)
2574 {
2575 if (!(fptr->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE)) {
2576 /* For backwards compatibility reasons, do not enforce the return type if it is not set. */
2577 return;
2578 }
2579
2580 if (ZEND_TYPE_PURE_MASK(fptr->common.arg_info[-1].type) & MAY_BE_NEVER) {
2581 /* It is always legal to specify the never type. */
2582 return;
2583 }
2584
2585 bool is_complex_type = ZEND_TYPE_IS_COMPLEX(fptr->common.arg_info[-1].type);
2586 uint32_t extra_types = ZEND_TYPE_PURE_MASK(fptr->common.arg_info[-1].type) & ~return_type;
2587 if (extra_types & MAY_BE_STATIC) {
2588 extra_types &= ~MAY_BE_STATIC;
2589 is_complex_type = true;
2590 }
2591
2592 if (extra_types || (is_complex_type && return_type != MAY_BE_OBJECT)) {
2593 zend_error(error_type, "%s::%s(): Return type must be %s when declared",
2594 ZSTR_VAL(ce->name), ZSTR_VAL(fptr->common.function_name),
2595 ZSTR_VAL(zend_type_to_string((zend_type) ZEND_TYPE_INIT_MASK(return_type))));
2596 }
2597 }
2598
zend_check_magic_method_non_static(const zend_class_entry * ce,const zend_function * fptr,int error_type)2599 static void zend_check_magic_method_non_static(
2600 const zend_class_entry *ce, const zend_function *fptr, int error_type)
2601 {
2602 if (fptr->common.fn_flags & ZEND_ACC_STATIC) {
2603 zend_error(error_type, "Method %s::%s() cannot be static",
2604 ZSTR_VAL(ce->name), ZSTR_VAL(fptr->common.function_name));
2605 }
2606 }
2607
zend_check_magic_method_static(const zend_class_entry * ce,const zend_function * fptr,int error_type)2608 static void zend_check_magic_method_static(
2609 const zend_class_entry *ce, const zend_function *fptr, int error_type)
2610 {
2611 if (!(fptr->common.fn_flags & ZEND_ACC_STATIC)) {
2612 zend_error(error_type, "Method %s::%s() must be static",
2613 ZSTR_VAL(ce->name), ZSTR_VAL(fptr->common.function_name));
2614 }
2615 }
2616
zend_check_magic_method_public(const zend_class_entry * ce,const zend_function * fptr,int error_type)2617 static void zend_check_magic_method_public(
2618 const zend_class_entry *ce, const zend_function *fptr, int error_type)
2619 {
2620 // TODO: Remove this warning after adding proper visibility handling.
2621 if (!(fptr->common.fn_flags & ZEND_ACC_PUBLIC)) {
2622 zend_error(E_WARNING, "The magic method %s::%s() must have public visibility",
2623 ZSTR_VAL(ce->name), ZSTR_VAL(fptr->common.function_name));
2624 }
2625 }
2626
zend_check_magic_method_no_return_type(const zend_class_entry * ce,const zend_function * fptr,int error_type)2627 static void zend_check_magic_method_no_return_type(
2628 const zend_class_entry *ce, const zend_function *fptr, int error_type)
2629 {
2630 if (fptr->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
2631 zend_error_noreturn(error_type, "Method %s::%s() cannot declare a return type",
2632 ZSTR_VAL(ce->name), ZSTR_VAL(fptr->common.function_name));
2633 }
2634 }
2635
zend_check_magic_method_implementation(const zend_class_entry * ce,const zend_function * fptr,zend_string * lcname,int error_type)2636 ZEND_API void zend_check_magic_method_implementation(const zend_class_entry *ce, const zend_function *fptr, zend_string *lcname, int error_type) /* {{{ */
2637 {
2638 if (ZSTR_VAL(lcname)[0] != '_'
2639 || ZSTR_VAL(lcname)[1] != '_') {
2640 return;
2641 }
2642
2643 if (zend_string_equals_literal(lcname, ZEND_CONSTRUCTOR_FUNC_NAME)) {
2644 zend_check_magic_method_non_static(ce, fptr, error_type);
2645 zend_check_magic_method_no_return_type(ce, fptr, error_type);
2646 } else if (zend_string_equals_literal(lcname, ZEND_DESTRUCTOR_FUNC_NAME)) {
2647 zend_check_magic_method_args(0, ce, fptr, error_type);
2648 zend_check_magic_method_non_static(ce, fptr, error_type);
2649 zend_check_magic_method_no_return_type(ce, fptr, error_type);
2650 } else if (zend_string_equals_literal(lcname, ZEND_CLONE_FUNC_NAME)) {
2651 zend_check_magic_method_args(0, ce, fptr, error_type);
2652 zend_check_magic_method_non_static(ce, fptr, error_type);
2653 zend_check_magic_method_return_type(ce, fptr, error_type, MAY_BE_VOID);
2654 } else if (zend_string_equals_literal(lcname, ZEND_GET_FUNC_NAME)) {
2655 zend_check_magic_method_args(1, ce, fptr, error_type);
2656 zend_check_magic_method_non_static(ce, fptr, error_type);
2657 zend_check_magic_method_public(ce, fptr, error_type);
2658 zend_check_magic_method_arg_type(0, ce, fptr, error_type, MAY_BE_STRING);
2659 } else if (zend_string_equals_literal(lcname, ZEND_SET_FUNC_NAME)) {
2660 zend_check_magic_method_args(2, ce, fptr, error_type);
2661 zend_check_magic_method_non_static(ce, fptr, error_type);
2662 zend_check_magic_method_public(ce, fptr, error_type);
2663 zend_check_magic_method_arg_type(0, ce, fptr, error_type, MAY_BE_STRING);
2664 zend_check_magic_method_return_type(ce, fptr, error_type, MAY_BE_VOID);
2665 } else if (zend_string_equals_literal(lcname, ZEND_UNSET_FUNC_NAME)) {
2666 zend_check_magic_method_args(1, ce, fptr, error_type);
2667 zend_check_magic_method_non_static(ce, fptr, error_type);
2668 zend_check_magic_method_public(ce, fptr, error_type);
2669 zend_check_magic_method_arg_type(0, ce, fptr, error_type, MAY_BE_STRING);
2670 zend_check_magic_method_return_type(ce, fptr, error_type, MAY_BE_VOID);
2671 } else if (zend_string_equals_literal(lcname, ZEND_ISSET_FUNC_NAME)) {
2672 zend_check_magic_method_args(1, ce, fptr, error_type);
2673 zend_check_magic_method_non_static(ce, fptr, error_type);
2674 zend_check_magic_method_public(ce, fptr, error_type);
2675 zend_check_magic_method_arg_type(0, ce, fptr, error_type, MAY_BE_STRING);
2676 zend_check_magic_method_return_type(ce, fptr, error_type, MAY_BE_BOOL);
2677 } else if (zend_string_equals_literal(lcname, ZEND_CALL_FUNC_NAME)) {
2678 zend_check_magic_method_args(2, ce, fptr, error_type);
2679 zend_check_magic_method_non_static(ce, fptr, error_type);
2680 zend_check_magic_method_public(ce, fptr, error_type);
2681 zend_check_magic_method_arg_type(0, ce, fptr, error_type, MAY_BE_STRING);
2682 zend_check_magic_method_arg_type(1, ce, fptr, error_type, MAY_BE_ARRAY);
2683 } else if (zend_string_equals_literal(lcname, ZEND_CALLSTATIC_FUNC_NAME)) {
2684 zend_check_magic_method_args(2, ce, fptr, error_type);
2685 zend_check_magic_method_static(ce, fptr, error_type);
2686 zend_check_magic_method_public(ce, fptr, error_type);
2687 zend_check_magic_method_arg_type(0, ce, fptr, error_type, MAY_BE_STRING);
2688 zend_check_magic_method_arg_type(1, ce, fptr, error_type, MAY_BE_ARRAY);
2689 } else if (zend_string_equals_literal(lcname, ZEND_TOSTRING_FUNC_NAME)) {
2690 zend_check_magic_method_args(0, ce, fptr, error_type);
2691 zend_check_magic_method_non_static(ce, fptr, error_type);
2692 zend_check_magic_method_public(ce, fptr, error_type);
2693 zend_check_magic_method_return_type(ce, fptr, error_type, MAY_BE_STRING);
2694 } else if (zend_string_equals_literal(lcname, ZEND_DEBUGINFO_FUNC_NAME)) {
2695 zend_check_magic_method_args(0, ce, fptr, error_type);
2696 zend_check_magic_method_non_static(ce, fptr, error_type);
2697 zend_check_magic_method_public(ce, fptr, error_type);
2698 zend_check_magic_method_return_type(ce, fptr, error_type, (MAY_BE_ARRAY | MAY_BE_NULL));
2699 } else if (zend_string_equals_literal(lcname, "__serialize")) {
2700 zend_check_magic_method_args(0, ce, fptr, error_type);
2701 zend_check_magic_method_non_static(ce, fptr, error_type);
2702 zend_check_magic_method_public(ce, fptr, error_type);
2703 zend_check_magic_method_return_type(ce, fptr, error_type, MAY_BE_ARRAY);
2704 } else if (zend_string_equals_literal(lcname, "__unserialize")) {
2705 zend_check_magic_method_args(1, ce, fptr, error_type);
2706 zend_check_magic_method_non_static(ce, fptr, error_type);
2707 zend_check_magic_method_public(ce, fptr, error_type);
2708 zend_check_magic_method_arg_type(0, ce, fptr, error_type, MAY_BE_ARRAY);
2709 zend_check_magic_method_return_type(ce, fptr, error_type, MAY_BE_VOID);
2710 } else if (zend_string_equals_literal(lcname, "__set_state")) {
2711 zend_check_magic_method_args(1, ce, fptr, error_type);
2712 zend_check_magic_method_static(ce, fptr, error_type);
2713 zend_check_magic_method_public(ce, fptr, error_type);
2714 zend_check_magic_method_arg_type(0, ce, fptr, error_type, MAY_BE_ARRAY);
2715 zend_check_magic_method_return_type(ce, fptr, error_type, MAY_BE_OBJECT);
2716 } else if (zend_string_equals(lcname, ZSTR_KNOWN(ZEND_STR_MAGIC_INVOKE))) {
2717 zend_check_magic_method_non_static(ce, fptr, error_type);
2718 zend_check_magic_method_public(ce, fptr, error_type);
2719 } else if (zend_string_equals(lcname, ZSTR_KNOWN(ZEND_STR_SLEEP))) {
2720 zend_check_magic_method_args(0, ce, fptr, error_type);
2721 zend_check_magic_method_non_static(ce, fptr, error_type);
2722 zend_check_magic_method_public(ce, fptr, error_type);
2723 zend_check_magic_method_return_type(ce, fptr, error_type, MAY_BE_ARRAY);
2724 } else if (zend_string_equals(lcname, ZSTR_KNOWN(ZEND_STR_WAKEUP))) {
2725 zend_check_magic_method_args(0, ce, fptr, error_type);
2726 zend_check_magic_method_non_static(ce, fptr, error_type);
2727 zend_check_magic_method_public(ce, fptr, error_type);
2728 zend_check_magic_method_return_type(ce, fptr, error_type, MAY_BE_VOID);
2729 }
2730 }
2731 /* }}} */
2732
zend_add_magic_method(zend_class_entry * ce,zend_function * fptr,zend_string * lcname)2733 ZEND_API void zend_add_magic_method(zend_class_entry *ce, zend_function *fptr, zend_string *lcname)
2734 {
2735 if (ZSTR_VAL(lcname)[0] != '_' || ZSTR_VAL(lcname)[1] != '_') {
2736 /* pass */
2737 } else if (zend_string_equals_literal(lcname, ZEND_CLONE_FUNC_NAME)) {
2738 ce->clone = fptr;
2739 } else if (zend_string_equals_literal(lcname, ZEND_CONSTRUCTOR_FUNC_NAME)) {
2740 ce->constructor = fptr;
2741 ce->constructor->common.fn_flags |= ZEND_ACC_CTOR;
2742 } else if (zend_string_equals_literal(lcname, ZEND_DESTRUCTOR_FUNC_NAME)) {
2743 ce->destructor = fptr;
2744 } else if (zend_string_equals_literal(lcname, ZEND_GET_FUNC_NAME)) {
2745 ce->__get = fptr;
2746 ce->ce_flags |= ZEND_ACC_USE_GUARDS;
2747 } else if (zend_string_equals_literal(lcname, ZEND_SET_FUNC_NAME)) {
2748 ce->__set = fptr;
2749 ce->ce_flags |= ZEND_ACC_USE_GUARDS;
2750 } else if (zend_string_equals_literal(lcname, ZEND_CALL_FUNC_NAME)) {
2751 ce->__call = fptr;
2752 } else if (zend_string_equals_literal(lcname, ZEND_UNSET_FUNC_NAME)) {
2753 ce->__unset = fptr;
2754 ce->ce_flags |= ZEND_ACC_USE_GUARDS;
2755 } else if (zend_string_equals_literal(lcname, ZEND_ISSET_FUNC_NAME)) {
2756 ce->__isset = fptr;
2757 ce->ce_flags |= ZEND_ACC_USE_GUARDS;
2758 } else if (zend_string_equals_literal(lcname, ZEND_CALLSTATIC_FUNC_NAME)) {
2759 ce->__callstatic = fptr;
2760 } else if (zend_string_equals_literal(lcname, ZEND_TOSTRING_FUNC_NAME)) {
2761 ce->__tostring = fptr;
2762 } else if (zend_string_equals_literal(lcname, ZEND_DEBUGINFO_FUNC_NAME)) {
2763 ce->__debugInfo = fptr;
2764 ce->ce_flags |= ZEND_ACC_USE_GUARDS;
2765 } else if (zend_string_equals_literal(lcname, "__serialize")) {
2766 ce->__serialize = fptr;
2767 } else if (zend_string_equals_literal(lcname, "__unserialize")) {
2768 ce->__unserialize = fptr;
2769 }
2770 }
2771
2772 ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arg_info_toString, 0, 0, IS_STRING, 0)
ZEND_END_ARG_INFO()2773 ZEND_END_ARG_INFO()
2774
2775 static zend_always_inline void zend_normalize_internal_type(zend_type *type) {
2776 ZEND_ASSERT(!ZEND_TYPE_HAS_LITERAL_NAME(*type));
2777 zend_type *current;
2778 ZEND_TYPE_FOREACH(*type, current) {
2779 if (ZEND_TYPE_HAS_NAME(*current)) {
2780 zend_string *name = zend_new_interned_string(ZEND_TYPE_NAME(*current));
2781 zend_alloc_ce_cache(name);
2782 ZEND_TYPE_SET_PTR(*current, name);
2783 } else if (ZEND_TYPE_HAS_LIST(*current)) {
2784 zend_type *inner;
2785 ZEND_TYPE_FOREACH(*current, inner) {
2786 ZEND_ASSERT(!ZEND_TYPE_HAS_LITERAL_NAME(*inner) && !ZEND_TYPE_HAS_LIST(*inner));
2787 if (ZEND_TYPE_HAS_NAME(*inner)) {
2788 zend_string *name = zend_new_interned_string(ZEND_TYPE_NAME(*inner));
2789 zend_alloc_ce_cache(name);
2790 ZEND_TYPE_SET_PTR(*inner, name);
2791 }
2792 } ZEND_TYPE_FOREACH_END();
2793 }
2794 } ZEND_TYPE_FOREACH_END();
2795 }
2796
2797 /* registers all functions in *library_functions in the function hash */
zend_register_functions(zend_class_entry * scope,const zend_function_entry * functions,HashTable * function_table,int type)2798 ZEND_API zend_result zend_register_functions(zend_class_entry *scope, const zend_function_entry *functions, HashTable *function_table, int type) /* {{{ */
2799 {
2800 const zend_function_entry *ptr = functions;
2801 zend_function function;
2802 zend_internal_function *reg_function, *internal_function = (zend_internal_function *)&function;
2803 int count=0, unload=0;
2804 HashTable *target_function_table = function_table;
2805 int error_type;
2806 zend_string *lowercase_name;
2807 size_t fname_len;
2808
2809 if (type==MODULE_PERSISTENT) {
2810 error_type = E_CORE_WARNING;
2811 } else {
2812 error_type = E_WARNING;
2813 }
2814
2815 if (!target_function_table) {
2816 target_function_table = CG(function_table);
2817 }
2818 internal_function->type = ZEND_INTERNAL_FUNCTION;
2819 internal_function->module = EG(current_module);
2820 internal_function->T = 0;
2821 memset(internal_function->reserved, 0, ZEND_MAX_RESERVED_RESOURCES * sizeof(void*));
2822
2823 while (ptr->fname) {
2824 fname_len = strlen(ptr->fname);
2825 internal_function->handler = ptr->handler;
2826 internal_function->function_name = zend_string_init_interned(ptr->fname, fname_len, 1);
2827 internal_function->scope = scope;
2828 internal_function->prototype = NULL;
2829 internal_function->attributes = NULL;
2830 if (EG(active)) { // at run-time: this ought to only happen if registered with dl() or somehow temporarily at runtime
2831 ZEND_MAP_PTR_INIT(internal_function->run_time_cache, zend_arena_calloc(&CG(arena), 1, zend_internal_run_time_cache_reserved_size()));
2832 } else {
2833 ZEND_MAP_PTR_NEW(internal_function->run_time_cache);
2834 }
2835 if (ptr->flags) {
2836 if (!(ptr->flags & ZEND_ACC_PPP_MASK)) {
2837 if (ptr->flags != ZEND_ACC_DEPRECATED && scope) {
2838 zend_error(error_type, "Invalid access level for %s::%s() - access must be exactly one of public, protected or private", ZSTR_VAL(scope->name), ptr->fname);
2839 }
2840 internal_function->fn_flags = ZEND_ACC_PUBLIC | ptr->flags;
2841 } else {
2842 internal_function->fn_flags = ptr->flags;
2843 }
2844 } else {
2845 internal_function->fn_flags = ZEND_ACC_PUBLIC;
2846 }
2847
2848 if (ptr->arg_info) {
2849 zend_internal_function_info *info = (zend_internal_function_info*)ptr->arg_info;
2850 internal_function->arg_info = (zend_internal_arg_info*)ptr->arg_info+1;
2851 internal_function->num_args = ptr->num_args;
2852 /* Currently you cannot denote that the function can accept less arguments than num_args */
2853 if (info->required_num_args == (uintptr_t)-1) {
2854 internal_function->required_num_args = ptr->num_args;
2855 } else {
2856 internal_function->required_num_args = info->required_num_args;
2857 }
2858 if (ZEND_ARG_SEND_MODE(info)) {
2859 internal_function->fn_flags |= ZEND_ACC_RETURN_REFERENCE;
2860 }
2861 if (ZEND_ARG_IS_VARIADIC(&ptr->arg_info[ptr->num_args])) {
2862 internal_function->fn_flags |= ZEND_ACC_VARIADIC;
2863 /* Don't count the variadic argument */
2864 internal_function->num_args--;
2865 }
2866 if (ZEND_TYPE_IS_SET(info->type)) {
2867 if (ZEND_TYPE_HAS_NAME(info->type)) {
2868 const char *type_name = ZEND_TYPE_LITERAL_NAME(info->type);
2869 if (!scope && (!strcasecmp(type_name, "self") || !strcasecmp(type_name, "parent"))) {
2870 zend_error_noreturn(E_CORE_ERROR, "Cannot declare a return type of %s outside of a class scope", type_name);
2871 }
2872 }
2873
2874 internal_function->fn_flags |= ZEND_ACC_HAS_RETURN_TYPE;
2875 }
2876 } else {
2877 zend_error(E_CORE_WARNING, "Missing arginfo for %s%s%s()",
2878 scope ? ZSTR_VAL(scope->name) : "", scope ? "::" : "", ptr->fname);
2879
2880 internal_function->arg_info = NULL;
2881 internal_function->num_args = 0;
2882 internal_function->required_num_args = 0;
2883 }
2884
2885 /* If not specified, add __toString() return type for compatibility with Stringable
2886 * interface. */
2887 if (scope && zend_string_equals_literal_ci(internal_function->function_name, "__tostring") &&
2888 !(internal_function->fn_flags & ZEND_ACC_HAS_RETURN_TYPE)) {
2889 zend_error(E_CORE_WARNING, "%s::__toString() implemented without string return type",
2890 ZSTR_VAL(scope->name));
2891 internal_function->arg_info = (zend_internal_arg_info *) arg_info_toString + 1;
2892 internal_function->fn_flags |= ZEND_ACC_HAS_RETURN_TYPE;
2893 internal_function->num_args = internal_function->required_num_args = 0;
2894 }
2895
2896
2897 zend_set_function_arg_flags((zend_function*)internal_function);
2898 if (ptr->flags & ZEND_ACC_ABSTRACT) {
2899 if (scope) {
2900 /* This is a class that must be abstract itself. Here we set the check info. */
2901 scope->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
2902 if (!(scope->ce_flags & ZEND_ACC_INTERFACE)) {
2903 /* Since the class is not an interface it needs to be declared as a abstract class. */
2904 /* Since here we are handling internal functions only we can add the keyword flag. */
2905 /* This time we set the flag for the keyword 'abstract'. */
2906 scope->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS;
2907 }
2908 }
2909 if ((ptr->flags & ZEND_ACC_STATIC) && (!scope || !(scope->ce_flags & ZEND_ACC_INTERFACE))) {
2910 zend_error(error_type, "Static function %s%s%s() cannot be abstract", scope ? ZSTR_VAL(scope->name) : "", scope ? "::" : "", ptr->fname);
2911 }
2912 } else {
2913 if (scope && (scope->ce_flags & ZEND_ACC_INTERFACE)) {
2914 zend_error(error_type, "Interface %s cannot contain non abstract method %s()", ZSTR_VAL(scope->name), ptr->fname);
2915 return FAILURE;
2916 }
2917 if (!internal_function->handler) {
2918 zend_error(error_type, "Method %s%s%s() cannot be a NULL function", scope ? ZSTR_VAL(scope->name) : "", scope ? "::" : "", ptr->fname);
2919 zend_unregister_functions(functions, count, target_function_table);
2920 return FAILURE;
2921 }
2922 }
2923 lowercase_name = zend_string_tolower_ex(internal_function->function_name, type == MODULE_PERSISTENT);
2924 lowercase_name = zend_new_interned_string(lowercase_name);
2925 reg_function = malloc(sizeof(zend_internal_function));
2926 memcpy(reg_function, &function, sizeof(zend_internal_function));
2927 if (zend_hash_add_ptr(target_function_table, lowercase_name, reg_function) == NULL) {
2928 unload=1;
2929 free(reg_function);
2930 zend_string_release(lowercase_name);
2931 break;
2932 }
2933
2934 /* Get parameter count including variadic parameter. */
2935 uint32_t num_args = reg_function->num_args;
2936 if (reg_function->fn_flags & ZEND_ACC_VARIADIC) {
2937 num_args++;
2938 }
2939
2940 /* If types of arguments have to be checked */
2941 if (reg_function->arg_info && num_args) {
2942 uint32_t i;
2943 for (i = 0; i < num_args; i++) {
2944 zend_internal_arg_info *arg_info = ®_function->arg_info[i];
2945 ZEND_ASSERT(arg_info->name && "Parameter must have a name");
2946 if (ZEND_TYPE_IS_SET(arg_info->type)) {
2947 reg_function->fn_flags |= ZEND_ACC_HAS_TYPE_HINTS;
2948 }
2949 #if ZEND_DEBUG
2950 for (uint32_t j = 0; j < i; j++) {
2951 if (!strcmp(arg_info->name, reg_function->arg_info[j].name)) {
2952 zend_error_noreturn(E_CORE_ERROR,
2953 "Duplicate parameter name $%s for function %s%s%s()", arg_info->name,
2954 scope ? ZSTR_VAL(scope->name) : "", scope ? "::" : "", ptr->fname);
2955 }
2956 }
2957 #endif
2958 }
2959 }
2960
2961 /* Rebuild arginfos if parameter/property types and/or a return type are used */
2962 if (reg_function->arg_info &&
2963 (reg_function->fn_flags & (ZEND_ACC_HAS_RETURN_TYPE|ZEND_ACC_HAS_TYPE_HINTS))) {
2964 /* convert "const char*" class type names into "zend_string*" */
2965 uint32_t i;
2966 zend_internal_arg_info *arg_info = reg_function->arg_info - 1;
2967 zend_internal_arg_info *new_arg_info;
2968
2969 /* Treat return type as an extra argument */
2970 num_args++;
2971 new_arg_info = malloc(sizeof(zend_internal_arg_info) * num_args);
2972 memcpy(new_arg_info, arg_info, sizeof(zend_internal_arg_info) * num_args);
2973 reg_function->arg_info = new_arg_info + 1;
2974 for (i = 0; i < num_args; i++) {
2975 if (ZEND_TYPE_HAS_LITERAL_NAME(new_arg_info[i].type)) {
2976 // gen_stubs.php does not support codegen for DNF types in arg infos.
2977 // As a temporary workaround, we split the type name on `|` characters,
2978 // converting it to an union type if necessary.
2979 const char *class_name = ZEND_TYPE_LITERAL_NAME(new_arg_info[i].type);
2980 new_arg_info[i].type.type_mask &= ~_ZEND_TYPE_LITERAL_NAME_BIT;
2981
2982 size_t num_types = 1;
2983 const char *p = class_name;
2984 while ((p = strchr(p, '|'))) {
2985 num_types++;
2986 p++;
2987 }
2988
2989 if (num_types == 1) {
2990 /* Simple class type */
2991 zend_string *str = zend_string_init_interned(class_name, strlen(class_name), 1);
2992 zend_alloc_ce_cache(str);
2993 ZEND_TYPE_SET_PTR(new_arg_info[i].type, str);
2994 new_arg_info[i].type.type_mask |= _ZEND_TYPE_NAME_BIT;
2995 } else {
2996 /* Union type */
2997 zend_type_list *list = malloc(ZEND_TYPE_LIST_SIZE(num_types));
2998 list->num_types = num_types;
2999 ZEND_TYPE_SET_LIST(new_arg_info[i].type, list);
3000 ZEND_TYPE_FULL_MASK(new_arg_info[i].type) |= _ZEND_TYPE_UNION_BIT;
3001
3002 const char *start = class_name;
3003 uint32_t j = 0;
3004 while (true) {
3005 const char *end = strchr(start, '|');
3006 zend_string *str = zend_string_init_interned(start, end ? end - start : strlen(start), 1);
3007 zend_alloc_ce_cache(str);
3008 list->types[j] = (zend_type) ZEND_TYPE_INIT_CLASS(str, 0, 0);
3009 if (!end) {
3010 break;
3011 }
3012 start = end + 1;
3013 j++;
3014 }
3015 }
3016 }
3017 if (ZEND_TYPE_IS_ITERABLE_FALLBACK(new_arg_info[i].type)) {
3018 /* Warning generated an extension load warning which is emitted for every test
3019 zend_error(E_CORE_WARNING, "iterable type is now a compile time alias for array|Traversable,"
3020 " regenerate the argument info via the php-src gen_stub build script");
3021 */
3022 zend_type legacy_iterable = ZEND_TYPE_INIT_CLASS_MASK(
3023 ZSTR_KNOWN(ZEND_STR_TRAVERSABLE),
3024 (new_arg_info[i].type.type_mask | MAY_BE_ARRAY)
3025 );
3026 new_arg_info[i].type = legacy_iterable;
3027 }
3028
3029 zend_normalize_internal_type(&new_arg_info[i].type);
3030 }
3031 }
3032
3033 if (scope) {
3034 zend_check_magic_method_implementation(
3035 scope, (zend_function *)reg_function, lowercase_name, E_CORE_ERROR);
3036 zend_add_magic_method(scope, (zend_function *)reg_function, lowercase_name);
3037 }
3038 ptr++;
3039 count++;
3040 zend_string_release(lowercase_name);
3041 }
3042 if (unload) { /* before unloading, display all remaining bad function in the module */
3043 while (ptr->fname) {
3044 fname_len = strlen(ptr->fname);
3045 lowercase_name = zend_string_alloc(fname_len, 0);
3046 zend_str_tolower_copy(ZSTR_VAL(lowercase_name), ptr->fname, fname_len);
3047 if (zend_hash_exists(target_function_table, lowercase_name)) {
3048 zend_error(error_type, "Function registration failed - duplicate name - %s%s%s", scope ? ZSTR_VAL(scope->name) : "", scope ? "::" : "", ptr->fname);
3049 }
3050 zend_string_efree(lowercase_name);
3051 ptr++;
3052 }
3053 zend_unregister_functions(functions, count, target_function_table);
3054 return FAILURE;
3055 }
3056 return SUCCESS;
3057 }
3058 /* }}} */
3059
3060 /* count=-1 means erase all functions, otherwise,
3061 * erase the first count functions
3062 */
zend_unregister_functions(const zend_function_entry * functions,int count,HashTable * function_table)3063 ZEND_API void zend_unregister_functions(const zend_function_entry *functions, int count, HashTable *function_table) /* {{{ */
3064 {
3065 const zend_function_entry *ptr = functions;
3066 int i=0;
3067 HashTable *target_function_table = function_table;
3068 zend_string *lowercase_name;
3069 size_t fname_len;
3070
3071 if (!target_function_table) {
3072 target_function_table = CG(function_table);
3073 }
3074 while (ptr->fname) {
3075 if (count!=-1 && i>=count) {
3076 break;
3077 }
3078 fname_len = strlen(ptr->fname);
3079 lowercase_name = zend_string_alloc(fname_len, 0);
3080 zend_str_tolower_copy(ZSTR_VAL(lowercase_name), ptr->fname, fname_len);
3081 zend_hash_del(target_function_table, lowercase_name);
3082 zend_string_efree(lowercase_name);
3083 ptr++;
3084 i++;
3085 }
3086 }
3087 /* }}} */
3088
zend_startup_module(zend_module_entry * module)3089 ZEND_API zend_result zend_startup_module(zend_module_entry *module) /* {{{ */
3090 {
3091 if ((module = zend_register_internal_module(module)) != NULL && zend_startup_module_ex(module) == SUCCESS) {
3092 return SUCCESS;
3093 }
3094 return FAILURE;
3095 }
3096 /* }}} */
3097
zend_get_module_started(const char * module_name)3098 ZEND_API zend_result zend_get_module_started(const char *module_name) /* {{{ */
3099 {
3100 zend_module_entry *module;
3101
3102 module = zend_hash_str_find_ptr(&module_registry, module_name, strlen(module_name));
3103 return (module && module->module_started) ? SUCCESS : FAILURE;
3104 }
3105 /* }}} */
3106
clean_module_class(zval * el,void * arg)3107 static int clean_module_class(zval *el, void *arg) /* {{{ */
3108 {
3109 zend_class_entry *ce = (zend_class_entry *)Z_PTR_P(el);
3110 int module_number = *(int *)arg;
3111 if (ce->type == ZEND_INTERNAL_CLASS && ce->info.internal.module->module_number == module_number) {
3112 return ZEND_HASH_APPLY_REMOVE;
3113 } else {
3114 return ZEND_HASH_APPLY_KEEP;
3115 }
3116 }
3117 /* }}} */
3118
clean_module_classes(int module_number)3119 static void clean_module_classes(int module_number) /* {{{ */
3120 {
3121 zend_hash_apply_with_argument(EG(class_table), clean_module_class, (void *) &module_number);
3122 }
3123 /* }}} */
3124
clean_module_function(zval * el,void * arg)3125 static int clean_module_function(zval *el, void *arg) /* {{{ */
3126 {
3127 zend_function *fe = (zend_function *) Z_PTR_P(el);
3128 zend_module_entry *module = (zend_module_entry *) arg;
3129 if (fe->common.type == ZEND_INTERNAL_FUNCTION && fe->internal_function.module == module) {
3130 return ZEND_HASH_APPLY_REMOVE;
3131 } else {
3132 return ZEND_HASH_APPLY_KEEP;
3133 }
3134 }
3135 /* }}} */
3136
clean_module_functions(zend_module_entry * module)3137 static void clean_module_functions(zend_module_entry *module) /* {{{ */
3138 {
3139 zend_hash_apply_with_argument(CG(function_table), clean_module_function, module);
3140 }
3141 /* }}} */
3142
module_destructor(zend_module_entry * module)3143 void module_destructor(zend_module_entry *module) /* {{{ */
3144 {
3145 #if ZEND_RC_DEBUG
3146 bool orig_rc_debug = zend_rc_debug;
3147 #endif
3148
3149 if (module->type == MODULE_TEMPORARY) {
3150 #if ZEND_RC_DEBUG
3151 /* FIXME: Loading extensions during the request breaks some invariants.
3152 * In particular, it will create persistent interned strings, which is
3153 * not allowed at this stage. */
3154 zend_rc_debug = false;
3155 #endif
3156 zend_clean_module_rsrc_dtors(module->module_number);
3157 clean_module_constants(module->module_number);
3158 clean_module_classes(module->module_number);
3159 }
3160
3161 if (module->module_started && module->module_shutdown_func) {
3162 #if 0
3163 zend_printf("%s: Module shutdown\n", module->name);
3164 #endif
3165 module->module_shutdown_func(module->type, module->module_number);
3166 }
3167
3168 if (module->module_started
3169 && !module->module_shutdown_func
3170 && module->type == MODULE_TEMPORARY) {
3171 zend_unregister_ini_entries_ex(module->module_number, module->type);
3172 }
3173
3174 /* Deinitialize module globals */
3175 if (module->globals_size) {
3176 #ifdef ZTS
3177 if (*module->globals_id_ptr) {
3178 ts_free_id(*module->globals_id_ptr);
3179 }
3180 #else
3181 if (module->globals_dtor) {
3182 module->globals_dtor(module->globals_ptr);
3183 }
3184 #endif
3185 }
3186
3187 module->module_started=0;
3188 if (module->type == MODULE_TEMPORARY && module->functions) {
3189 zend_unregister_functions(module->functions, -1, NULL);
3190 /* Clean functions registered separately from module->functions */
3191 clean_module_functions(module);
3192 }
3193
3194 #if ZEND_RC_DEBUG
3195 zend_rc_debug = orig_rc_debug;
3196 #endif
3197 }
3198 /* }}} */
3199
module_registry_unload(const zend_module_entry * module)3200 void module_registry_unload(const zend_module_entry *module)
3201 {
3202 #if HAVE_LIBDL
3203 if (!getenv("ZEND_DONT_UNLOAD_MODULES")) {
3204 DL_UNLOAD(module->handle);
3205 }
3206 #else
3207 ZEND_IGNORE_VALUE(module);
3208 #endif
3209 }
3210
zend_activate_modules(void)3211 ZEND_API void zend_activate_modules(void) /* {{{ */
3212 {
3213 zend_module_entry **p = module_request_startup_handlers;
3214
3215 while (*p) {
3216 zend_module_entry *module = *p;
3217
3218 if (module->request_startup_func(module->type, module->module_number)==FAILURE) {
3219 zend_error(E_WARNING, "request_startup() for %s module failed", module->name);
3220 exit(1);
3221 }
3222 p++;
3223 }
3224 }
3225 /* }}} */
3226
zend_deactivate_modules(void)3227 ZEND_API void zend_deactivate_modules(void) /* {{{ */
3228 {
3229 EG(current_execute_data) = NULL; /* we're no longer executing anything */
3230
3231 if (EG(full_tables_cleanup)) {
3232 zend_module_entry *module;
3233
3234 ZEND_HASH_MAP_REVERSE_FOREACH_PTR(&module_registry, module) {
3235 if (module->request_shutdown_func) {
3236 zend_try {
3237 module->request_shutdown_func(module->type, module->module_number);
3238 } zend_end_try();
3239 }
3240 } ZEND_HASH_FOREACH_END();
3241 } else {
3242 zend_module_entry **p = module_request_shutdown_handlers;
3243
3244 while (*p) {
3245 zend_module_entry *module = *p;
3246 zend_try {
3247 module->request_shutdown_func(module->type, module->module_number);
3248 } zend_end_try();
3249 p++;
3250 }
3251 }
3252 }
3253 /* }}} */
3254
zend_unload_modules(void)3255 void zend_unload_modules(void) /* {{{ */
3256 {
3257 zend_module_entry **modules = modules_dl_loaded;
3258 while (*modules) {
3259 module_registry_unload(*modules);
3260 modules++;
3261 }
3262 free(modules_dl_loaded);
3263 modules_dl_loaded = NULL;
3264 }
3265 /* }}} */
3266
zend_post_deactivate_modules(void)3267 ZEND_API void zend_post_deactivate_modules(void) /* {{{ */
3268 {
3269 if (EG(full_tables_cleanup)) {
3270 zend_module_entry *module;
3271 zval *zv;
3272 zend_string *key;
3273
3274 ZEND_HASH_MAP_FOREACH_PTR(&module_registry, module) {
3275 if (module->post_deactivate_func) {
3276 module->post_deactivate_func();
3277 }
3278 } ZEND_HASH_FOREACH_END();
3279 ZEND_HASH_MAP_REVERSE_FOREACH_STR_KEY_VAL(&module_registry, key, zv) {
3280 module = Z_PTR_P(zv);
3281 if (module->type != MODULE_TEMPORARY) {
3282 break;
3283 }
3284 module_destructor(module);
3285 if (module->handle) {
3286 module_registry_unload(module);
3287 }
3288 zend_string_release_ex(key, 0);
3289 } ZEND_HASH_MAP_FOREACH_END_DEL();
3290 } else {
3291 zend_module_entry **p = module_post_deactivate_handlers;
3292
3293 while (*p) {
3294 zend_module_entry *module = *p;
3295
3296 module->post_deactivate_func();
3297 p++;
3298 }
3299 }
3300 }
3301 /* }}} */
3302
3303 /* return the next free module number */
zend_next_free_module(void)3304 ZEND_API int zend_next_free_module(void) /* {{{ */
3305 {
3306 return zend_hash_num_elements(&module_registry) + 1;
3307 }
3308 /* }}} */
3309
do_register_internal_class(zend_class_entry * orig_class_entry,uint32_t ce_flags)3310 static zend_class_entry *do_register_internal_class(zend_class_entry *orig_class_entry, uint32_t ce_flags) /* {{{ */
3311 {
3312 zend_class_entry *class_entry = malloc(sizeof(zend_class_entry));
3313 zend_string *lowercase_name;
3314 *class_entry = *orig_class_entry;
3315
3316 class_entry->type = ZEND_INTERNAL_CLASS;
3317 zend_initialize_class_data(class_entry, 0);
3318 zend_alloc_ce_cache(class_entry->name);
3319 class_entry->ce_flags = orig_class_entry->ce_flags | ce_flags | ZEND_ACC_CONSTANTS_UPDATED | ZEND_ACC_LINKED | ZEND_ACC_RESOLVED_PARENT | ZEND_ACC_RESOLVED_INTERFACES;
3320 class_entry->info.internal.module = EG(current_module);
3321
3322 if (class_entry->info.internal.builtin_functions) {
3323 zend_register_functions(class_entry, class_entry->info.internal.builtin_functions, &class_entry->function_table, EG(current_module)->type);
3324 }
3325
3326 lowercase_name = zend_string_tolower_ex(orig_class_entry->name, EG(current_module)->type == MODULE_PERSISTENT);
3327 lowercase_name = zend_new_interned_string(lowercase_name);
3328 zend_hash_update_ptr(CG(class_table), lowercase_name, class_entry);
3329 zend_string_release_ex(lowercase_name, 1);
3330
3331 if (class_entry->__tostring && !zend_string_equals_literal(class_entry->name, "Stringable")
3332 && !(class_entry->ce_flags & ZEND_ACC_TRAIT)) {
3333 ZEND_ASSERT(zend_ce_stringable
3334 && "Should be registered before first class using __toString()");
3335 zend_do_implement_interface(class_entry, zend_ce_stringable);
3336 }
3337 return class_entry;
3338 }
3339 /* }}} */
3340
3341 /* If parent_ce is not NULL then it inherits from parent_ce
3342 * If parent_ce is NULL and parent_name isn't then it looks for the parent and inherits from it
3343 * If both parent_ce and parent_name are NULL it does a regular class registration
3344 * If parent_name is specified but not found NULL is returned
3345 */
zend_register_internal_class_ex(zend_class_entry * class_entry,zend_class_entry * parent_ce)3346 ZEND_API zend_class_entry *zend_register_internal_class_ex(zend_class_entry *class_entry, zend_class_entry *parent_ce) /* {{{ */
3347 {
3348 zend_class_entry *register_class;
3349
3350 register_class = zend_register_internal_class(class_entry);
3351
3352 if (parent_ce) {
3353 zend_do_inheritance(register_class, parent_ce);
3354 zend_build_properties_info_table(register_class);
3355 }
3356
3357 return register_class;
3358 }
3359 /* }}} */
3360
zend_class_implements(zend_class_entry * class_entry,int num_interfaces,...)3361 ZEND_API void zend_class_implements(zend_class_entry *class_entry, int num_interfaces, ...) /* {{{ */
3362 {
3363 zend_class_entry *interface_entry;
3364 va_list interface_list;
3365 va_start(interface_list, num_interfaces);
3366
3367 while (num_interfaces--) {
3368 interface_entry = va_arg(interface_list, zend_class_entry *);
3369 if (interface_entry == zend_ce_stringable
3370 && zend_class_implements_interface(class_entry, zend_ce_stringable)) {
3371 /* Stringable is implemented automatically,
3372 * silently ignore an explicit implementation. */
3373 continue;
3374 }
3375
3376 zend_do_implement_interface(class_entry, interface_entry);
3377 }
3378
3379 va_end(interface_list);
3380 }
3381 /* }}} */
3382
3383 /* A class that contains at least one abstract method automatically becomes an abstract class.
3384 */
zend_register_internal_class(zend_class_entry * orig_class_entry)3385 ZEND_API zend_class_entry *zend_register_internal_class(zend_class_entry *orig_class_entry) /* {{{ */
3386 {
3387 return do_register_internal_class(orig_class_entry, 0);
3388 }
3389 /* }}} */
3390
zend_register_internal_interface(zend_class_entry * orig_class_entry)3391 ZEND_API zend_class_entry *zend_register_internal_interface(zend_class_entry *orig_class_entry) /* {{{ */
3392 {
3393 return do_register_internal_class(orig_class_entry, ZEND_ACC_INTERFACE);
3394 }
3395 /* }}} */
3396
zend_register_class_alias_ex(const char * name,size_t name_len,zend_class_entry * ce,bool persistent)3397 ZEND_API zend_result zend_register_class_alias_ex(const char *name, size_t name_len, zend_class_entry *ce, bool persistent) /* {{{ */
3398 {
3399 zend_string *lcname;
3400 zval zv, *ret;
3401
3402 /* TODO: Move this out of here in 7.4. */
3403 if (persistent && EG(current_module) && EG(current_module)->type == MODULE_TEMPORARY) {
3404 persistent = 0;
3405 }
3406
3407 if (name[0] == '\\') {
3408 lcname = zend_string_alloc(name_len-1, persistent);
3409 zend_str_tolower_copy(ZSTR_VAL(lcname), name+1, name_len-1);
3410 } else {
3411 lcname = zend_string_alloc(name_len, persistent);
3412 zend_str_tolower_copy(ZSTR_VAL(lcname), name, name_len);
3413 }
3414
3415 zend_assert_valid_class_name(lcname);
3416
3417 lcname = zend_new_interned_string(lcname);
3418
3419 /* We cannot increase the refcount of an internal class during request time.
3420 * Instead of having to deal with differentiating between class types and lifetimes,
3421 * we simply don't increase the refcount of a class entry for aliases.
3422 */
3423 ZVAL_ALIAS_PTR(&zv, ce);
3424
3425 ret = zend_hash_add(CG(class_table), lcname, &zv);
3426 zend_string_release_ex(lcname, 0);
3427 if (ret) {
3428 // avoid notifying at MINIT time
3429 if (ce->type == ZEND_USER_CLASS) {
3430 zend_observer_class_linked_notify(ce, lcname);
3431 }
3432 return SUCCESS;
3433 }
3434 return FAILURE;
3435 }
3436 /* }}} */
3437
3438 // TODO num_symbol_tables as unsigned int?
zend_set_hash_symbol(zval * symbol,const char * name,size_t name_length,bool is_ref,int num_symbol_tables,...)3439 ZEND_API zend_result zend_set_hash_symbol(zval *symbol, const char *name, size_t name_length, bool is_ref, int num_symbol_tables, ...) /* {{{ */
3440 {
3441 HashTable *symbol_table;
3442 va_list symbol_table_list;
3443
3444 if (num_symbol_tables <= 0) return FAILURE;
3445
3446 if (is_ref) {
3447 ZVAL_MAKE_REF(symbol);
3448 }
3449
3450 va_start(symbol_table_list, num_symbol_tables);
3451 while (num_symbol_tables-- > 0) {
3452 symbol_table = va_arg(symbol_table_list, HashTable *);
3453 zend_hash_str_update(symbol_table, name, name_length, symbol);
3454 Z_TRY_ADDREF_P(symbol);
3455 }
3456 va_end(symbol_table_list);
3457 return SUCCESS;
3458 }
3459 /* }}} */
3460
3461 /* Disabled functions support */
3462
zend_disable_function(const char * function_name,size_t function_name_length)3463 static void zend_disable_function(const char *function_name, size_t function_name_length)
3464 {
3465 zend_hash_str_del(CG(function_table), function_name, function_name_length);
3466 }
3467
zend_disable_functions(const char * function_list)3468 ZEND_API void zend_disable_functions(const char *function_list) /* {{{ */
3469 {
3470 if (!function_list || !*function_list) {
3471 return;
3472 }
3473
3474 const char *s = NULL, *e = function_list;
3475 while (*e) {
3476 switch (*e) {
3477 case ' ':
3478 case ',':
3479 if (s) {
3480 zend_disable_function(s, e - s);
3481 s = NULL;
3482 }
3483 break;
3484 default:
3485 if (!s) {
3486 s = e;
3487 }
3488 break;
3489 }
3490 e++;
3491 }
3492 if (s) {
3493 zend_disable_function(s, e - s);
3494 }
3495
3496 /* Rehash the function table after deleting functions. This ensures that all internal
3497 * functions are contiguous, which means we don't need to perform full table cleanup
3498 * on shutdown. */
3499 zend_hash_rehash(CG(function_table));
3500 }
3501 /* }}} */
3502
3503 #ifdef ZEND_WIN32
3504 #pragma optimize("", off)
3505 #endif
display_disabled_class(zend_class_entry * class_type)3506 static ZEND_COLD zend_object *display_disabled_class(zend_class_entry *class_type) /* {{{ */
3507 {
3508 zend_object *intern;
3509
3510 intern = zend_objects_new(class_type);
3511
3512 /* Initialize default properties */
3513 if (EXPECTED(class_type->default_properties_count != 0)) {
3514 zval *p = intern->properties_table;
3515 zval *end = p + class_type->default_properties_count;
3516 do {
3517 ZVAL_UNDEF(p);
3518 p++;
3519 } while (p != end);
3520 }
3521
3522 zend_error(E_WARNING, "%s() has been disabled for security reasons", ZSTR_VAL(class_type->name));
3523 return intern;
3524 }
3525 #ifdef ZEND_WIN32
3526 #pragma optimize("", on)
3527 #endif
3528 /* }}} */
3529
3530 static const zend_function_entry disabled_class_new[] = {
3531 ZEND_FE_END
3532 };
3533
zend_disable_class(const char * class_name,size_t class_name_length)3534 ZEND_API zend_result zend_disable_class(const char *class_name, size_t class_name_length) /* {{{ */
3535 {
3536 zend_class_entry *disabled_class;
3537 zend_string *key;
3538 zend_function *fn;
3539 zend_property_info *prop;
3540
3541 key = zend_string_alloc(class_name_length, 0);
3542 zend_str_tolower_copy(ZSTR_VAL(key), class_name, class_name_length);
3543 disabled_class = zend_hash_find_ptr(CG(class_table), key);
3544 zend_string_release_ex(key, 0);
3545 if (!disabled_class) {
3546 return FAILURE;
3547 }
3548
3549 /* Will be reset by INIT_CLASS_ENTRY. */
3550 free(disabled_class->interfaces);
3551
3552 INIT_CLASS_ENTRY_INIT_METHODS((*disabled_class), disabled_class_new);
3553 disabled_class->create_object = display_disabled_class;
3554
3555 ZEND_HASH_MAP_FOREACH_PTR(&disabled_class->function_table, fn) {
3556 if ((fn->common.fn_flags & (ZEND_ACC_HAS_RETURN_TYPE|ZEND_ACC_HAS_TYPE_HINTS)) &&
3557 fn->common.scope == disabled_class) {
3558 zend_free_internal_arg_info(&fn->internal_function);
3559 }
3560 } ZEND_HASH_FOREACH_END();
3561 zend_hash_clean(&disabled_class->function_table);
3562 ZEND_HASH_MAP_FOREACH_PTR(&disabled_class->properties_info, prop) {
3563 if (prop->ce == disabled_class) {
3564 zend_string_release(prop->name);
3565 zend_type_release(prop->type, /* persistent */ 1);
3566 free(prop);
3567 }
3568 } ZEND_HASH_FOREACH_END();
3569 zend_hash_clean(&disabled_class->properties_info);
3570 return SUCCESS;
3571 }
3572 /* }}} */
3573
get_scope(zend_execute_data * frame)3574 static zend_always_inline zend_class_entry *get_scope(zend_execute_data *frame)
3575 {
3576 return frame && frame->func ? frame->func->common.scope : NULL;
3577 }
3578
zend_is_callable_check_class(zend_string * name,zend_class_entry * scope,zend_execute_data * frame,zend_fcall_info_cache * fcc,bool * strict_class,char ** error,bool suppress_deprecation)3579 static bool zend_is_callable_check_class(zend_string *name, zend_class_entry *scope, zend_execute_data *frame, zend_fcall_info_cache *fcc, bool *strict_class, char **error, bool suppress_deprecation) /* {{{ */
3580 {
3581 bool ret = 0;
3582 zend_class_entry *ce;
3583 size_t name_len = ZSTR_LEN(name);
3584 zend_string *lcname;
3585 ALLOCA_FLAG(use_heap);
3586
3587 ZSTR_ALLOCA_ALLOC(lcname, name_len, use_heap);
3588 zend_str_tolower_copy(ZSTR_VAL(lcname), ZSTR_VAL(name), name_len);
3589
3590 *strict_class = 0;
3591 if (zend_string_equals_literal(lcname, "self")) {
3592 if (!scope) {
3593 if (error) *error = estrdup("cannot access \"self\" when no class scope is active");
3594 } else {
3595 if (!suppress_deprecation) {
3596 zend_error(E_DEPRECATED, "Use of \"self\" in callables is deprecated");
3597 }
3598 fcc->called_scope = zend_get_called_scope(frame);
3599 if (!fcc->called_scope || !instanceof_function(fcc->called_scope, scope)) {
3600 fcc->called_scope = scope;
3601 }
3602 fcc->calling_scope = scope;
3603 if (!fcc->object) {
3604 fcc->object = zend_get_this_object(frame);
3605 }
3606 ret = 1;
3607 }
3608 } else if (zend_string_equals_literal(lcname, "parent")) {
3609 if (!scope) {
3610 if (error) *error = estrdup("cannot access \"parent\" when no class scope is active");
3611 } else if (!scope->parent) {
3612 if (error) *error = estrdup("cannot access \"parent\" when current class scope has no parent");
3613 } else {
3614 if (!suppress_deprecation) {
3615 zend_error(E_DEPRECATED, "Use of \"parent\" in callables is deprecated");
3616 }
3617 fcc->called_scope = zend_get_called_scope(frame);
3618 if (!fcc->called_scope || !instanceof_function(fcc->called_scope, scope->parent)) {
3619 fcc->called_scope = scope->parent;
3620 }
3621 fcc->calling_scope = scope->parent;
3622 if (!fcc->object) {
3623 fcc->object = zend_get_this_object(frame);
3624 }
3625 *strict_class = 1;
3626 ret = 1;
3627 }
3628 } else if (zend_string_equals(lcname, ZSTR_KNOWN(ZEND_STR_STATIC))) {
3629 zend_class_entry *called_scope = zend_get_called_scope(frame);
3630
3631 if (!called_scope) {
3632 if (error) *error = estrdup("cannot access \"static\" when no class scope is active");
3633 } else {
3634 if (!suppress_deprecation) {
3635 zend_error(E_DEPRECATED, "Use of \"static\" in callables is deprecated");
3636 }
3637 fcc->called_scope = called_scope;
3638 fcc->calling_scope = called_scope;
3639 if (!fcc->object) {
3640 fcc->object = zend_get_this_object(frame);
3641 }
3642 *strict_class = 1;
3643 ret = 1;
3644 }
3645 } else if ((ce = zend_lookup_class(name)) != NULL) {
3646 zend_class_entry *scope = get_scope(frame);
3647 fcc->calling_scope = ce;
3648 if (scope && !fcc->object) {
3649 zend_object *object = zend_get_this_object(frame);
3650
3651 if (object &&
3652 instanceof_function(object->ce, scope) &&
3653 instanceof_function(scope, ce)) {
3654 fcc->object = object;
3655 fcc->called_scope = object->ce;
3656 } else {
3657 fcc->called_scope = ce;
3658 }
3659 } else {
3660 fcc->called_scope = fcc->object ? fcc->object->ce : ce;
3661 }
3662 *strict_class = 1;
3663 ret = 1;
3664 } else {
3665 if (error) zend_spprintf(error, 0, "class \"%.*s\" not found", (int)name_len, ZSTR_VAL(name));
3666 }
3667 ZSTR_ALLOCA_FREE(lcname, use_heap);
3668 return ret;
3669 }
3670 /* }}} */
3671
zend_release_fcall_info_cache(zend_fcall_info_cache * fcc)3672 ZEND_API void zend_release_fcall_info_cache(zend_fcall_info_cache *fcc) {
3673 if (fcc->function_handler &&
3674 (fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
3675 if (fcc->function_handler->common.function_name) {
3676 zend_string_release_ex(fcc->function_handler->common.function_name, 0);
3677 }
3678 zend_free_trampoline(fcc->function_handler);
3679 fcc->function_handler = NULL;
3680 }
3681 }
3682
zend_is_callable_check_func(zval * callable,zend_execute_data * frame,zend_fcall_info_cache * fcc,bool strict_class,char ** error,bool suppress_deprecation)3683 static zend_always_inline bool zend_is_callable_check_func(zval *callable, zend_execute_data *frame, zend_fcall_info_cache *fcc, bool strict_class, char **error, bool suppress_deprecation) /* {{{ */
3684 {
3685 zend_class_entry *ce_org = fcc->calling_scope;
3686 bool retval = 0;
3687 zend_string *mname, *cname;
3688 zend_string *lmname;
3689 const char *colon;
3690 size_t clen;
3691 HashTable *ftable;
3692 int call_via_handler = 0;
3693 zend_class_entry *scope;
3694 zval *zv;
3695 ALLOCA_FLAG(use_heap)
3696
3697 fcc->calling_scope = NULL;
3698
3699 if (!ce_org) {
3700 zend_function *func;
3701 zend_string *lmname;
3702
3703 /* Check if function with given name exists.
3704 * This may be a compound name that includes namespace name */
3705 if (UNEXPECTED(Z_STRVAL_P(callable)[0] == '\\')) {
3706 /* Skip leading \ */
3707 ZSTR_ALLOCA_ALLOC(lmname, Z_STRLEN_P(callable) - 1, use_heap);
3708 zend_str_tolower_copy(ZSTR_VAL(lmname), Z_STRVAL_P(callable) + 1, Z_STRLEN_P(callable) - 1);
3709 func = zend_fetch_function(lmname);
3710 ZSTR_ALLOCA_FREE(lmname, use_heap);
3711 } else {
3712 lmname = Z_STR_P(callable);
3713 func = zend_fetch_function(lmname);
3714 if (!func) {
3715 ZSTR_ALLOCA_ALLOC(lmname, Z_STRLEN_P(callable), use_heap);
3716 zend_str_tolower_copy(ZSTR_VAL(lmname), Z_STRVAL_P(callable), Z_STRLEN_P(callable));
3717 func = zend_fetch_function(lmname);
3718 ZSTR_ALLOCA_FREE(lmname, use_heap);
3719 }
3720 }
3721 if (EXPECTED(func != NULL)) {
3722 fcc->function_handler = func;
3723 return 1;
3724 }
3725 }
3726
3727 /* Split name into class/namespace and method/function names */
3728 if ((colon = zend_memrchr(Z_STRVAL_P(callable), ':', Z_STRLEN_P(callable))) != NULL &&
3729 colon > Z_STRVAL_P(callable) &&
3730 *(colon-1) == ':'
3731 ) {
3732 size_t mlen;
3733
3734 colon--;
3735 clen = colon - Z_STRVAL_P(callable);
3736 mlen = Z_STRLEN_P(callable) - clen - 2;
3737
3738 if (colon == Z_STRVAL_P(callable)) {
3739 if (error) *error = estrdup("invalid function name");
3740 return 0;
3741 }
3742
3743 /* This is a compound name.
3744 * Try to fetch class and then find static method. */
3745 if (ce_org) {
3746 scope = ce_org;
3747 } else {
3748 scope = get_scope(frame);
3749 }
3750
3751 cname = zend_string_init_interned(Z_STRVAL_P(callable), clen, 0);
3752 if (ZSTR_HAS_CE_CACHE(cname) && ZSTR_GET_CE_CACHE(cname)) {
3753 fcc->calling_scope = ZSTR_GET_CE_CACHE(cname);
3754 if (scope && !fcc->object) {
3755 zend_object *object = zend_get_this_object(frame);
3756
3757 if (object &&
3758 instanceof_function(object->ce, scope) &&
3759 instanceof_function(scope, fcc->calling_scope)) {
3760 fcc->object = object;
3761 fcc->called_scope = object->ce;
3762 } else {
3763 fcc->called_scope = fcc->calling_scope;
3764 }
3765 } else {
3766 fcc->called_scope = fcc->object ? fcc->object->ce : fcc->calling_scope;
3767 }
3768 strict_class = 1;
3769 } else if (!zend_is_callable_check_class(cname, scope, frame, fcc, &strict_class, error, suppress_deprecation || ce_org != NULL)) {
3770 zend_string_release_ex(cname, 0);
3771 return 0;
3772 }
3773 zend_string_release_ex(cname, 0);
3774
3775 ftable = &fcc->calling_scope->function_table;
3776 if (ce_org && !instanceof_function(ce_org, fcc->calling_scope)) {
3777 if (error) zend_spprintf(error, 0, "class %s is not a subclass of %s", ZSTR_VAL(ce_org->name), ZSTR_VAL(fcc->calling_scope->name));
3778 return 0;
3779 }
3780 if (ce_org && !suppress_deprecation) {
3781 zend_error(E_DEPRECATED,
3782 "Callables of the form [\"%s\", \"%s\"] are deprecated",
3783 ZSTR_VAL(ce_org->name), Z_STRVAL_P(callable));
3784 }
3785 mname = zend_string_init(Z_STRVAL_P(callable) + clen + 2, mlen, 0);
3786 } else if (ce_org) {
3787 /* Try to fetch find static method of given class. */
3788 mname = Z_STR_P(callable);
3789 zend_string_addref(mname);
3790 ftable = &ce_org->function_table;
3791 fcc->calling_scope = ce_org;
3792 } else {
3793 /* We already checked for plain function before. */
3794 if (error) {
3795 zend_spprintf(error, 0, "function \"%s\" not found or invalid function name", Z_STRVAL_P(callable));
3796 }
3797 return 0;
3798 }
3799
3800 lmname = zend_string_tolower(mname);
3801 if (strict_class &&
3802 fcc->calling_scope &&
3803 zend_string_equals_literal(lmname, ZEND_CONSTRUCTOR_FUNC_NAME)) {
3804 fcc->function_handler = fcc->calling_scope->constructor;
3805 if (fcc->function_handler) {
3806 retval = 1;
3807 }
3808 } else if ((zv = zend_hash_find(ftable, lmname)) != NULL) {
3809 fcc->function_handler = Z_PTR_P(zv);
3810 retval = 1;
3811 if ((fcc->function_handler->op_array.fn_flags & ZEND_ACC_CHANGED) &&
3812 !strict_class) {
3813 scope = get_scope(frame);
3814 if (scope &&
3815 instanceof_function(fcc->function_handler->common.scope, scope)) {
3816
3817 zv = zend_hash_find(&scope->function_table, lmname);
3818 if (zv != NULL) {
3819 zend_function *priv_fbc = Z_PTR_P(zv);
3820
3821 if ((priv_fbc->common.fn_flags & ZEND_ACC_PRIVATE)
3822 && priv_fbc->common.scope == scope) {
3823 fcc->function_handler = priv_fbc;
3824 }
3825 }
3826 }
3827 }
3828 if (!(fcc->function_handler->common.fn_flags & ZEND_ACC_PUBLIC) &&
3829 (fcc->calling_scope &&
3830 ((fcc->object && fcc->calling_scope->__call) ||
3831 (!fcc->object && fcc->calling_scope->__callstatic)))) {
3832 scope = get_scope(frame);
3833 if (fcc->function_handler->common.scope != scope) {
3834 if ((fcc->function_handler->common.fn_flags & ZEND_ACC_PRIVATE)
3835 || !zend_check_protected(zend_get_function_root_class(fcc->function_handler), scope)) {
3836 retval = 0;
3837 fcc->function_handler = NULL;
3838 goto get_function_via_handler;
3839 }
3840 }
3841 }
3842 } else {
3843 get_function_via_handler:
3844 if (fcc->object && fcc->calling_scope == ce_org) {
3845 if (strict_class && ce_org->__call) {
3846 fcc->function_handler = zend_get_call_trampoline_func(ce_org, mname, 0);
3847 call_via_handler = 1;
3848 retval = 1;
3849 } else {
3850 fcc->function_handler = fcc->object->handlers->get_method(&fcc->object, mname, NULL);
3851 if (fcc->function_handler) {
3852 if (strict_class &&
3853 (!fcc->function_handler->common.scope ||
3854 !instanceof_function(ce_org, fcc->function_handler->common.scope))) {
3855 zend_release_fcall_info_cache(fcc);
3856 } else {
3857 retval = 1;
3858 call_via_handler = (fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) != 0;
3859 }
3860 }
3861 }
3862 } else if (fcc->calling_scope) {
3863 if (fcc->calling_scope->get_static_method) {
3864 fcc->function_handler = fcc->calling_scope->get_static_method(fcc->calling_scope, mname);
3865 } else {
3866 fcc->function_handler = zend_std_get_static_method(fcc->calling_scope, mname, NULL);
3867 }
3868 if (fcc->function_handler) {
3869 retval = 1;
3870 call_via_handler = (fcc->function_handler->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) != 0;
3871 if (call_via_handler && !fcc->object) {
3872 zend_object *object = zend_get_this_object(frame);
3873 if (object &&
3874 instanceof_function(object->ce, fcc->calling_scope)) {
3875 fcc->object = object;
3876 }
3877 }
3878 }
3879 }
3880 }
3881
3882 if (retval) {
3883 if (fcc->calling_scope && !call_via_handler) {
3884 if (fcc->function_handler->common.fn_flags & ZEND_ACC_ABSTRACT) {
3885 retval = 0;
3886 if (error) {
3887 zend_spprintf(error, 0, "cannot call abstract method %s::%s()", ZSTR_VAL(fcc->calling_scope->name), ZSTR_VAL(fcc->function_handler->common.function_name));
3888 }
3889 } else if (!fcc->object && !(fcc->function_handler->common.fn_flags & ZEND_ACC_STATIC)) {
3890 retval = 0;
3891 if (error) {
3892 zend_spprintf(error, 0, "non-static method %s::%s() cannot be called statically", ZSTR_VAL(fcc->calling_scope->name), ZSTR_VAL(fcc->function_handler->common.function_name));
3893 }
3894 }
3895 if (retval
3896 && !(fcc->function_handler->common.fn_flags & ZEND_ACC_PUBLIC)) {
3897 scope = get_scope(frame);
3898 if (fcc->function_handler->common.scope != scope) {
3899 if ((fcc->function_handler->common.fn_flags & ZEND_ACC_PRIVATE)
3900 || (!zend_check_protected(zend_get_function_root_class(fcc->function_handler), scope))) {
3901 if (error) {
3902 if (*error) {
3903 efree(*error);
3904 }
3905 zend_spprintf(error, 0, "cannot access %s method %s::%s()", zend_visibility_string(fcc->function_handler->common.fn_flags), ZSTR_VAL(fcc->calling_scope->name), ZSTR_VAL(fcc->function_handler->common.function_name));
3906 }
3907 retval = 0;
3908 }
3909 }
3910 }
3911 }
3912 } else if (error) {
3913 if (fcc->calling_scope) {
3914 zend_spprintf(error, 0, "class %s does not have a method \"%s\"", ZSTR_VAL(fcc->calling_scope->name), ZSTR_VAL(mname));
3915 } else {
3916 zend_spprintf(error, 0, "function %s() does not exist", ZSTR_VAL(mname));
3917 }
3918 }
3919 zend_string_release_ex(lmname, 0);
3920 zend_string_release_ex(mname, 0);
3921
3922 if (fcc->object) {
3923 fcc->called_scope = fcc->object->ce;
3924 if (fcc->function_handler
3925 && (fcc->function_handler->common.fn_flags & ZEND_ACC_STATIC)) {
3926 fcc->object = NULL;
3927 }
3928 }
3929 return retval;
3930 }
3931 /* }}} */
3932
zend_get_callable_name_ex(zval * callable,zend_object * object)3933 ZEND_API zend_string *zend_get_callable_name_ex(zval *callable, zend_object *object) /* {{{ */
3934 {
3935 try_again:
3936 switch (Z_TYPE_P(callable)) {
3937 case IS_STRING:
3938 if (object) {
3939 return zend_create_member_string(object->ce->name, Z_STR_P(callable));
3940 }
3941 return zend_string_copy(Z_STR_P(callable));
3942
3943 case IS_ARRAY:
3944 {
3945 zval *method = NULL;
3946 zval *obj = NULL;
3947
3948 if (zend_hash_num_elements(Z_ARRVAL_P(callable)) == 2) {
3949 obj = zend_hash_index_find_deref(Z_ARRVAL_P(callable), 0);
3950 method = zend_hash_index_find_deref(Z_ARRVAL_P(callable), 1);
3951 }
3952
3953 if (obj == NULL || method == NULL || Z_TYPE_P(method) != IS_STRING) {
3954 return ZSTR_KNOWN(ZEND_STR_ARRAY_CAPITALIZED);
3955 }
3956
3957 if (Z_TYPE_P(obj) == IS_STRING) {
3958 return zend_create_member_string(Z_STR_P(obj), Z_STR_P(method));
3959 } else if (Z_TYPE_P(obj) == IS_OBJECT) {
3960 return zend_create_member_string(Z_OBJCE_P(obj)->name, Z_STR_P(method));
3961 } else {
3962 return ZSTR_KNOWN(ZEND_STR_ARRAY_CAPITALIZED);
3963 }
3964 }
3965 case IS_OBJECT:
3966 {
3967 zend_class_entry *ce = Z_OBJCE_P(callable);
3968 return zend_string_concat2(
3969 ZSTR_VAL(ce->name), ZSTR_LEN(ce->name),
3970 "::__invoke", sizeof("::__invoke") - 1);
3971 }
3972 case IS_REFERENCE:
3973 callable = Z_REFVAL_P(callable);
3974 goto try_again;
3975 default:
3976 return zval_get_string_func(callable);
3977 }
3978 }
3979 /* }}} */
3980
zend_get_callable_name(zval * callable)3981 ZEND_API zend_string *zend_get_callable_name(zval *callable) /* {{{ */
3982 {
3983 return zend_get_callable_name_ex(callable, NULL);
3984 }
3985 /* }}} */
3986
zend_is_callable_at_frame(zval * callable,zend_object * object,zend_execute_data * frame,uint32_t check_flags,zend_fcall_info_cache * fcc,char ** error)3987 ZEND_API bool zend_is_callable_at_frame(
3988 zval *callable, zend_object *object, zend_execute_data *frame,
3989 uint32_t check_flags, zend_fcall_info_cache *fcc, char **error) /* {{{ */
3990 {
3991 bool ret;
3992 zend_fcall_info_cache fcc_local;
3993 bool strict_class = 0;
3994
3995 if (fcc == NULL) {
3996 fcc = &fcc_local;
3997 }
3998 if (error) {
3999 *error = NULL;
4000 }
4001
4002 fcc->calling_scope = NULL;
4003 fcc->called_scope = NULL;
4004 fcc->function_handler = NULL;
4005 fcc->object = NULL;
4006 fcc->closure = NULL;
4007
4008 again:
4009 switch (Z_TYPE_P(callable)) {
4010 case IS_STRING:
4011 if (object) {
4012 fcc->object = object;
4013 fcc->calling_scope = object->ce;
4014 }
4015
4016 if (check_flags & IS_CALLABLE_CHECK_SYNTAX_ONLY) {
4017 fcc->called_scope = fcc->calling_scope;
4018 return 1;
4019 }
4020
4021 check_func:
4022 ret = zend_is_callable_check_func(callable, frame, fcc, strict_class, error, check_flags & IS_CALLABLE_SUPPRESS_DEPRECATIONS);
4023 if (fcc == &fcc_local) {
4024 zend_release_fcall_info_cache(fcc);
4025 }
4026 return ret;
4027
4028 case IS_ARRAY:
4029 {
4030 if (zend_hash_num_elements(Z_ARRVAL_P(callable)) != 2) {
4031 if (error) *error = estrdup("array callback must have exactly two members");
4032 return 0;
4033 }
4034
4035 zval *obj = zend_hash_index_find(Z_ARRVAL_P(callable), 0);
4036 zval *method = zend_hash_index_find(Z_ARRVAL_P(callable), 1);
4037 if (!obj || !method) {
4038 if (error) *error = estrdup("array callback has to contain indices 0 and 1");
4039 return 0;
4040 }
4041
4042 ZVAL_DEREF(obj);
4043 if (Z_TYPE_P(obj) != IS_STRING && Z_TYPE_P(obj) != IS_OBJECT) {
4044 if (error) *error = estrdup("first array member is not a valid class name or object");
4045 return 0;
4046 }
4047
4048 ZVAL_DEREF(method);
4049 if (Z_TYPE_P(method) != IS_STRING) {
4050 if (error) *error = estrdup("second array member is not a valid method");
4051 return 0;
4052 }
4053
4054 if (Z_TYPE_P(obj) == IS_STRING) {
4055 if (check_flags & IS_CALLABLE_CHECK_SYNTAX_ONLY) {
4056 return 1;
4057 }
4058
4059 if (!zend_is_callable_check_class(Z_STR_P(obj), get_scope(frame), frame, fcc, &strict_class, error, check_flags & IS_CALLABLE_SUPPRESS_DEPRECATIONS)) {
4060 return 0;
4061 }
4062 } else {
4063 ZEND_ASSERT(Z_TYPE_P(obj) == IS_OBJECT);
4064 fcc->calling_scope = Z_OBJCE_P(obj); /* TBFixed: what if it's overloaded? */
4065 fcc->object = Z_OBJ_P(obj);
4066
4067 if (check_flags & IS_CALLABLE_CHECK_SYNTAX_ONLY) {
4068 fcc->called_scope = fcc->calling_scope;
4069 return 1;
4070 }
4071 }
4072
4073 callable = method;
4074 goto check_func;
4075 }
4076 return 0;
4077 case IS_OBJECT:
4078 if (Z_OBJ_HANDLER_P(callable, get_closure) && Z_OBJ_HANDLER_P(callable, get_closure)(Z_OBJ_P(callable), &fcc->calling_scope, &fcc->function_handler, &fcc->object, 1) == SUCCESS) {
4079 fcc->called_scope = fcc->calling_scope;
4080 fcc->closure = Z_OBJ_P(callable);
4081 if (fcc == &fcc_local) {
4082 zend_release_fcall_info_cache(fcc);
4083 }
4084 return 1;
4085 }
4086 if (error) *error = estrdup("no array or string given");
4087 return 0;
4088 case IS_REFERENCE:
4089 callable = Z_REFVAL_P(callable);
4090 goto again;
4091 default:
4092 if (error) *error = estrdup("no array or string given");
4093 return 0;
4094 }
4095 }
4096 /* }}} */
4097
zend_is_callable_ex(zval * callable,zend_object * object,uint32_t check_flags,zend_string ** callable_name,zend_fcall_info_cache * fcc,char ** error)4098 ZEND_API bool zend_is_callable_ex(zval *callable, zend_object *object, uint32_t check_flags, zend_string **callable_name, zend_fcall_info_cache *fcc, char **error) /* {{{ */
4099 {
4100 /* Determine callability at the first parent user frame. */
4101 zend_execute_data *frame = EG(current_execute_data);
4102 while (frame && (!frame->func || !ZEND_USER_CODE(frame->func->type))) {
4103 frame = frame->prev_execute_data;
4104 }
4105
4106 bool ret = zend_is_callable_at_frame(callable, object, frame, check_flags, fcc, error);
4107 if (callable_name) {
4108 *callable_name = zend_get_callable_name_ex(callable, object);
4109 }
4110 return ret;
4111 }
4112
zend_is_callable(zval * callable,uint32_t check_flags,zend_string ** callable_name)4113 ZEND_API bool zend_is_callable(zval *callable, uint32_t check_flags, zend_string **callable_name) /* {{{ */
4114 {
4115 return zend_is_callable_ex(callable, NULL, check_flags, callable_name, NULL, NULL);
4116 }
4117 /* }}} */
4118
zend_make_callable(zval * callable,zend_string ** callable_name)4119 ZEND_API bool zend_make_callable(zval *callable, zend_string **callable_name) /* {{{ */
4120 {
4121 zend_fcall_info_cache fcc;
4122
4123 if (zend_is_callable_ex(callable, NULL, IS_CALLABLE_SUPPRESS_DEPRECATIONS, callable_name, &fcc, NULL)) {
4124 if (Z_TYPE_P(callable) == IS_STRING && fcc.calling_scope) {
4125 zval_ptr_dtor_str(callable);
4126 array_init(callable);
4127 add_next_index_str(callable, zend_string_copy(fcc.calling_scope->name));
4128 add_next_index_str(callable, zend_string_copy(fcc.function_handler->common.function_name));
4129 }
4130 zend_release_fcall_info_cache(&fcc);
4131 return 1;
4132 }
4133 return 0;
4134 }
4135 /* }}} */
4136
zend_fcall_info_init(zval * callable,uint32_t check_flags,zend_fcall_info * fci,zend_fcall_info_cache * fcc,zend_string ** callable_name,char ** error)4137 ZEND_API zend_result zend_fcall_info_init(zval *callable, uint32_t check_flags, zend_fcall_info *fci, zend_fcall_info_cache *fcc, zend_string **callable_name, char **error) /* {{{ */
4138 {
4139 if (!zend_is_callable_ex(callable, NULL, check_flags, callable_name, fcc, error)) {
4140 return FAILURE;
4141 }
4142
4143 fci->size = sizeof(*fci);
4144 fci->object = fcc->object;
4145 ZVAL_COPY_VALUE(&fci->function_name, callable);
4146 fci->retval = NULL;
4147 fci->param_count = 0;
4148 fci->params = NULL;
4149 fci->named_params = NULL;
4150
4151 return SUCCESS;
4152 }
4153 /* }}} */
4154
zend_fcall_info_args_clear(zend_fcall_info * fci,bool free_mem)4155 ZEND_API void zend_fcall_info_args_clear(zend_fcall_info *fci, bool free_mem) /* {{{ */
4156 {
4157 if (fci->params) {
4158 zval *p = fci->params;
4159 zval *end = p + fci->param_count;
4160
4161 while (p != end) {
4162 i_zval_ptr_dtor(p);
4163 p++;
4164 }
4165 if (free_mem) {
4166 efree(fci->params);
4167 fci->params = NULL;
4168 }
4169 }
4170 fci->param_count = 0;
4171 }
4172 /* }}} */
4173
zend_fcall_info_args_save(zend_fcall_info * fci,uint32_t * param_count,zval ** params)4174 ZEND_API void zend_fcall_info_args_save(zend_fcall_info *fci, uint32_t *param_count, zval **params) /* {{{ */
4175 {
4176 *param_count = fci->param_count;
4177 *params = fci->params;
4178 fci->param_count = 0;
4179 fci->params = NULL;
4180 }
4181 /* }}} */
4182
zend_fcall_info_args_restore(zend_fcall_info * fci,uint32_t param_count,zval * params)4183 ZEND_API void zend_fcall_info_args_restore(zend_fcall_info *fci, uint32_t param_count, zval *params) /* {{{ */
4184 {
4185 zend_fcall_info_args_clear(fci, 1);
4186 fci->param_count = param_count;
4187 fci->params = params;
4188 }
4189 /* }}} */
4190
zend_fcall_info_args_ex(zend_fcall_info * fci,zend_function * func,zval * args)4191 ZEND_API zend_result zend_fcall_info_args_ex(zend_fcall_info *fci, zend_function *func, zval *args) /* {{{ */
4192 {
4193 zval *arg, *params;
4194 uint32_t n = 1;
4195
4196 zend_fcall_info_args_clear(fci, !args);
4197
4198 if (!args) {
4199 return SUCCESS;
4200 }
4201
4202 if (Z_TYPE_P(args) != IS_ARRAY) {
4203 return FAILURE;
4204 }
4205
4206 fci->param_count = zend_hash_num_elements(Z_ARRVAL_P(args));
4207 fci->params = params = (zval *) erealloc(fci->params, fci->param_count * sizeof(zval));
4208
4209 ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(args), arg) {
4210 if (func && !Z_ISREF_P(arg) && ARG_SHOULD_BE_SENT_BY_REF(func, n)) {
4211 ZVAL_NEW_REF(params, arg);
4212 Z_TRY_ADDREF_P(arg);
4213 } else {
4214 ZVAL_COPY(params, arg);
4215 }
4216 params++;
4217 n++;
4218 } ZEND_HASH_FOREACH_END();
4219
4220 return SUCCESS;
4221 }
4222 /* }}} */
4223
zend_fcall_info_args(zend_fcall_info * fci,zval * args)4224 ZEND_API zend_result zend_fcall_info_args(zend_fcall_info *fci, zval *args) /* {{{ */
4225 {
4226 return zend_fcall_info_args_ex(fci, NULL, args);
4227 }
4228 /* }}} */
4229
zend_fcall_info_argp(zend_fcall_info * fci,uint32_t argc,zval * argv)4230 ZEND_API void zend_fcall_info_argp(zend_fcall_info *fci, uint32_t argc, zval *argv) /* {{{ */
4231 {
4232 zend_fcall_info_args_clear(fci, !argc);
4233
4234 if (argc) {
4235 fci->param_count = argc;
4236 fci->params = (zval *) erealloc(fci->params, fci->param_count * sizeof(zval));
4237
4238 for (uint32_t i = 0; i < argc; ++i) {
4239 ZVAL_COPY(&fci->params[i], &argv[i]);
4240 }
4241 }
4242 }
4243 /* }}} */
4244
zend_fcall_info_argv(zend_fcall_info * fci,uint32_t argc,va_list * argv)4245 ZEND_API void zend_fcall_info_argv(zend_fcall_info *fci, uint32_t argc, va_list *argv) /* {{{ */
4246 {
4247 zend_fcall_info_args_clear(fci, !argc);
4248
4249 if (argc) {
4250 zval *arg;
4251 fci->param_count = argc;
4252 fci->params = (zval *) erealloc(fci->params, fci->param_count * sizeof(zval));
4253
4254 for (uint32_t i = 0; i < argc; ++i) {
4255 arg = va_arg(*argv, zval *);
4256 ZVAL_COPY(&fci->params[i], arg);
4257 }
4258 }
4259 }
4260 /* }}} */
4261
zend_fcall_info_argn(zend_fcall_info * fci,uint32_t argc,...)4262 ZEND_API void zend_fcall_info_argn(zend_fcall_info *fci, uint32_t argc, ...) /* {{{ */
4263 {
4264 va_list argv;
4265
4266 va_start(argv, argc);
4267 zend_fcall_info_argv(fci, argc, &argv);
4268 va_end(argv);
4269 }
4270 /* }}} */
4271
zend_fcall_info_call(zend_fcall_info * fci,zend_fcall_info_cache * fcc,zval * retval_ptr,zval * args)4272 ZEND_API zend_result zend_fcall_info_call(zend_fcall_info *fci, zend_fcall_info_cache *fcc, zval *retval_ptr, zval *args) /* {{{ */
4273 {
4274 zval retval, *org_params = NULL;
4275 uint32_t org_count = 0;
4276 zend_result result;
4277
4278 fci->retval = retval_ptr ? retval_ptr : &retval;
4279 if (args) {
4280 zend_fcall_info_args_save(fci, &org_count, &org_params);
4281 zend_fcall_info_args(fci, args);
4282 }
4283 result = zend_call_function(fci, fcc);
4284
4285 if (!retval_ptr && Z_TYPE(retval) != IS_UNDEF) {
4286 zval_ptr_dtor(&retval);
4287 }
4288 if (args) {
4289 zend_fcall_info_args_restore(fci, org_count, org_params);
4290 }
4291 return result;
4292 }
4293 /* }}} */
4294
zend_get_callable_zval_from_fcc(const zend_fcall_info_cache * fcc,zval * callable)4295 ZEND_API void zend_get_callable_zval_from_fcc(const zend_fcall_info_cache *fcc, zval *callable)
4296 {
4297 if (fcc->closure) {
4298 ZVAL_OBJ_COPY(callable, fcc->closure);
4299 } else if (fcc->function_handler->common.scope) {
4300 array_init(callable);
4301 if (fcc->object) {
4302 GC_ADDREF(fcc->object);
4303 add_next_index_object(callable, fcc->object);
4304 } else {
4305 add_next_index_str(callable, zend_string_copy(fcc->calling_scope->name));
4306 }
4307 add_next_index_str(callable, zend_string_copy(fcc->function_handler->common.function_name));
4308 } else {
4309 ZVAL_STR_COPY(callable, fcc->function_handler->common.function_name);
4310 }
4311 }
4312
zend_get_module_version(const char * module_name)4313 ZEND_API const char *zend_get_module_version(const char *module_name) /* {{{ */
4314 {
4315 zend_string *lname;
4316 size_t name_len = strlen(module_name);
4317 zend_module_entry *module;
4318
4319 lname = zend_string_alloc(name_len, 0);
4320 zend_str_tolower_copy(ZSTR_VAL(lname), module_name, name_len);
4321 module = zend_hash_find_ptr(&module_registry, lname);
4322 zend_string_efree(lname);
4323 return module ? module->version : NULL;
4324 }
4325 /* }}} */
4326
is_persistent_class(zend_class_entry * ce)4327 static zend_always_inline bool is_persistent_class(zend_class_entry *ce) {
4328 return (ce->type & ZEND_INTERNAL_CLASS)
4329 && ce->info.internal.module->type == MODULE_PERSISTENT;
4330 }
4331
zend_declare_typed_property(zend_class_entry * ce,zend_string * name,zval * property,int access_type,zend_string * doc_comment,zend_type type)4332 ZEND_API zend_property_info *zend_declare_typed_property(zend_class_entry *ce, zend_string *name, zval *property, int access_type, zend_string *doc_comment, zend_type type) /* {{{ */
4333 {
4334 zend_property_info *property_info, *property_info_ptr;
4335
4336 if (ZEND_TYPE_IS_SET(type)) {
4337 ce->ce_flags |= ZEND_ACC_HAS_TYPE_HINTS;
4338
4339 if (access_type & ZEND_ACC_READONLY) {
4340 ce->ce_flags |= ZEND_ACC_HAS_READONLY_PROPS;
4341 }
4342 }
4343
4344 if (ce->type == ZEND_INTERNAL_CLASS) {
4345 property_info = pemalloc(sizeof(zend_property_info), 1);
4346 } else {
4347 property_info = zend_arena_alloc(&CG(arena), sizeof(zend_property_info));
4348 if (Z_TYPE_P(property) == IS_CONSTANT_AST) {
4349 ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
4350 if (access_type & ZEND_ACC_STATIC) {
4351 ce->ce_flags |= ZEND_ACC_HAS_AST_STATICS;
4352 } else {
4353 ce->ce_flags |= ZEND_ACC_HAS_AST_PROPERTIES;
4354 }
4355 }
4356 }
4357
4358 if (Z_TYPE_P(property) == IS_STRING && !ZSTR_IS_INTERNED(Z_STR_P(property))) {
4359 zval_make_interned_string(property);
4360 }
4361
4362 if (!(access_type & ZEND_ACC_PPP_MASK)) {
4363 access_type |= ZEND_ACC_PUBLIC;
4364 }
4365 if (access_type & ZEND_ACC_STATIC) {
4366 if ((property_info_ptr = zend_hash_find_ptr(&ce->properties_info, name)) != NULL &&
4367 (property_info_ptr->flags & ZEND_ACC_STATIC) != 0) {
4368 property_info->offset = property_info_ptr->offset;
4369 zval_ptr_dtor(&ce->default_static_members_table[property_info->offset]);
4370 if (property_info_ptr->doc_comment && property_info_ptr->ce == ce) {
4371 zend_string_release(property_info_ptr->doc_comment);
4372 }
4373 zend_hash_del(&ce->properties_info, name);
4374 } else {
4375 property_info->offset = ce->default_static_members_count++;
4376 ce->default_static_members_table = perealloc(ce->default_static_members_table, sizeof(zval) * ce->default_static_members_count, ce->type == ZEND_INTERNAL_CLASS);
4377 }
4378 ZVAL_COPY_VALUE(&ce->default_static_members_table[property_info->offset], property);
4379 if (!ZEND_MAP_PTR(ce->static_members_table)) {
4380 if (ce->type == ZEND_INTERNAL_CLASS &&
4381 ce->info.internal.module->type == MODULE_PERSISTENT) {
4382 ZEND_MAP_PTR_NEW(ce->static_members_table);
4383 }
4384 }
4385 } else {
4386 zval *property_default_ptr;
4387 if ((property_info_ptr = zend_hash_find_ptr(&ce->properties_info, name)) != NULL &&
4388 (property_info_ptr->flags & ZEND_ACC_STATIC) == 0) {
4389 property_info->offset = property_info_ptr->offset;
4390 zval_ptr_dtor(&ce->default_properties_table[OBJ_PROP_TO_NUM(property_info->offset)]);
4391 if (property_info_ptr->doc_comment && property_info_ptr->ce == ce) {
4392 zend_string_release_ex(property_info_ptr->doc_comment, 1);
4393 }
4394 zend_hash_del(&ce->properties_info, name);
4395
4396 ZEND_ASSERT(ce->type == ZEND_INTERNAL_CLASS);
4397 ZEND_ASSERT(ce->properties_info_table != NULL);
4398 ce->properties_info_table[OBJ_PROP_TO_NUM(property_info->offset)] = property_info;
4399 } else {
4400 property_info->offset = OBJ_PROP_TO_OFFSET(ce->default_properties_count);
4401 ce->default_properties_count++;
4402 ce->default_properties_table = perealloc(ce->default_properties_table, sizeof(zval) * ce->default_properties_count, ce->type == ZEND_INTERNAL_CLASS);
4403
4404 /* For user classes this is handled during linking */
4405 if (ce->type == ZEND_INTERNAL_CLASS) {
4406 ce->properties_info_table = perealloc(ce->properties_info_table, sizeof(zend_property_info *) * ce->default_properties_count, 1);
4407 ce->properties_info_table[ce->default_properties_count - 1] = property_info;
4408 }
4409 }
4410 property_default_ptr = &ce->default_properties_table[OBJ_PROP_TO_NUM(property_info->offset)];
4411 ZVAL_COPY_VALUE(property_default_ptr, property);
4412 Z_PROP_FLAG_P(property_default_ptr) = Z_ISUNDEF_P(property) ? IS_PROP_UNINIT : 0;
4413 }
4414 if (ce->type & ZEND_INTERNAL_CLASS) {
4415 /* Must be interned to avoid ZTS data races */
4416 if (is_persistent_class(ce)) {
4417 name = zend_new_interned_string(zend_string_copy(name));
4418 }
4419
4420 if (Z_REFCOUNTED_P(property)) {
4421 zend_error_noreturn(E_CORE_ERROR, "Internal zvals cannot be refcounted");
4422 }
4423 }
4424
4425 if (access_type & ZEND_ACC_PUBLIC) {
4426 property_info->name = zend_string_copy(name);
4427 } else if (access_type & ZEND_ACC_PRIVATE) {
4428 property_info->name = zend_mangle_property_name(ZSTR_VAL(ce->name), ZSTR_LEN(ce->name), ZSTR_VAL(name), ZSTR_LEN(name), is_persistent_class(ce));
4429 } else {
4430 ZEND_ASSERT(access_type & ZEND_ACC_PROTECTED);
4431 property_info->name = zend_mangle_property_name("*", 1, ZSTR_VAL(name), ZSTR_LEN(name), is_persistent_class(ce));
4432 }
4433
4434 property_info->name = zend_new_interned_string(property_info->name);
4435 property_info->flags = access_type;
4436 property_info->doc_comment = doc_comment;
4437 property_info->attributes = NULL;
4438 property_info->ce = ce;
4439 property_info->type = type;
4440
4441 if (is_persistent_class(ce)) {
4442 zend_normalize_internal_type(&property_info->type);
4443 }
4444
4445 zend_hash_update_ptr(&ce->properties_info, name, property_info);
4446
4447 return property_info;
4448 }
4449 /* }}} */
4450
zend_try_assign_typed_ref_ex(zend_reference * ref,zval * val,bool strict)4451 ZEND_API zend_result zend_try_assign_typed_ref_ex(zend_reference *ref, zval *val, bool strict) /* {{{ */
4452 {
4453 if (UNEXPECTED(!zend_verify_ref_assignable_zval(ref, val, strict))) {
4454 zval_ptr_dtor(val);
4455 return FAILURE;
4456 } else {
4457 zval_ptr_dtor(&ref->val);
4458 ZVAL_COPY_VALUE(&ref->val, val);
4459 return SUCCESS;
4460 }
4461 }
4462 /* }}} */
4463
zend_try_assign_typed_ref(zend_reference * ref,zval * val)4464 ZEND_API zend_result zend_try_assign_typed_ref(zend_reference *ref, zval *val) /* {{{ */
4465 {
4466 return zend_try_assign_typed_ref_ex(ref, val, ZEND_ARG_USES_STRICT_TYPES());
4467 }
4468 /* }}} */
4469
zend_try_assign_typed_ref_null(zend_reference * ref)4470 ZEND_API zend_result zend_try_assign_typed_ref_null(zend_reference *ref) /* {{{ */
4471 {
4472 zval tmp;
4473
4474 ZVAL_NULL(&tmp);
4475 return zend_try_assign_typed_ref(ref, &tmp);
4476 }
4477 /* }}} */
4478
zend_try_assign_typed_ref_bool(zend_reference * ref,bool val)4479 ZEND_API zend_result zend_try_assign_typed_ref_bool(zend_reference *ref, bool val) /* {{{ */
4480 {
4481 zval tmp;
4482
4483 ZVAL_BOOL(&tmp, val);
4484 return zend_try_assign_typed_ref(ref, &tmp);
4485 }
4486 /* }}} */
4487
zend_try_assign_typed_ref_long(zend_reference * ref,zend_long lval)4488 ZEND_API zend_result zend_try_assign_typed_ref_long(zend_reference *ref, zend_long lval) /* {{{ */
4489 {
4490 zval tmp;
4491
4492 ZVAL_LONG(&tmp, lval);
4493 return zend_try_assign_typed_ref(ref, &tmp);
4494 }
4495 /* }}} */
4496
zend_try_assign_typed_ref_double(zend_reference * ref,double dval)4497 ZEND_API zend_result zend_try_assign_typed_ref_double(zend_reference *ref, double dval) /* {{{ */
4498 {
4499 zval tmp;
4500
4501 ZVAL_DOUBLE(&tmp, dval);
4502 return zend_try_assign_typed_ref(ref, &tmp);
4503 }
4504 /* }}} */
4505
zend_try_assign_typed_ref_empty_string(zend_reference * ref)4506 ZEND_API zend_result zend_try_assign_typed_ref_empty_string(zend_reference *ref) /* {{{ */
4507 {
4508 zval tmp;
4509
4510 ZVAL_EMPTY_STRING(&tmp);
4511 return zend_try_assign_typed_ref(ref, &tmp);
4512 }
4513 /* }}} */
4514
zend_try_assign_typed_ref_str(zend_reference * ref,zend_string * str)4515 ZEND_API zend_result zend_try_assign_typed_ref_str(zend_reference *ref, zend_string *str) /* {{{ */
4516 {
4517 zval tmp;
4518
4519 ZVAL_STR(&tmp, str);
4520 return zend_try_assign_typed_ref(ref, &tmp);
4521 }
4522 /* }}} */
4523
zend_try_assign_typed_ref_string(zend_reference * ref,const char * string)4524 ZEND_API zend_result zend_try_assign_typed_ref_string(zend_reference *ref, const char *string) /* {{{ */
4525 {
4526 zval tmp;
4527
4528 ZVAL_STRING(&tmp, string);
4529 return zend_try_assign_typed_ref(ref, &tmp);
4530 }
4531 /* }}} */
4532
zend_try_assign_typed_ref_stringl(zend_reference * ref,const char * string,size_t len)4533 ZEND_API zend_result zend_try_assign_typed_ref_stringl(zend_reference *ref, const char *string, size_t len) /* {{{ */
4534 {
4535 zval tmp;
4536
4537 ZVAL_STRINGL(&tmp, string, len);
4538 return zend_try_assign_typed_ref(ref, &tmp);
4539 }
4540 /* }}} */
4541
zend_try_assign_typed_ref_arr(zend_reference * ref,zend_array * arr)4542 ZEND_API zend_result zend_try_assign_typed_ref_arr(zend_reference *ref, zend_array *arr) /* {{{ */
4543 {
4544 zval tmp;
4545
4546 ZVAL_ARR(&tmp, arr);
4547 return zend_try_assign_typed_ref(ref, &tmp);
4548 }
4549 /* }}} */
4550
zend_try_assign_typed_ref_res(zend_reference * ref,zend_resource * res)4551 ZEND_API zend_result zend_try_assign_typed_ref_res(zend_reference *ref, zend_resource *res) /* {{{ */
4552 {
4553 zval tmp;
4554
4555 ZVAL_RES(&tmp, res);
4556 return zend_try_assign_typed_ref(ref, &tmp);
4557 }
4558 /* }}} */
4559
zend_try_assign_typed_ref_zval(zend_reference * ref,zval * zv)4560 ZEND_API zend_result zend_try_assign_typed_ref_zval(zend_reference *ref, zval *zv) /* {{{ */
4561 {
4562 zval tmp;
4563
4564 ZVAL_COPY_VALUE(&tmp, zv);
4565 return zend_try_assign_typed_ref(ref, &tmp);
4566 }
4567 /* }}} */
4568
zend_try_assign_typed_ref_zval_ex(zend_reference * ref,zval * zv,bool strict)4569 ZEND_API zend_result zend_try_assign_typed_ref_zval_ex(zend_reference *ref, zval *zv, bool strict) /* {{{ */
4570 {
4571 zval tmp;
4572
4573 ZVAL_COPY_VALUE(&tmp, zv);
4574 return zend_try_assign_typed_ref_ex(ref, &tmp, strict);
4575 }
4576 /* }}} */
4577
zend_declare_property_ex(zend_class_entry * ce,zend_string * name,zval * property,int access_type,zend_string * doc_comment)4578 ZEND_API void zend_declare_property_ex(zend_class_entry *ce, zend_string *name, zval *property, int access_type, zend_string *doc_comment) /* {{{ */
4579 {
4580 zend_declare_typed_property(ce, name, property, access_type, doc_comment, (zend_type) ZEND_TYPE_INIT_NONE(0));
4581 }
4582 /* }}} */
4583
zend_declare_property(zend_class_entry * ce,const char * name,size_t name_length,zval * property,int access_type)4584 ZEND_API void zend_declare_property(zend_class_entry *ce, const char *name, size_t name_length, zval *property, int access_type) /* {{{ */
4585 {
4586 zend_string *key = zend_string_init(name, name_length, is_persistent_class(ce));
4587 zend_declare_property_ex(ce, key, property, access_type, NULL);
4588 zend_string_release(key);
4589 }
4590 /* }}} */
4591
zend_declare_property_null(zend_class_entry * ce,const char * name,size_t name_length,int access_type)4592 ZEND_API void zend_declare_property_null(zend_class_entry *ce, const char *name, size_t name_length, int access_type) /* {{{ */
4593 {
4594 zval property;
4595
4596 ZVAL_NULL(&property);
4597 zend_declare_property(ce, name, name_length, &property, access_type);
4598 }
4599 /* }}} */
4600
zend_declare_property_bool(zend_class_entry * ce,const char * name,size_t name_length,zend_long value,int access_type)4601 ZEND_API void zend_declare_property_bool(zend_class_entry *ce, const char *name, size_t name_length, zend_long value, int access_type) /* {{{ */
4602 {
4603 zval property;
4604
4605 ZVAL_BOOL(&property, value);
4606 zend_declare_property(ce, name, name_length, &property, access_type);
4607 }
4608 /* }}} */
4609
zend_declare_property_long(zend_class_entry * ce,const char * name,size_t name_length,zend_long value,int access_type)4610 ZEND_API void zend_declare_property_long(zend_class_entry *ce, const char *name, size_t name_length, zend_long value, int access_type) /* {{{ */
4611 {
4612 zval property;
4613
4614 ZVAL_LONG(&property, value);
4615 zend_declare_property(ce, name, name_length, &property, access_type);
4616 }
4617 /* }}} */
4618
zend_declare_property_double(zend_class_entry * ce,const char * name,size_t name_length,double value,int access_type)4619 ZEND_API void zend_declare_property_double(zend_class_entry *ce, const char *name, size_t name_length, double value, int access_type) /* {{{ */
4620 {
4621 zval property;
4622
4623 ZVAL_DOUBLE(&property, value);
4624 zend_declare_property(ce, name, name_length, &property, access_type);
4625 }
4626 /* }}} */
4627
zend_declare_property_string(zend_class_entry * ce,const char * name,size_t name_length,const char * value,int access_type)4628 ZEND_API void zend_declare_property_string(zend_class_entry *ce, const char *name, size_t name_length, const char *value, int access_type) /* {{{ */
4629 {
4630 zval property;
4631
4632 ZVAL_NEW_STR(&property, zend_string_init(value, strlen(value), ce->type & ZEND_INTERNAL_CLASS));
4633 zend_declare_property(ce, name, name_length, &property, access_type);
4634 }
4635 /* }}} */
4636
zend_declare_property_stringl(zend_class_entry * ce,const char * name,size_t name_length,const char * value,size_t value_len,int access_type)4637 ZEND_API void zend_declare_property_stringl(zend_class_entry *ce, const char *name, size_t name_length, const char *value, size_t value_len, int access_type) /* {{{ */
4638 {
4639 zval property;
4640
4641 ZVAL_NEW_STR(&property, zend_string_init(value, value_len, ce->type & ZEND_INTERNAL_CLASS));
4642 zend_declare_property(ce, name, name_length, &property, access_type);
4643 }
4644 /* }}} */
4645
zend_declare_typed_class_constant(zend_class_entry * ce,zend_string * name,zval * value,int flags,zend_string * doc_comment,zend_type type)4646 ZEND_API zend_class_constant *zend_declare_typed_class_constant(zend_class_entry *ce, zend_string *name, zval *value, int flags, zend_string *doc_comment, zend_type type) /* {{{ */
4647 {
4648 zend_class_constant *c;
4649
4650 if (ce->ce_flags & ZEND_ACC_INTERFACE) {
4651 if (!(flags & ZEND_ACC_PUBLIC)) {
4652 zend_error_noreturn(E_COMPILE_ERROR, "Access type for interface constant %s::%s must be public", ZSTR_VAL(ce->name), ZSTR_VAL(name));
4653 }
4654 }
4655
4656 if (zend_string_equals_ci(name, ZSTR_KNOWN(ZEND_STR_CLASS))) {
4657 zend_error_noreturn(ce->type == ZEND_INTERNAL_CLASS ? E_CORE_ERROR : E_COMPILE_ERROR,
4658 "A class constant must not be called 'class'; it is reserved for class name fetching");
4659 }
4660
4661 if (Z_TYPE_P(value) == IS_STRING && !ZSTR_IS_INTERNED(Z_STR_P(value))) {
4662 zval_make_interned_string(value);
4663 }
4664
4665 if (ce->type == ZEND_INTERNAL_CLASS) {
4666 c = pemalloc(sizeof(zend_class_constant), 1);
4667 } else {
4668 c = zend_arena_alloc(&CG(arena), sizeof(zend_class_constant));
4669 }
4670 ZVAL_COPY_VALUE(&c->value, value);
4671 ZEND_CLASS_CONST_FLAGS(c) = flags;
4672 c->doc_comment = doc_comment;
4673 c->attributes = NULL;
4674 c->ce = ce;
4675 c->type = type;
4676
4677 if (Z_TYPE_P(value) == IS_CONSTANT_AST) {
4678 ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
4679 ce->ce_flags |= ZEND_ACC_HAS_AST_CONSTANTS;
4680 if (ce->type == ZEND_INTERNAL_CLASS && !ZEND_MAP_PTR(ce->mutable_data)) {
4681 ZEND_MAP_PTR_NEW(ce->mutable_data);
4682 }
4683 }
4684
4685 if (!zend_hash_add_ptr(&ce->constants_table, name, c)) {
4686 zend_error_noreturn(ce->type == ZEND_INTERNAL_CLASS ? E_CORE_ERROR : E_COMPILE_ERROR,
4687 "Cannot redefine class constant %s::%s", ZSTR_VAL(ce->name), ZSTR_VAL(name));
4688 }
4689
4690 return c;
4691 }
4692
zend_declare_class_constant_ex(zend_class_entry * ce,zend_string * name,zval * value,int flags,zend_string * doc_comment)4693 ZEND_API zend_class_constant *zend_declare_class_constant_ex(zend_class_entry *ce, zend_string *name, zval *value, int flags, zend_string *doc_comment)
4694 {
4695 return zend_declare_typed_class_constant(ce, name, value, flags, doc_comment, (zend_type) ZEND_TYPE_INIT_NONE(0));
4696 }
4697
zend_declare_class_constant(zend_class_entry * ce,const char * name,size_t name_length,zval * value)4698 ZEND_API void zend_declare_class_constant(zend_class_entry *ce, const char *name, size_t name_length, zval *value) /* {{{ */
4699 {
4700 zend_string *key;
4701
4702 if (ce->type == ZEND_INTERNAL_CLASS) {
4703 key = zend_string_init_interned(name, name_length, 1);
4704 } else {
4705 key = zend_string_init(name, name_length, 0);
4706 }
4707 zend_declare_class_constant_ex(ce, key, value, ZEND_ACC_PUBLIC, NULL);
4708 zend_string_release(key);
4709 }
4710 /* }}} */
4711
zend_declare_class_constant_null(zend_class_entry * ce,const char * name,size_t name_length)4712 ZEND_API void zend_declare_class_constant_null(zend_class_entry *ce, const char *name, size_t name_length) /* {{{ */
4713 {
4714 zval constant;
4715
4716 ZVAL_NULL(&constant);
4717 zend_declare_class_constant(ce, name, name_length, &constant);
4718 }
4719 /* }}} */
4720
zend_declare_class_constant_long(zend_class_entry * ce,const char * name,size_t name_length,zend_long value)4721 ZEND_API void zend_declare_class_constant_long(zend_class_entry *ce, const char *name, size_t name_length, zend_long value) /* {{{ */
4722 {
4723 zval constant;
4724
4725 ZVAL_LONG(&constant, value);
4726 zend_declare_class_constant(ce, name, name_length, &constant);
4727 }
4728 /* }}} */
4729
zend_declare_class_constant_bool(zend_class_entry * ce,const char * name,size_t name_length,bool value)4730 ZEND_API void zend_declare_class_constant_bool(zend_class_entry *ce, const char *name, size_t name_length, bool value) /* {{{ */
4731 {
4732 zval constant;
4733
4734 ZVAL_BOOL(&constant, value);
4735 zend_declare_class_constant(ce, name, name_length, &constant);
4736 }
4737 /* }}} */
4738
zend_declare_class_constant_double(zend_class_entry * ce,const char * name,size_t name_length,double value)4739 ZEND_API void zend_declare_class_constant_double(zend_class_entry *ce, const char *name, size_t name_length, double value) /* {{{ */
4740 {
4741 zval constant;
4742
4743 ZVAL_DOUBLE(&constant, value);
4744 zend_declare_class_constant(ce, name, name_length, &constant);
4745 }
4746 /* }}} */
4747
zend_declare_class_constant_stringl(zend_class_entry * ce,const char * name,size_t name_length,const char * value,size_t value_length)4748 ZEND_API void zend_declare_class_constant_stringl(zend_class_entry *ce, const char *name, size_t name_length, const char *value, size_t value_length) /* {{{ */
4749 {
4750 zval constant;
4751
4752 ZVAL_NEW_STR(&constant, zend_string_init(value, value_length, ce->type & ZEND_INTERNAL_CLASS));
4753 zend_declare_class_constant(ce, name, name_length, &constant);
4754 }
4755 /* }}} */
4756
zend_declare_class_constant_string(zend_class_entry * ce,const char * name,size_t name_length,const char * value)4757 ZEND_API void zend_declare_class_constant_string(zend_class_entry *ce, const char *name, size_t name_length, const char *value) /* {{{ */
4758 {
4759 zend_declare_class_constant_stringl(ce, name, name_length, value, strlen(value));
4760 }
4761 /* }}} */
4762
zend_update_property_ex(zend_class_entry * scope,zend_object * object,zend_string * name,zval * value)4763 ZEND_API void zend_update_property_ex(zend_class_entry *scope, zend_object *object, zend_string *name, zval *value) /* {{{ */
4764 {
4765 zend_class_entry *old_scope = EG(fake_scope);
4766
4767 EG(fake_scope) = scope;
4768
4769 object->handlers->write_property(object, name, value, NULL);
4770
4771 EG(fake_scope) = old_scope;
4772 }
4773 /* }}} */
4774
zend_update_property(zend_class_entry * scope,zend_object * object,const char * name,size_t name_length,zval * value)4775 ZEND_API void zend_update_property(zend_class_entry *scope, zend_object *object, const char *name, size_t name_length, zval *value) /* {{{ */
4776 {
4777 zend_string *property;
4778 zend_class_entry *old_scope = EG(fake_scope);
4779
4780 EG(fake_scope) = scope;
4781
4782 property = zend_string_init(name, name_length, 0);
4783 object->handlers->write_property(object, property, value, NULL);
4784 zend_string_release_ex(property, 0);
4785
4786 EG(fake_scope) = old_scope;
4787 }
4788 /* }}} */
4789
zend_update_property_null(zend_class_entry * scope,zend_object * object,const char * name,size_t name_length)4790 ZEND_API void zend_update_property_null(zend_class_entry *scope, zend_object *object, const char *name, size_t name_length) /* {{{ */
4791 {
4792 zval tmp;
4793
4794 ZVAL_NULL(&tmp);
4795 zend_update_property(scope, object, name, name_length, &tmp);
4796 }
4797 /* }}} */
4798
zend_unset_property(zend_class_entry * scope,zend_object * object,const char * name,size_t name_length)4799 ZEND_API void zend_unset_property(zend_class_entry *scope, zend_object *object, const char *name, size_t name_length) /* {{{ */
4800 {
4801 zend_string *property;
4802 zend_class_entry *old_scope = EG(fake_scope);
4803
4804 EG(fake_scope) = scope;
4805
4806 property = zend_string_init(name, name_length, 0);
4807 object->handlers->unset_property(object, property, 0);
4808 zend_string_release_ex(property, 0);
4809
4810 EG(fake_scope) = old_scope;
4811 }
4812 /* }}} */
4813
zend_update_property_bool(zend_class_entry * scope,zend_object * object,const char * name,size_t name_length,zend_long value)4814 ZEND_API void zend_update_property_bool(zend_class_entry *scope, zend_object *object, const char *name, size_t name_length, zend_long value) /* {{{ */
4815 {
4816 zval tmp;
4817
4818 ZVAL_BOOL(&tmp, value);
4819 zend_update_property(scope, object, name, name_length, &tmp);
4820 }
4821 /* }}} */
4822
zend_update_property_long(zend_class_entry * scope,zend_object * object,const char * name,size_t name_length,zend_long value)4823 ZEND_API void zend_update_property_long(zend_class_entry *scope, zend_object *object, const char *name, size_t name_length, zend_long value) /* {{{ */
4824 {
4825 zval tmp;
4826
4827 ZVAL_LONG(&tmp, value);
4828 zend_update_property(scope, object, name, name_length, &tmp);
4829 }
4830 /* }}} */
4831
zend_update_property_double(zend_class_entry * scope,zend_object * object,const char * name,size_t name_length,double value)4832 ZEND_API void zend_update_property_double(zend_class_entry *scope, zend_object *object, const char *name, size_t name_length, double value) /* {{{ */
4833 {
4834 zval tmp;
4835
4836 ZVAL_DOUBLE(&tmp, value);
4837 zend_update_property(scope, object, name, name_length, &tmp);
4838 }
4839 /* }}} */
4840
zend_update_property_str(zend_class_entry * scope,zend_object * object,const char * name,size_t name_length,zend_string * value)4841 ZEND_API void zend_update_property_str(zend_class_entry *scope, zend_object *object, const char *name, size_t name_length, zend_string *value) /* {{{ */
4842 {
4843 zval tmp;
4844
4845 ZVAL_STR(&tmp, value);
4846 zend_update_property(scope, object, name, name_length, &tmp);
4847 }
4848 /* }}} */
4849
zend_update_property_string(zend_class_entry * scope,zend_object * object,const char * name,size_t name_length,const char * value)4850 ZEND_API void zend_update_property_string(zend_class_entry *scope, zend_object *object, const char *name, size_t name_length, const char *value) /* {{{ */
4851 {
4852 zval tmp;
4853
4854 ZVAL_STRING(&tmp, value);
4855 Z_SET_REFCOUNT(tmp, 0);
4856 zend_update_property(scope, object, name, name_length, &tmp);
4857 }
4858 /* }}} */
4859
zend_update_property_stringl(zend_class_entry * scope,zend_object * object,const char * name,size_t name_length,const char * value,size_t value_len)4860 ZEND_API void zend_update_property_stringl(zend_class_entry *scope, zend_object *object, const char *name, size_t name_length, const char *value, size_t value_len) /* {{{ */
4861 {
4862 zval tmp;
4863
4864 ZVAL_STRINGL(&tmp, value, value_len);
4865 Z_SET_REFCOUNT(tmp, 0);
4866 zend_update_property(scope, object, name, name_length, &tmp);
4867 }
4868 /* }}} */
4869
zend_update_static_property_ex(zend_class_entry * scope,zend_string * name,zval * value)4870 ZEND_API zend_result zend_update_static_property_ex(zend_class_entry *scope, zend_string *name, zval *value) /* {{{ */
4871 {
4872 zval *property, tmp;
4873 zend_property_info *prop_info;
4874 zend_class_entry *old_scope = EG(fake_scope);
4875
4876 if (UNEXPECTED(!(scope->ce_flags & ZEND_ACC_CONSTANTS_UPDATED))) {
4877 if (UNEXPECTED(zend_update_class_constants(scope) != SUCCESS)) {
4878 return FAILURE;
4879 }
4880 }
4881
4882 EG(fake_scope) = scope;
4883 property = zend_std_get_static_property_with_info(scope, name, BP_VAR_W, &prop_info);
4884 EG(fake_scope) = old_scope;
4885
4886 if (!property) {
4887 return FAILURE;
4888 }
4889
4890 ZEND_ASSERT(!Z_ISREF_P(value));
4891 Z_TRY_ADDREF_P(value);
4892 if (ZEND_TYPE_IS_SET(prop_info->type)) {
4893 ZVAL_COPY_VALUE(&tmp, value);
4894 if (!zend_verify_property_type(prop_info, &tmp, /* strict */ 0)) {
4895 Z_TRY_DELREF_P(value);
4896 return FAILURE;
4897 }
4898 value = &tmp;
4899 }
4900
4901 zend_assign_to_variable(property, value, IS_TMP_VAR, /* strict */ 0);
4902 return SUCCESS;
4903 }
4904 /* }}} */
4905
zend_update_static_property(zend_class_entry * scope,const char * name,size_t name_length,zval * value)4906 ZEND_API zend_result zend_update_static_property(zend_class_entry *scope, const char *name, size_t name_length, zval *value) /* {{{ */
4907 {
4908 zend_string *key = zend_string_init(name, name_length, 0);
4909 zend_result retval = zend_update_static_property_ex(scope, key, value);
4910 zend_string_efree(key);
4911 return retval;
4912 }
4913 /* }}} */
4914
zend_update_static_property_null(zend_class_entry * scope,const char * name,size_t name_length)4915 ZEND_API zend_result zend_update_static_property_null(zend_class_entry *scope, const char *name, size_t name_length) /* {{{ */
4916 {
4917 zval tmp;
4918
4919 ZVAL_NULL(&tmp);
4920 return zend_update_static_property(scope, name, name_length, &tmp);
4921 }
4922 /* }}} */
4923
zend_update_static_property_bool(zend_class_entry * scope,const char * name,size_t name_length,zend_long value)4924 ZEND_API zend_result zend_update_static_property_bool(zend_class_entry *scope, const char *name, size_t name_length, zend_long value) /* {{{ */
4925 {
4926 zval tmp;
4927
4928 ZVAL_BOOL(&tmp, value);
4929 return zend_update_static_property(scope, name, name_length, &tmp);
4930 }
4931 /* }}} */
4932
zend_update_static_property_long(zend_class_entry * scope,const char * name,size_t name_length,zend_long value)4933 ZEND_API zend_result zend_update_static_property_long(zend_class_entry *scope, const char *name, size_t name_length, zend_long value) /* {{{ */
4934 {
4935 zval tmp;
4936
4937 ZVAL_LONG(&tmp, value);
4938 return zend_update_static_property(scope, name, name_length, &tmp);
4939 }
4940 /* }}} */
4941
zend_update_static_property_double(zend_class_entry * scope,const char * name,size_t name_length,double value)4942 ZEND_API zend_result zend_update_static_property_double(zend_class_entry *scope, const char *name, size_t name_length, double value) /* {{{ */
4943 {
4944 zval tmp;
4945
4946 ZVAL_DOUBLE(&tmp, value);
4947 return zend_update_static_property(scope, name, name_length, &tmp);
4948 }
4949 /* }}} */
4950
zend_update_static_property_string(zend_class_entry * scope,const char * name,size_t name_length,const char * value)4951 ZEND_API zend_result zend_update_static_property_string(zend_class_entry *scope, const char *name, size_t name_length, const char *value) /* {{{ */
4952 {
4953 zval tmp;
4954
4955 ZVAL_STRING(&tmp, value);
4956 Z_SET_REFCOUNT(tmp, 0);
4957 return zend_update_static_property(scope, name, name_length, &tmp);
4958 }
4959 /* }}} */
4960
zend_update_static_property_stringl(zend_class_entry * scope,const char * name,size_t name_length,const char * value,size_t value_len)4961 ZEND_API zend_result zend_update_static_property_stringl(zend_class_entry *scope, const char *name, size_t name_length, const char *value, size_t value_len) /* {{{ */
4962 {
4963 zval tmp;
4964
4965 ZVAL_STRINGL(&tmp, value, value_len);
4966 Z_SET_REFCOUNT(tmp, 0);
4967 return zend_update_static_property(scope, name, name_length, &tmp);
4968 }
4969 /* }}} */
4970
zend_read_property_ex(zend_class_entry * scope,zend_object * object,zend_string * name,bool silent,zval * rv)4971 ZEND_API zval *zend_read_property_ex(zend_class_entry *scope, zend_object *object, zend_string *name, bool silent, zval *rv) /* {{{ */
4972 {
4973 zval *value;
4974 zend_class_entry *old_scope = EG(fake_scope);
4975
4976 EG(fake_scope) = scope;
4977
4978 value = object->handlers->read_property(object, name, silent?BP_VAR_IS:BP_VAR_R, NULL, rv);
4979
4980 EG(fake_scope) = old_scope;
4981 return value;
4982 }
4983 /* }}} */
4984
zend_read_property(zend_class_entry * scope,zend_object * object,const char * name,size_t name_length,bool silent,zval * rv)4985 ZEND_API zval *zend_read_property(zend_class_entry *scope, zend_object *object, const char *name, size_t name_length, bool silent, zval *rv) /* {{{ */
4986 {
4987 zval *value;
4988 zend_string *str;
4989
4990 str = zend_string_init(name, name_length, 0);
4991 value = zend_read_property_ex(scope, object, str, silent, rv);
4992 zend_string_release_ex(str, 0);
4993 return value;
4994 }
4995 /* }}} */
4996
zend_read_static_property_ex(zend_class_entry * scope,zend_string * name,bool silent)4997 ZEND_API zval *zend_read_static_property_ex(zend_class_entry *scope, zend_string *name, bool silent) /* {{{ */
4998 {
4999 zval *property;
5000 zend_class_entry *old_scope = EG(fake_scope);
5001
5002 EG(fake_scope) = scope;
5003 property = zend_std_get_static_property(scope, name, silent ? BP_VAR_IS : BP_VAR_R);
5004 EG(fake_scope) = old_scope;
5005
5006 return property;
5007 }
5008 /* }}} */
5009
zend_read_static_property(zend_class_entry * scope,const char * name,size_t name_length,bool silent)5010 ZEND_API zval *zend_read_static_property(zend_class_entry *scope, const char *name, size_t name_length, bool silent) /* {{{ */
5011 {
5012 zend_string *key = zend_string_init(name, name_length, 0);
5013 zval *property = zend_read_static_property_ex(scope, key, silent);
5014 zend_string_efree(key);
5015 return property;
5016 }
5017 /* }}} */
5018
zend_save_error_handling(zend_error_handling * current)5019 ZEND_API void zend_save_error_handling(zend_error_handling *current) /* {{{ */
5020 {
5021 current->handling = EG(error_handling);
5022 current->exception = EG(exception_class);
5023 }
5024 /* }}} */
5025
zend_replace_error_handling(zend_error_handling_t error_handling,zend_class_entry * exception_class,zend_error_handling * current)5026 ZEND_API void zend_replace_error_handling(zend_error_handling_t error_handling, zend_class_entry *exception_class, zend_error_handling *current) /* {{{ */
5027 {
5028 if (current) {
5029 zend_save_error_handling(current);
5030 }
5031 ZEND_ASSERT(error_handling == EH_THROW || exception_class == NULL);
5032 EG(error_handling) = error_handling;
5033 EG(exception_class) = exception_class;
5034 }
5035 /* }}} */
5036
zend_restore_error_handling(zend_error_handling * saved)5037 ZEND_API void zend_restore_error_handling(zend_error_handling *saved) /* {{{ */
5038 {
5039 EG(error_handling) = saved->handling;
5040 EG(exception_class) = saved->exception;
5041 }
5042 /* }}} */
5043
zend_get_object_type_case(const zend_class_entry * ce,bool upper_case)5044 ZEND_API ZEND_COLD const char *zend_get_object_type_case(const zend_class_entry *ce, bool upper_case) /* {{{ */
5045 {
5046 if (ce->ce_flags & ZEND_ACC_TRAIT) {
5047 return upper_case ? "Trait" : "trait";
5048 } else if (ce->ce_flags & ZEND_ACC_INTERFACE) {
5049 return upper_case ? "Interface" : "interface";
5050 } else if (ce->ce_flags & ZEND_ACC_ENUM) {
5051 return upper_case ? "Enum" : "enum";
5052 } else {
5053 return upper_case ? "Class" : "class";
5054 }
5055 }
5056 /* }}} */
5057
zend_is_iterable(const zval * iterable)5058 ZEND_API bool zend_is_iterable(const zval *iterable) /* {{{ */
5059 {
5060 switch (Z_TYPE_P(iterable)) {
5061 case IS_ARRAY:
5062 return 1;
5063 case IS_OBJECT:
5064 return zend_class_implements_interface(Z_OBJCE_P(iterable), zend_ce_traversable);
5065 default:
5066 return 0;
5067 }
5068 }
5069 /* }}} */
5070
zend_is_countable(const zval * countable)5071 ZEND_API bool zend_is_countable(const zval *countable) /* {{{ */
5072 {
5073 switch (Z_TYPE_P(countable)) {
5074 case IS_ARRAY:
5075 return 1;
5076 case IS_OBJECT:
5077 if (Z_OBJ_HT_P(countable)->count_elements) {
5078 return 1;
5079 }
5080
5081 return zend_class_implements_interface(Z_OBJCE_P(countable), zend_ce_countable);
5082 default:
5083 return 0;
5084 }
5085 }
5086 /* }}} */
5087
get_default_via_ast(zval * default_value_zval,const char * default_value)5088 static zend_result get_default_via_ast(zval *default_value_zval, const char *default_value) {
5089 zend_ast *ast;
5090 zend_arena *ast_arena;
5091
5092 zend_string *code = zend_string_concat3(
5093 "<?php ", sizeof("<?php ") - 1, default_value, strlen(default_value), ";", 1);
5094
5095 ast = zend_compile_string_to_ast(code, &ast_arena, ZSTR_EMPTY_ALLOC());
5096 zend_string_release(code);
5097
5098 if (!ast) {
5099 return FAILURE;
5100 }
5101
5102 zend_ast_list *statement_list = zend_ast_get_list(ast);
5103 zend_ast **const_expr_ast_ptr = &statement_list->child[0];
5104
5105 zend_arena *original_ast_arena = CG(ast_arena);
5106 uint32_t original_compiler_options = CG(compiler_options);
5107 zend_file_context original_file_context;
5108 CG(ast_arena) = ast_arena;
5109 /* Disable constant substitution, to make getDefaultValueConstant() work. */
5110 CG(compiler_options) |= ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION | ZEND_COMPILE_NO_PERSISTENT_CONSTANT_SUBSTITUTION;
5111 zend_file_context_begin(&original_file_context);
5112 zend_const_expr_to_zval(default_value_zval, const_expr_ast_ptr, /* allow_dynamic */ true);
5113 CG(ast_arena) = original_ast_arena;
5114 CG(compiler_options) = original_compiler_options;
5115 zend_file_context_end(&original_file_context);
5116
5117 zend_ast_destroy(ast);
5118 zend_arena_destroy(ast_arena);
5119
5120 return SUCCESS;
5121 }
5122
try_parse_string(const char * str,size_t len,char quote)5123 static zend_string *try_parse_string(const char *str, size_t len, char quote) {
5124 if (len == 0) {
5125 return ZSTR_EMPTY_ALLOC();
5126 }
5127
5128 for (size_t i = 0; i < len; i++) {
5129 if (str[i] == '\\' || str[i] == quote) {
5130 return NULL;
5131 }
5132 }
5133 return zend_string_init(str, len, 0);
5134 }
5135
zend_get_default_from_internal_arg_info(zval * default_value_zval,zend_internal_arg_info * arg_info)5136 ZEND_API zend_result zend_get_default_from_internal_arg_info(
5137 zval *default_value_zval, zend_internal_arg_info *arg_info)
5138 {
5139 const char *default_value = arg_info->default_value;
5140 if (!default_value) {
5141 return FAILURE;
5142 }
5143
5144 /* Avoid going through the full AST machinery for some simple and common cases. */
5145 size_t default_value_len = strlen(default_value);
5146 zend_ulong lval;
5147 if (default_value_len == sizeof("null")-1
5148 && !memcmp(default_value, "null", sizeof("null")-1)) {
5149 ZVAL_NULL(default_value_zval);
5150 return SUCCESS;
5151 } else if (default_value_len == sizeof("true")-1
5152 && !memcmp(default_value, "true", sizeof("true")-1)) {
5153 ZVAL_TRUE(default_value_zval);
5154 return SUCCESS;
5155 } else if (default_value_len == sizeof("false")-1
5156 && !memcmp(default_value, "false", sizeof("false")-1)) {
5157 ZVAL_FALSE(default_value_zval);
5158 return SUCCESS;
5159 } else if (default_value_len >= 2
5160 && (default_value[0] == '\'' || default_value[0] == '"')
5161 && default_value[default_value_len - 1] == default_value[0]) {
5162 zend_string *str = try_parse_string(
5163 default_value + 1, default_value_len - 2, default_value[0]);
5164 if (str) {
5165 ZVAL_STR(default_value_zval, str);
5166 return SUCCESS;
5167 }
5168 } else if (default_value_len == sizeof("[]")-1
5169 && !memcmp(default_value, "[]", sizeof("[]")-1)) {
5170 ZVAL_EMPTY_ARRAY(default_value_zval);
5171 return SUCCESS;
5172 } else if (ZEND_HANDLE_NUMERIC_STR(default_value, default_value_len, lval)) {
5173 ZVAL_LONG(default_value_zval, lval);
5174 return SUCCESS;
5175 }
5176
5177 #if 0
5178 fprintf(stderr, "Evaluating %s via AST\n", default_value);
5179 #endif
5180 return get_default_via_ast(default_value_zval, default_value);
5181 }
5182