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