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