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