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