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