xref: /PHP-8.2/Zend/zend_builtin_functions.c (revision 706bcdbc)
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    +----------------------------------------------------------------------+
18 */
19 
20 #include "zend.h"
21 #include "zend_API.h"
22 #include "zend_attributes.h"
23 #include "zend_gc.h"
24 #include "zend_builtin_functions.h"
25 #include "zend_constants.h"
26 #include "zend_ini.h"
27 #include "zend_interfaces.h"
28 #include "zend_exceptions.h"
29 #include "zend_extensions.h"
30 #include "zend_closures.h"
31 #include "zend_generators.h"
32 #include "zend_builtin_functions_arginfo.h"
33 #include "zend_smart_str.h"
34 
35 /* }}} */
36 
ZEND_MINIT_FUNCTION(core)37 ZEND_MINIT_FUNCTION(core) { /* {{{ */
38 	zend_register_default_classes();
39 
40 	zend_standard_class_def = register_class_stdClass();
41 
42 	return SUCCESS;
43 }
44 /* }}} */
45 
46 zend_module_entry zend_builtin_module = { /* {{{ */
47 	STANDARD_MODULE_HEADER,
48 	"Core",
49 	ext_functions,
50 	ZEND_MINIT(core),
51 	NULL,
52 	NULL,
53 	NULL,
54 	NULL,
55 	ZEND_VERSION,
56 	STANDARD_MODULE_PROPERTIES
57 };
58 /* }}} */
59 
zend_startup_builtin_functions(void)60 zend_result zend_startup_builtin_functions(void) /* {{{ */
61 {
62 	zend_builtin_module.module_number = 0;
63 	zend_builtin_module.type = MODULE_PERSISTENT;
64 	return (EG(current_module) = zend_register_module_ex(&zend_builtin_module)) == NULL ? FAILURE : SUCCESS;
65 }
66 /* }}} */
67 
68 /* {{{ Get the version of the Zend Engine */
ZEND_FUNCTION(zend_version)69 ZEND_FUNCTION(zend_version)
70 {
71 	ZEND_PARSE_PARAMETERS_NONE();
72 
73 	RETURN_STRINGL(ZEND_VERSION, sizeof(ZEND_VERSION)-1);
74 }
75 /* }}} */
76 
77 /* {{{ Reclaims memory used by MM caches.
78    Returns number of freed bytes */
ZEND_FUNCTION(gc_mem_caches)79 ZEND_FUNCTION(gc_mem_caches)
80 {
81 	ZEND_PARSE_PARAMETERS_NONE();
82 
83 	RETURN_LONG(zend_mm_gc(zend_mm_get_heap()));
84 }
85 /* }}} */
86 
87 /* {{{ Forces collection of any existing garbage cycles.
88    Returns number of freed zvals */
ZEND_FUNCTION(gc_collect_cycles)89 ZEND_FUNCTION(gc_collect_cycles)
90 {
91 	ZEND_PARSE_PARAMETERS_NONE();
92 
93 	RETURN_LONG(gc_collect_cycles());
94 }
95 /* }}} */
96 
97 /* {{{ Returns status of the circular reference collector */
ZEND_FUNCTION(gc_enabled)98 ZEND_FUNCTION(gc_enabled)
99 {
100 	ZEND_PARSE_PARAMETERS_NONE();
101 
102 	RETURN_BOOL(gc_enabled());
103 }
104 /* }}} */
105 
106 /* {{{ Activates the circular reference collector */
ZEND_FUNCTION(gc_enable)107 ZEND_FUNCTION(gc_enable)
108 {
109 	zend_string *key;
110 
111 	ZEND_PARSE_PARAMETERS_NONE();
112 
113 	key = zend_string_init("zend.enable_gc", sizeof("zend.enable_gc")-1, 0);
114 	zend_alter_ini_entry_chars(key, "1", sizeof("1")-1, ZEND_INI_USER, ZEND_INI_STAGE_RUNTIME);
115 	zend_string_release_ex(key, 0);
116 }
117 /* }}} */
118 
119 /* {{{ Deactivates the circular reference collector */
ZEND_FUNCTION(gc_disable)120 ZEND_FUNCTION(gc_disable)
121 {
122 	zend_string *key;
123 
124 	ZEND_PARSE_PARAMETERS_NONE();
125 
126 	key = zend_string_init("zend.enable_gc", sizeof("zend.enable_gc")-1, 0);
127 	zend_alter_ini_entry_chars(key, "0", sizeof("0")-1, ZEND_INI_USER, ZEND_INI_STAGE_RUNTIME);
128 	zend_string_release_ex(key, 0);
129 }
130 /* }}} */
131 
132 /* {{{ Returns current GC statistics */
ZEND_FUNCTION(gc_status)133 ZEND_FUNCTION(gc_status)
134 {
135 	zend_gc_status status;
136 
137 	ZEND_PARSE_PARAMETERS_NONE();
138 
139 	zend_gc_get_status(&status);
140 
141 	array_init_size(return_value, 3);
142 
143 	add_assoc_long_ex(return_value, "runs", sizeof("runs")-1, (long)status.runs);
144 	add_assoc_long_ex(return_value, "collected", sizeof("collected")-1, (long)status.collected);
145 	add_assoc_long_ex(return_value, "threshold", sizeof("threshold")-1, (long)status.threshold);
146 	add_assoc_long_ex(return_value, "roots", sizeof("roots")-1, (long)status.num_roots);
147 }
148 /* }}} */
149 
150 /* {{{ Get the number of arguments that were passed to the function */
ZEND_FUNCTION(func_num_args)151 ZEND_FUNCTION(func_num_args)
152 {
153 	zend_execute_data *ex = EX(prev_execute_data);
154 
155 	ZEND_PARSE_PARAMETERS_NONE();
156 
157 	if (ex && (ZEND_CALL_INFO(ex) & ZEND_CALL_CODE)) {
158 		zend_throw_error(NULL, "func_num_args() must be called from a function context");
159 		RETURN_THROWS();
160 	}
161 
162 	if (zend_forbid_dynamic_call() == FAILURE) {
163 		RETURN_LONG(-1);
164 	}
165 
166 	RETURN_LONG(ZEND_CALL_NUM_ARGS(ex));
167 }
168 /* }}} */
169 
170 /* {{{ Get the $arg_num'th argument that was passed to the function */
ZEND_FUNCTION(func_get_arg)171 ZEND_FUNCTION(func_get_arg)
172 {
173 	uint32_t arg_count, first_extra_arg;
174 	zval *arg;
175 	zend_long requested_offset;
176 	zend_execute_data *ex;
177 
178 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &requested_offset) == FAILURE) {
179 		RETURN_THROWS();
180 	}
181 
182 	if (requested_offset < 0) {
183 		zend_argument_value_error(1, "must be greater than or equal to 0");
184 		RETURN_THROWS();
185 	}
186 
187 	ex = EX(prev_execute_data);
188 	if (ex && (ZEND_CALL_INFO(ex) & ZEND_CALL_CODE)) {
189 		zend_throw_error(NULL, "func_get_arg() cannot be called from the global scope");
190 		RETURN_THROWS();
191 	}
192 
193 	if (zend_forbid_dynamic_call() == FAILURE) {
194 		RETURN_THROWS();
195 	}
196 
197 	arg_count = ZEND_CALL_NUM_ARGS(ex);
198 
199 	if ((zend_ulong)requested_offset >= arg_count) {
200 		zend_argument_value_error(1, "must be less than the number of the arguments passed to the currently executed function");
201 		RETURN_THROWS();
202 	}
203 
204 	first_extra_arg = ex->func->op_array.num_args;
205 	if ((zend_ulong)requested_offset >= first_extra_arg && (ZEND_CALL_NUM_ARGS(ex) > first_extra_arg)) {
206 		arg = ZEND_CALL_VAR_NUM(ex, ex->func->op_array.last_var + ex->func->op_array.T) + (requested_offset - first_extra_arg);
207 	} else {
208 		arg = ZEND_CALL_ARG(ex, requested_offset + 1);
209 	}
210 	if (EXPECTED(!Z_ISUNDEF_P(arg))) {
211 		RETURN_COPY_DEREF(arg);
212 	}
213 }
214 /* }}} */
215 
216 /* {{{ Get an array of the arguments that were passed to the function */
ZEND_FUNCTION(func_get_args)217 ZEND_FUNCTION(func_get_args)
218 {
219 	zval *p, *q;
220 	uint32_t arg_count, first_extra_arg;
221 	uint32_t i;
222 	zend_execute_data *ex = EX(prev_execute_data);
223 
224 	ZEND_PARSE_PARAMETERS_NONE();
225 
226 	if (ex && (ZEND_CALL_INFO(ex) & ZEND_CALL_CODE)) {
227 		zend_throw_error(NULL, "func_get_args() cannot be called from the global scope");
228 		RETURN_THROWS();
229 	}
230 
231 	if (zend_forbid_dynamic_call() == FAILURE) {
232 		RETURN_THROWS();
233 	}
234 
235 	arg_count = ZEND_CALL_NUM_ARGS(ex);
236 
237 	if (arg_count) {
238 		array_init_size(return_value, arg_count);
239 		first_extra_arg = ex->func->op_array.num_args;
240 		zend_hash_real_init_packed(Z_ARRVAL_P(return_value));
241 		ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
242 			i = 0;
243 			p = ZEND_CALL_ARG(ex, 1);
244 			if (arg_count > first_extra_arg) {
245 				while (i < first_extra_arg) {
246 					q = p;
247 					if (EXPECTED(Z_TYPE_INFO_P(q) != IS_UNDEF)) {
248 						ZVAL_DEREF(q);
249 						if (Z_OPT_REFCOUNTED_P(q)) {
250 							Z_ADDREF_P(q);
251 						}
252 						ZEND_HASH_FILL_SET(q);
253 					} else {
254 						ZEND_HASH_FILL_SET_NULL();
255 					}
256 					ZEND_HASH_FILL_NEXT();
257 					p++;
258 					i++;
259 				}
260 				p = ZEND_CALL_VAR_NUM(ex, ex->func->op_array.last_var + ex->func->op_array.T);
261 			}
262 			while (i < arg_count) {
263 				q = p;
264 				if (EXPECTED(Z_TYPE_INFO_P(q) != IS_UNDEF)) {
265 					ZVAL_DEREF(q);
266 					if (Z_OPT_REFCOUNTED_P(q)) {
267 						Z_ADDREF_P(q);
268 					}
269 					ZEND_HASH_FILL_SET(q);
270 				} else {
271 					ZEND_HASH_FILL_SET_NULL();
272 				}
273 				ZEND_HASH_FILL_NEXT();
274 				p++;
275 				i++;
276 			}
277 		} ZEND_HASH_FILL_END();
278 		Z_ARRVAL_P(return_value)->nNumOfElements = arg_count;
279 	} else {
280 		RETURN_EMPTY_ARRAY();
281 	}
282 }
283 /* }}} */
284 
285 /* {{{ Get string length
286    Warning: This function is special-cased by zend_compile.c and so is usually bypassed */
ZEND_FUNCTION(strlen)287 ZEND_FUNCTION(strlen)
288 {
289 	zend_string *s;
290 
291 	ZEND_PARSE_PARAMETERS_START(1, 1)
292 		Z_PARAM_STR(s)
293 	ZEND_PARSE_PARAMETERS_END();
294 
295 	RETVAL_LONG(ZSTR_LEN(s));
296 }
297 /* }}} */
298 
299 /* {{{ Binary safe string comparison */
ZEND_FUNCTION(strcmp)300 ZEND_FUNCTION(strcmp)
301 {
302 	zend_string *s1, *s2;
303 
304 	ZEND_PARSE_PARAMETERS_START(2, 2)
305 		Z_PARAM_STR(s1)
306 		Z_PARAM_STR(s2)
307 	ZEND_PARSE_PARAMETERS_END();
308 
309 	RETURN_LONG(zend_binary_strcmp(ZSTR_VAL(s1), ZSTR_LEN(s1), ZSTR_VAL(s2), ZSTR_LEN(s2)));
310 }
311 /* }}} */
312 
313 /* {{{ Binary safe string comparison */
ZEND_FUNCTION(strncmp)314 ZEND_FUNCTION(strncmp)
315 {
316 	zend_string *s1, *s2;
317 	zend_long len;
318 
319 	ZEND_PARSE_PARAMETERS_START(3, 3)
320 		Z_PARAM_STR(s1)
321 		Z_PARAM_STR(s2)
322 		Z_PARAM_LONG(len)
323 	ZEND_PARSE_PARAMETERS_END();
324 
325 	if (len < 0) {
326 		zend_argument_value_error(3, "must be greater than or equal to 0");
327 		RETURN_THROWS();
328 	}
329 
330 	RETURN_LONG(zend_binary_strncmp(ZSTR_VAL(s1), ZSTR_LEN(s1), ZSTR_VAL(s2), ZSTR_LEN(s2), len));
331 }
332 /* }}} */
333 
334 /* {{{ Binary safe case-insensitive string comparison */
ZEND_FUNCTION(strcasecmp)335 ZEND_FUNCTION(strcasecmp)
336 {
337 	zend_string *s1, *s2;
338 
339 	ZEND_PARSE_PARAMETERS_START(2, 2)
340 		Z_PARAM_STR(s1)
341 		Z_PARAM_STR(s2)
342 	ZEND_PARSE_PARAMETERS_END();
343 
344 	RETURN_LONG(zend_binary_strcasecmp(ZSTR_VAL(s1), ZSTR_LEN(s1), ZSTR_VAL(s2), ZSTR_LEN(s2)));
345 }
346 /* }}} */
347 
348 /* {{{ Binary safe string comparison */
ZEND_FUNCTION(strncasecmp)349 ZEND_FUNCTION(strncasecmp)
350 {
351 	zend_string *s1, *s2;
352 	zend_long len;
353 
354 	ZEND_PARSE_PARAMETERS_START(3, 3)
355 		Z_PARAM_STR(s1)
356 		Z_PARAM_STR(s2)
357 		Z_PARAM_LONG(len)
358 	ZEND_PARSE_PARAMETERS_END();
359 
360 	if (len < 0) {
361 		zend_argument_value_error(3, "must be greater than or equal to 0");
362 		RETURN_THROWS();
363 	}
364 
365 	RETURN_LONG(zend_binary_strncasecmp(ZSTR_VAL(s1), ZSTR_LEN(s1), ZSTR_VAL(s2), ZSTR_LEN(s2), len));
366 }
367 /* }}} */
368 
369 /* {{{ Return the current error_reporting level, and if an argument was passed - change to the new level */
ZEND_FUNCTION(error_reporting)370 ZEND_FUNCTION(error_reporting)
371 {
372 	zend_long err;
373 	bool err_is_null = 1;
374 	int old_error_reporting;
375 
376 	ZEND_PARSE_PARAMETERS_START(0, 1)
377 		Z_PARAM_OPTIONAL
378 		Z_PARAM_LONG_OR_NULL(err, err_is_null)
379 	ZEND_PARSE_PARAMETERS_END();
380 
381 	old_error_reporting = EG(error_reporting);
382 
383 	if (!err_is_null && err != old_error_reporting) {
384 		zend_ini_entry *p = EG(error_reporting_ini_entry);
385 
386 		if (!p) {
387 			zval *zv = zend_hash_find_known_hash(EG(ini_directives), ZSTR_KNOWN(ZEND_STR_ERROR_REPORTING));
388 			if (!zv) {
389 				/* Ini setting does not exist -- can this happen? */
390 				RETURN_LONG(old_error_reporting);
391 			}
392 
393 			p = EG(error_reporting_ini_entry) = (zend_ini_entry*)Z_PTR_P(zv);
394 		}
395 		if (!p->modified) {
396 			if (!EG(modified_ini_directives)) {
397 				ALLOC_HASHTABLE(EG(modified_ini_directives));
398 				zend_hash_init(EG(modified_ini_directives), 8, NULL, NULL, 0);
399 			}
400 			if (EXPECTED(zend_hash_add_ptr(EG(modified_ini_directives), ZSTR_KNOWN(ZEND_STR_ERROR_REPORTING), p) != NULL)) {
401 				p->orig_value = p->value;
402 				p->orig_modifiable = p->modifiable;
403 				p->modified = 1;
404 			}
405 		} else if (p->orig_value != p->value) {
406 			zend_string_release_ex(p->value, 0);
407 		}
408 
409 		p->value = zend_long_to_str(err);
410 		EG(error_reporting) = err;
411 	}
412 
413 	RETURN_LONG(old_error_reporting);
414 }
415 /* }}} */
416 
validate_constant_array_argument(HashTable * ht,int argument_number)417 static bool validate_constant_array_argument(HashTable *ht, int argument_number) /* {{{ */
418 {
419 	bool ret = 1;
420 	zval *val;
421 
422 	GC_PROTECT_RECURSION(ht);
423 	ZEND_HASH_FOREACH_VAL(ht, val) {
424 		ZVAL_DEREF(val);
425 		if (Z_TYPE_P(val) == IS_ARRAY && Z_REFCOUNTED_P(val)) {
426 			if (Z_IS_RECURSIVE_P(val)) {
427 				zend_argument_value_error(argument_number, "cannot be a recursive array");
428 				ret = 0;
429 				break;
430 			} else if (!validate_constant_array_argument(Z_ARRVAL_P(val), argument_number)) {
431 				ret = 0;
432 				break;
433 			}
434 		}
435 	} ZEND_HASH_FOREACH_END();
436 	GC_UNPROTECT_RECURSION(ht);
437 	return ret;
438 }
439 /* }}} */
440 
copy_constant_array(zval * dst,zval * src)441 static void copy_constant_array(zval *dst, zval *src) /* {{{ */
442 {
443 	zend_string *key;
444 	zend_ulong idx;
445 	zval *new_val, *val;
446 
447 	array_init_size(dst, zend_hash_num_elements(Z_ARRVAL_P(src)));
448 	ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(src), idx, key, val) {
449 		/* constant arrays can't contain references */
450 		ZVAL_DEREF(val);
451 		if (key) {
452 			new_val = zend_hash_add_new(Z_ARRVAL_P(dst), key, val);
453 		} else {
454 			new_val = zend_hash_index_add_new(Z_ARRVAL_P(dst), idx, val);
455 		}
456 		if (Z_TYPE_P(val) == IS_ARRAY) {
457 			if (Z_REFCOUNTED_P(val)) {
458 				copy_constant_array(new_val, val);
459 			}
460 		} else {
461 			Z_TRY_ADDREF_P(val);
462 		}
463 	} ZEND_HASH_FOREACH_END();
464 }
465 /* }}} */
466 
467 /* {{{ Define a new constant */
ZEND_FUNCTION(define)468 ZEND_FUNCTION(define)
469 {
470 	zend_string *name;
471 	zval *val, val_free;
472 	bool non_cs = 0;
473 	zend_constant c;
474 
475 	ZEND_PARSE_PARAMETERS_START(2, 3)
476 		Z_PARAM_STR(name)
477 		Z_PARAM_ZVAL(val)
478 		Z_PARAM_OPTIONAL
479 		Z_PARAM_BOOL(non_cs)
480 	ZEND_PARSE_PARAMETERS_END();
481 
482 	if (zend_memnstr(ZSTR_VAL(name), "::", sizeof("::") - 1, ZSTR_VAL(name) + ZSTR_LEN(name))) {
483 		zend_argument_value_error(1, "cannot be a class constant");
484 		RETURN_THROWS();
485 	}
486 
487 	if (non_cs) {
488 		zend_error(E_WARNING, "define(): Argument #3 ($case_insensitive) is ignored since declaration of case-insensitive constants is no longer supported");
489 	}
490 
491 	ZVAL_UNDEF(&val_free);
492 
493 	if (Z_TYPE_P(val) == IS_ARRAY) {
494 		if (Z_REFCOUNTED_P(val)) {
495 			if (!validate_constant_array_argument(Z_ARRVAL_P(val), 2)) {
496 				RETURN_THROWS();
497 			} else {
498 				copy_constant_array(&c.value, val);
499 				goto register_constant;
500 			}
501 		}
502 	}
503 
504 	ZVAL_COPY(&c.value, val);
505 	zval_ptr_dtor(&val_free);
506 
507 register_constant:
508 	/* non persistent */
509 	ZEND_CONSTANT_SET_FLAGS(&c, CONST_CS, PHP_USER_CONSTANT);
510 	c.name = zend_string_copy(name);
511 	if (zend_register_constant(&c) == SUCCESS) {
512 		RETURN_TRUE;
513 	} else {
514 		RETURN_FALSE;
515 	}
516 }
517 /* }}} */
518 
519 /* {{{ Check whether a constant exists
520    Warning: This function is special-cased by zend_compile.c and so is usually bypassed */
ZEND_FUNCTION(defined)521 ZEND_FUNCTION(defined)
522 {
523 	zend_string *name;
524 
525 	ZEND_PARSE_PARAMETERS_START(1, 1)
526 		Z_PARAM_STR(name)
527 	ZEND_PARSE_PARAMETERS_END();
528 
529 	if (zend_get_constant_ex(name, zend_get_executed_scope(), ZEND_FETCH_CLASS_SILENT)) {
530 		RETURN_TRUE;
531 	} else {
532 		RETURN_FALSE;
533 	}
534 }
535 /* }}} */
536 
537 /* {{{ Retrieves the class name */
ZEND_FUNCTION(get_class)538 ZEND_FUNCTION(get_class)
539 {
540 	zval *obj = NULL;
541 
542 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|o", &obj) == FAILURE) {
543 		RETURN_THROWS();
544 	}
545 
546 	if (!obj) {
547 		zend_class_entry *scope = zend_get_executed_scope();
548 
549 		if (scope) {
550 			RETURN_STR_COPY(scope->name);
551 		} else {
552 			zend_throw_error(NULL, "get_class() without arguments must be called from within a class");
553 			RETURN_THROWS();
554 		}
555 	}
556 
557 	RETURN_STR_COPY(Z_OBJCE_P(obj)->name);
558 }
559 /* }}} */
560 
561 /* {{{ Retrieves the "Late Static Binding" class name */
ZEND_FUNCTION(get_called_class)562 ZEND_FUNCTION(get_called_class)
563 {
564 	zend_class_entry *called_scope;
565 
566 	ZEND_PARSE_PARAMETERS_NONE();
567 
568 	called_scope = zend_get_called_scope(execute_data);
569 	if (!called_scope) {
570 		zend_throw_error(NULL, "get_called_class() must be called from within a class");
571 		RETURN_THROWS();
572 	}
573 
574 	RETURN_STR_COPY(called_scope->name);
575 }
576 /* }}} */
577 
578 /* {{{ Retrieves the parent class name for object or class or current scope or false if not in a scope. */
ZEND_FUNCTION(get_parent_class)579 ZEND_FUNCTION(get_parent_class)
580 {
581 	zend_class_entry *ce = NULL;
582 
583 	ZEND_PARSE_PARAMETERS_START(0, 1)
584 		Z_PARAM_OPTIONAL
585 		Z_PARAM_OBJ_OR_CLASS_NAME(ce)
586 	ZEND_PARSE_PARAMETERS_END();
587 
588 	if (!ce) {
589 		ce = zend_get_executed_scope();
590 	}
591 
592 	if (ce && ce->parent) {
593 		RETURN_STR_COPY(ce->parent->name);
594 	} else {
595 		RETURN_FALSE;
596 	}
597 }
598 /* }}} */
599 
is_a_impl(INTERNAL_FUNCTION_PARAMETERS,bool only_subclass)600 static void is_a_impl(INTERNAL_FUNCTION_PARAMETERS, bool only_subclass) /* {{{ */
601 {
602 	zval *obj;
603 	zend_string *class_name;
604 	zend_class_entry *instance_ce;
605 	zend_class_entry *ce;
606 	bool allow_string = only_subclass;
607 	bool retval;
608 
609 	ZEND_PARSE_PARAMETERS_START(2, 3)
610 		Z_PARAM_ZVAL(obj)
611 		Z_PARAM_STR(class_name)
612 		Z_PARAM_OPTIONAL
613 		Z_PARAM_BOOL(allow_string)
614 	ZEND_PARSE_PARAMETERS_END();
615 	/*
616 	 * allow_string - is_a default is no, is_subclass_of is yes.
617 	 *   if it's allowed, then the autoloader will be called if the class does not exist.
618 	 *   default behaviour is different, as 'is_a' used to be used to test mixed return values
619 	 *   and there is no easy way to deprecate this.
620 	 */
621 
622 	if (allow_string && Z_TYPE_P(obj) == IS_STRING) {
623 		instance_ce = zend_lookup_class(Z_STR_P(obj));
624 		if (!instance_ce) {
625 			RETURN_FALSE;
626 		}
627 	} else if (Z_TYPE_P(obj) == IS_OBJECT) {
628 		instance_ce = Z_OBJCE_P(obj);
629 	} else {
630 		RETURN_FALSE;
631 	}
632 
633 	if (!only_subclass && EXPECTED(zend_string_equals(instance_ce->name, class_name))) {
634 		retval = 1;
635 	} else {
636 		ce = zend_lookup_class_ex(class_name, NULL, ZEND_FETCH_CLASS_NO_AUTOLOAD);
637 		if (!ce) {
638 			retval = 0;
639 		} else {
640 			if (only_subclass && instance_ce == ce) {
641 				retval = 0;
642 			} else {
643 				retval = instanceof_function(instance_ce, ce);
644 			}
645 		}
646 	}
647 
648 	RETURN_BOOL(retval);
649 }
650 /* }}} */
651 
652 /* {{{ Returns true if the object has this class as one of its parents */
ZEND_FUNCTION(is_subclass_of)653 ZEND_FUNCTION(is_subclass_of)
654 {
655 	is_a_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
656 }
657 /* }}} */
658 
659 /* {{{ Returns true if the first argument is an object and is this class or has this class as one of its parents, */
ZEND_FUNCTION(is_a)660 ZEND_FUNCTION(is_a)
661 {
662 	is_a_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
663 }
664 /* }}} */
665 
666 /* {{{ add_class_vars */
add_class_vars(zend_class_entry * scope,zend_class_entry * ce,bool statics,zval * return_value)667 static void add_class_vars(zend_class_entry *scope, zend_class_entry *ce, bool statics, zval *return_value)
668 {
669 	zend_property_info *prop_info;
670 	zval *prop, prop_copy;
671 	zend_string *key;
672 	zval *default_properties_table = CE_DEFAULT_PROPERTIES_TABLE(ce);
673 
674 	ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&ce->properties_info, key, prop_info) {
675 		if (((prop_info->flags & ZEND_ACC_PROTECTED) &&
676 			 !zend_check_protected(prop_info->ce, scope)) ||
677 			((prop_info->flags & ZEND_ACC_PRIVATE) &&
678 			  prop_info->ce != scope)) {
679 			continue;
680 		}
681 		prop = NULL;
682 		if (statics && (prop_info->flags & ZEND_ACC_STATIC) != 0) {
683 			prop = &ce->default_static_members_table[prop_info->offset];
684 			ZVAL_DEINDIRECT(prop);
685 		} else if (!statics && (prop_info->flags & ZEND_ACC_STATIC) == 0) {
686 			prop = &default_properties_table[OBJ_PROP_TO_NUM(prop_info->offset)];
687 		}
688 		if (!prop) {
689 			continue;
690 		}
691 
692 		if (Z_ISUNDEF_P(prop)) {
693 			/* Return uninitialized typed properties as a null value */
694 			ZVAL_NULL(&prop_copy);
695 		} else {
696 			/* copy: enforce read only access */
697 			ZVAL_COPY_OR_DUP(&prop_copy, prop);
698 		}
699 		prop = &prop_copy;
700 
701 		/* this is necessary to make it able to work with default array
702 		 * properties, returned to user */
703 		if (Z_OPT_TYPE_P(prop) == IS_CONSTANT_AST) {
704 			if (UNEXPECTED(zval_update_constant_ex(prop, ce) != SUCCESS)) {
705 				return;
706 			}
707 		}
708 
709 		zend_hash_add_new(Z_ARRVAL_P(return_value), key, prop);
710 	} ZEND_HASH_FOREACH_END();
711 }
712 /* }}} */
713 
714 /* {{{ Returns an array of default properties of the class. */
ZEND_FUNCTION(get_class_vars)715 ZEND_FUNCTION(get_class_vars)
716 {
717 	zend_class_entry *ce = NULL, *scope;
718 
719 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "C", &ce) == FAILURE) {
720 		RETURN_THROWS();
721 	}
722 
723 	array_init(return_value);
724 	if (UNEXPECTED(!(ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED))) {
725 		if (UNEXPECTED(zend_update_class_constants(ce) != SUCCESS)) {
726 			return;
727 		}
728 	}
729 
730 	scope = zend_get_executed_scope();
731 	add_class_vars(scope, ce, 0, return_value);
732 	add_class_vars(scope, ce, 1, return_value);
733 }
734 /* }}} */
735 
736 /* {{{ Returns an array of object properties */
ZEND_FUNCTION(get_object_vars)737 ZEND_FUNCTION(get_object_vars)
738 {
739 	zval *value;
740 	HashTable *properties;
741 	zend_string *key;
742 	zend_object *zobj;
743 	zend_ulong num_key;
744 
745 	ZEND_PARSE_PARAMETERS_START(1, 1)
746 		Z_PARAM_OBJ(zobj)
747 	ZEND_PARSE_PARAMETERS_END();
748 
749 	properties = zobj->handlers->get_properties(zobj);
750 	if (properties == NULL) {
751 		RETURN_EMPTY_ARRAY();
752 	}
753 
754 	if (!zobj->ce->default_properties_count && properties == zobj->properties && !GC_IS_RECURSIVE(properties)) {
755 		/* fast copy */
756 		if (EXPECTED(zobj->handlers == &std_object_handlers)) {
757 			RETURN_ARR(zend_proptable_to_symtable(properties, 0));
758 		}
759 		RETURN_ARR(zend_proptable_to_symtable(properties, 1));
760 	} else {
761 		array_init_size(return_value, zend_hash_num_elements(properties));
762 
763 		ZEND_HASH_FOREACH_KEY_VAL(properties, num_key, key, value) {
764 			bool is_dynamic = 1;
765 			if (Z_TYPE_P(value) == IS_INDIRECT) {
766 				value = Z_INDIRECT_P(value);
767 				if (UNEXPECTED(Z_ISUNDEF_P(value))) {
768 					continue;
769 				}
770 
771 				is_dynamic = 0;
772 			}
773 
774 			if (key && zend_check_property_access(zobj, key, is_dynamic) == FAILURE) {
775 				continue;
776 			}
777 
778 			if (Z_ISREF_P(value) && Z_REFCOUNT_P(value) == 1) {
779 				value = Z_REFVAL_P(value);
780 			}
781 			Z_TRY_ADDREF_P(value);
782 
783 			if (UNEXPECTED(!key)) {
784 				/* This case is only possible due to loopholes, e.g. ArrayObject */
785 				zend_hash_index_add(Z_ARRVAL_P(return_value), num_key, value);
786 			} else if (!is_dynamic && ZSTR_VAL(key)[0] == 0) {
787 				const char *prop_name, *class_name;
788 				size_t prop_len;
789 				zend_unmangle_property_name_ex(key, &class_name, &prop_name, &prop_len);
790 				/* We assume here that a mangled property name is never
791 				 * numeric. This is probably a safe assumption, but
792 				 * theoretically someone might write an extension with
793 				 * private, numeric properties. Well, too bad.
794 				 */
795 				zend_hash_str_add_new(Z_ARRVAL_P(return_value), prop_name, prop_len, value);
796 			} else {
797 				zend_symtable_add_new(Z_ARRVAL_P(return_value), key, value);
798 			}
799 		} ZEND_HASH_FOREACH_END();
800 	}
801 }
802 /* }}} */
803 
804 /* {{{ Returns an array of mangled object properties. Does not respect property visibility. */
ZEND_FUNCTION(get_mangled_object_vars)805 ZEND_FUNCTION(get_mangled_object_vars)
806 {
807 	zend_object *obj;
808 	HashTable *properties;
809 
810 	ZEND_PARSE_PARAMETERS_START(1, 1)
811 		Z_PARAM_OBJ(obj)
812 	ZEND_PARSE_PARAMETERS_END();
813 
814 	properties = obj->handlers->get_properties(obj);
815 	if (!properties) {
816 		ZVAL_EMPTY_ARRAY(return_value);
817 		return;
818 	}
819 
820 	properties = zend_proptable_to_symtable(properties,
821 		(obj->ce->default_properties_count ||
822 		 obj->handlers != &std_object_handlers ||
823 		 GC_IS_RECURSIVE(properties)));
824 	RETURN_ARR(properties);
825 }
826 /* }}} */
827 
828 /* {{{ Returns an array of method names for class or class instance. */
ZEND_FUNCTION(get_class_methods)829 ZEND_FUNCTION(get_class_methods)
830 {
831 	zval method_name;
832 	zend_class_entry *ce = NULL;
833 	zend_class_entry *scope;
834 	zend_function *mptr;
835 
836 	ZEND_PARSE_PARAMETERS_START(1, 1)
837 		Z_PARAM_OBJ_OR_CLASS_NAME(ce)
838 	ZEND_PARSE_PARAMETERS_END();
839 
840 	array_init(return_value);
841 	scope = zend_get_executed_scope();
842 
843 	ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, mptr) {
844 		if ((mptr->common.fn_flags & ZEND_ACC_PUBLIC)
845 		 || (scope &&
846 			 (((mptr->common.fn_flags & ZEND_ACC_PROTECTED) &&
847 			   zend_check_protected(mptr->common.scope, scope))
848 		   || ((mptr->common.fn_flags & ZEND_ACC_PRIVATE) &&
849 			   scope == mptr->common.scope)))
850 		) {
851 			ZVAL_STR_COPY(&method_name, mptr->common.function_name);
852 			zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &method_name);
853 		}
854 	} ZEND_HASH_FOREACH_END();
855 }
856 /* }}} */
857 
858 /* {{{ Checks if the class method exists */
ZEND_FUNCTION(method_exists)859 ZEND_FUNCTION(method_exists)
860 {
861 	zval *klass;
862 	zend_string *method_name;
863 	zend_string *lcname;
864 	zend_class_entry *ce;
865 	zend_function *func;
866 
867 	ZEND_PARSE_PARAMETERS_START(2, 2)
868 		Z_PARAM_ZVAL(klass)
869 		Z_PARAM_STR(method_name)
870 	ZEND_PARSE_PARAMETERS_END();
871 
872 	if (Z_TYPE_P(klass) == IS_OBJECT) {
873 		ce = Z_OBJCE_P(klass);
874 	} else if (Z_TYPE_P(klass) == IS_STRING) {
875 		if ((ce = zend_lookup_class(Z_STR_P(klass))) == NULL) {
876 			RETURN_FALSE;
877 		}
878 	} else {
879 		zend_argument_type_error(1, "must be of type object|string, %s given", zend_zval_type_name(klass));
880 		RETURN_THROWS();
881 	}
882 
883 	lcname = zend_string_tolower(method_name);
884 	func = zend_hash_find_ptr(&ce->function_table, lcname);
885 	zend_string_release_ex(lcname, 0);
886 
887 	if (func) {
888 		/* Exclude shadow properties when checking a method on a specific class. Include
889 		 * them when checking an object, as method_exists() generally ignores visibility.
890 		 * TODO: Should we use EG(scope) for the object case instead? */
891 		RETURN_BOOL(Z_TYPE_P(klass) == IS_OBJECT
892 			|| !(func->common.fn_flags & ZEND_ACC_PRIVATE) || func->common.scope == ce);
893 	}
894 
895 	if (Z_TYPE_P(klass) == IS_OBJECT) {
896 		zend_object *obj = Z_OBJ_P(klass);
897 		func = Z_OBJ_HT_P(klass)->get_method(&obj, method_name, NULL);
898 		if (func != NULL) {
899 			if (func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) {
900 				/* Returns true for the fake Closure's __invoke */
901 				RETVAL_BOOL(func->common.scope == zend_ce_closure
902 					&& zend_string_equals_literal_ci(method_name, ZEND_INVOKE_FUNC_NAME));
903 
904 				zend_string_release_ex(func->common.function_name, 0);
905 				zend_free_trampoline(func);
906 				return;
907 			}
908 			RETURN_TRUE;
909 		}
910 	} else {
911 	    /* Returns true for fake Closure::__invoke */
912 	    if (ce == zend_ce_closure
913 	        && zend_string_equals_literal_ci(method_name, ZEND_INVOKE_FUNC_NAME)) {
914 	        RETURN_TRUE;
915 	    }
916 	}
917 	RETURN_FALSE;
918 }
919 /* }}} */
920 
921 /* {{{ Checks if the object or class has a property */
ZEND_FUNCTION(property_exists)922 ZEND_FUNCTION(property_exists)
923 {
924 	zval *object;
925 	zend_string *property;
926 	zend_class_entry *ce;
927 	zend_property_info *property_info;
928 
929 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "zS", &object, &property) == FAILURE) {
930 		RETURN_THROWS();
931 	}
932 
933 	if (Z_TYPE_P(object) == IS_STRING) {
934 		ce = zend_lookup_class(Z_STR_P(object));
935 		if (!ce) {
936 			RETURN_FALSE;
937 		}
938 	} else if (Z_TYPE_P(object) == IS_OBJECT) {
939 		ce = Z_OBJCE_P(object);
940 	} else {
941 		zend_argument_type_error(1, "must be of type object|string, %s given", zend_zval_type_name(object));
942 		RETURN_THROWS();
943 	}
944 
945 	property_info = zend_hash_find_ptr(&ce->properties_info, property);
946 	if (property_info != NULL
947 	 && (!(property_info->flags & ZEND_ACC_PRIVATE)
948 	  || property_info->ce == ce)) {
949 		RETURN_TRUE;
950 	}
951 
952 	if (Z_TYPE_P(object) ==  IS_OBJECT &&
953 		Z_OBJ_HANDLER_P(object, has_property)(Z_OBJ_P(object), property, 2, NULL)) {
954 		RETURN_TRUE;
955 	}
956 	RETURN_FALSE;
957 }
958 /* }}} */
959 
class_exists_impl(INTERNAL_FUNCTION_PARAMETERS,int flags,int skip_flags)960 static inline void class_exists_impl(INTERNAL_FUNCTION_PARAMETERS, int flags, int skip_flags) /* {{{ */
961 {
962 	zend_string *name;
963 	zend_string *lcname;
964 	zend_class_entry *ce;
965 	bool autoload = 1;
966 
967 	ZEND_PARSE_PARAMETERS_START(1, 2)
968 		Z_PARAM_STR(name)
969 		Z_PARAM_OPTIONAL
970 		Z_PARAM_BOOL(autoload)
971 	ZEND_PARSE_PARAMETERS_END();
972 
973 	if (ZSTR_HAS_CE_CACHE(name)) {
974 		ce = ZSTR_GET_CE_CACHE(name);
975 		if (ce) {
976 			RETURN_BOOL(((ce->ce_flags & flags) == flags) && !(ce->ce_flags & skip_flags));
977 		}
978 	}
979 
980 	if (!autoload) {
981 		if (ZSTR_VAL(name)[0] == '\\') {
982 			/* Ignore leading "\" */
983 			lcname = zend_string_alloc(ZSTR_LEN(name) - 1, 0);
984 			zend_str_tolower_copy(ZSTR_VAL(lcname), ZSTR_VAL(name) + 1, ZSTR_LEN(name) - 1);
985 		} else {
986 			lcname = zend_string_tolower(name);
987 		}
988 
989 		ce = zend_hash_find_ptr(EG(class_table), lcname);
990 		zend_string_release_ex(lcname, 0);
991 	} else {
992 		ce = zend_lookup_class(name);
993 	}
994 
995 	if (ce) {
996 		RETURN_BOOL(((ce->ce_flags & flags) == flags) && !(ce->ce_flags & skip_flags));
997 	} else {
998 		RETURN_FALSE;
999 	}
1000 }
1001 /* {{{ */
1002 
1003 /* {{{ Checks if the class exists */
ZEND_FUNCTION(class_exists)1004 ZEND_FUNCTION(class_exists)
1005 {
1006 	class_exists_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_LINKED, ZEND_ACC_INTERFACE | ZEND_ACC_TRAIT);
1007 }
1008 /* }}} */
1009 
1010 /* {{{ Checks if the class exists */
ZEND_FUNCTION(interface_exists)1011 ZEND_FUNCTION(interface_exists)
1012 {
1013 	class_exists_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_LINKED|ZEND_ACC_INTERFACE, 0);
1014 }
1015 /* }}} */
1016 
1017 /* {{{ Checks if the trait exists */
ZEND_FUNCTION(trait_exists)1018 ZEND_FUNCTION(trait_exists)
1019 {
1020 	class_exists_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_TRAIT, 0);
1021 }
1022 /* }}} */
1023 
ZEND_FUNCTION(enum_exists)1024 ZEND_FUNCTION(enum_exists)
1025 {
1026 	class_exists_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_ENUM, 0);
1027 }
1028 
1029 /* {{{ Checks if the function exists */
ZEND_FUNCTION(function_exists)1030 ZEND_FUNCTION(function_exists)
1031 {
1032 	zend_string *name;
1033 	bool exists;
1034 	zend_string *lcname;
1035 
1036 	ZEND_PARSE_PARAMETERS_START(1, 1)
1037 		Z_PARAM_STR(name)
1038 	ZEND_PARSE_PARAMETERS_END();
1039 
1040 	if (ZSTR_VAL(name)[0] == '\\') {
1041 		/* Ignore leading "\" */
1042 		lcname = zend_string_alloc(ZSTR_LEN(name) - 1, 0);
1043 		zend_str_tolower_copy(ZSTR_VAL(lcname), ZSTR_VAL(name) + 1, ZSTR_LEN(name) - 1);
1044 	} else {
1045 		lcname = zend_string_tolower(name);
1046 	}
1047 
1048 	exists = zend_hash_exists(EG(function_table), lcname);
1049 	zend_string_release_ex(lcname, 0);
1050 
1051 	RETURN_BOOL(exists);
1052 }
1053 /* }}} */
1054 
1055 /* {{{ Creates an alias for user defined class */
ZEND_FUNCTION(class_alias)1056 ZEND_FUNCTION(class_alias)
1057 {
1058 	zend_string *class_name;
1059 	zend_string *alias_name;
1060 	zend_class_entry *ce;
1061 	bool autoload = 1;
1062 
1063 	ZEND_PARSE_PARAMETERS_START(2, 3)
1064 		Z_PARAM_STR(class_name)
1065 		Z_PARAM_STR(alias_name)
1066 		Z_PARAM_OPTIONAL
1067 		Z_PARAM_BOOL(autoload)
1068 	ZEND_PARSE_PARAMETERS_END();
1069 
1070 	ce = zend_lookup_class_ex(class_name, NULL, !autoload ? ZEND_FETCH_CLASS_NO_AUTOLOAD : 0);
1071 
1072 	if (ce) {
1073 		if (ce->type == ZEND_USER_CLASS) {
1074 			if (zend_register_class_alias_ex(ZSTR_VAL(alias_name), ZSTR_LEN(alias_name), ce, 0) == SUCCESS) {
1075 				RETURN_TRUE;
1076 			} else {
1077 				zend_error(E_WARNING, "Cannot declare %s %s, because the name is already in use", zend_get_object_type(ce), ZSTR_VAL(alias_name));
1078 				RETURN_FALSE;
1079 			}
1080 		} else {
1081 			zend_argument_value_error(1, "must be a user-defined class name, internal class name given");
1082 			RETURN_THROWS();
1083 		}
1084 	} else {
1085 		zend_error(E_WARNING, "Class \"%s\" not found", ZSTR_VAL(class_name));
1086 		RETURN_FALSE;
1087 	}
1088 }
1089 /* }}} */
1090 
1091 /* {{{ Returns an array with the file names that were include_once()'d */
ZEND_FUNCTION(get_included_files)1092 ZEND_FUNCTION(get_included_files)
1093 {
1094 	zend_string *entry;
1095 
1096 	ZEND_PARSE_PARAMETERS_NONE();
1097 
1098 	array_init(return_value);
1099 	ZEND_HASH_MAP_FOREACH_STR_KEY(&EG(included_files), entry) {
1100 		if (entry) {
1101 			add_next_index_str(return_value, zend_string_copy(entry));
1102 		}
1103 	} ZEND_HASH_FOREACH_END();
1104 }
1105 /* }}} */
1106 
1107 /* {{{ Generates a user-level error/warning/notice message */
ZEND_FUNCTION(trigger_error)1108 ZEND_FUNCTION(trigger_error)
1109 {
1110 	zend_long error_type = E_USER_NOTICE;
1111 	zend_string *message;
1112 
1113 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|l", &message, &error_type) == FAILURE) {
1114 		RETURN_THROWS();
1115 	}
1116 
1117 	switch (error_type) {
1118 		case E_USER_ERROR:
1119 		case E_USER_WARNING:
1120 		case E_USER_NOTICE:
1121 		case E_USER_DEPRECATED:
1122 			break;
1123 		default:
1124 			zend_argument_value_error(2, "must be one of E_USER_ERROR, E_USER_WARNING, E_USER_NOTICE,"
1125 				" or E_USER_DEPRECATED");
1126 			RETURN_THROWS();
1127 			break;
1128 	}
1129 
1130 	zend_error_zstr_at(error_type, zend_get_executed_filename_ex(), zend_get_executed_lineno(), message);
1131 	// TODO Change to void
1132 	RETURN_TRUE;
1133 }
1134 /* }}} */
1135 
1136 /* {{{ Sets a user-defined error handler function.  Returns the previously defined error handler, or false on error */
ZEND_FUNCTION(set_error_handler)1137 ZEND_FUNCTION(set_error_handler)
1138 {
1139 	zend_fcall_info fci;
1140 	zend_fcall_info_cache fcc;
1141 	zend_long error_type = E_ALL;
1142 
1143 	ZEND_PARSE_PARAMETERS_START(1, 2)
1144 		Z_PARAM_FUNC_OR_NULL(fci, fcc)
1145 		Z_PARAM_OPTIONAL
1146 		Z_PARAM_LONG(error_type)
1147 	ZEND_PARSE_PARAMETERS_END();
1148 
1149 	if (Z_TYPE(EG(user_error_handler)) != IS_UNDEF) {
1150 		ZVAL_COPY(return_value, &EG(user_error_handler));
1151 	}
1152 
1153 	zend_stack_push(&EG(user_error_handlers_error_reporting), &EG(user_error_handler_error_reporting));
1154 	zend_stack_push(&EG(user_error_handlers), &EG(user_error_handler));
1155 
1156 	if (!ZEND_FCI_INITIALIZED(fci)) { /* unset user-defined handler */
1157 		ZVAL_UNDEF(&EG(user_error_handler));
1158 		return;
1159 	}
1160 
1161 	ZVAL_COPY(&EG(user_error_handler), &(fci.function_name));
1162 	EG(user_error_handler_error_reporting) = (int)error_type;
1163 }
1164 /* }}} */
1165 
1166 /* {{{ Restores the previously defined error handler function */
ZEND_FUNCTION(restore_error_handler)1167 ZEND_FUNCTION(restore_error_handler)
1168 {
1169 	ZEND_PARSE_PARAMETERS_NONE();
1170 
1171 	if (Z_TYPE(EG(user_error_handler)) != IS_UNDEF) {
1172 		zval zeh;
1173 
1174 		ZVAL_COPY_VALUE(&zeh, &EG(user_error_handler));
1175 		ZVAL_UNDEF(&EG(user_error_handler));
1176 		zval_ptr_dtor(&zeh);
1177 	}
1178 
1179 	if (zend_stack_is_empty(&EG(user_error_handlers))) {
1180 		ZVAL_UNDEF(&EG(user_error_handler));
1181 	} else {
1182 		zval *tmp;
1183 		EG(user_error_handler_error_reporting) = zend_stack_int_top(&EG(user_error_handlers_error_reporting));
1184 		zend_stack_del_top(&EG(user_error_handlers_error_reporting));
1185 		tmp = zend_stack_top(&EG(user_error_handlers));
1186 		ZVAL_COPY_VALUE(&EG(user_error_handler), tmp);
1187 		zend_stack_del_top(&EG(user_error_handlers));
1188 	}
1189 
1190 	// TODO Change to void
1191 	RETURN_TRUE;
1192 }
1193 /* }}} */
1194 
1195 /* {{{ Sets a user-defined exception handler function. Returns the previously defined exception handler, or false on error */
ZEND_FUNCTION(set_exception_handler)1196 ZEND_FUNCTION(set_exception_handler)
1197 {
1198 	zend_fcall_info fci;
1199 	zend_fcall_info_cache fcc;
1200 
1201 	ZEND_PARSE_PARAMETERS_START(1, 1)
1202 		Z_PARAM_FUNC_OR_NULL(fci, fcc)
1203 	ZEND_PARSE_PARAMETERS_END();
1204 
1205 	if (Z_TYPE(EG(user_exception_handler)) != IS_UNDEF) {
1206 		ZVAL_COPY(return_value, &EG(user_exception_handler));
1207 	}
1208 
1209 	zend_stack_push(&EG(user_exception_handlers), &EG(user_exception_handler));
1210 
1211 	if (!ZEND_FCI_INITIALIZED(fci)) { /* unset user-defined handler */
1212 		ZVAL_UNDEF(&EG(user_exception_handler));
1213 		return;
1214 	}
1215 
1216 	ZVAL_COPY(&EG(user_exception_handler), &(fci.function_name));
1217 }
1218 /* }}} */
1219 
1220 /* {{{ Restores the previously defined exception handler function */
ZEND_FUNCTION(restore_exception_handler)1221 ZEND_FUNCTION(restore_exception_handler)
1222 {
1223 	ZEND_PARSE_PARAMETERS_NONE();
1224 
1225 	if (Z_TYPE(EG(user_exception_handler)) != IS_UNDEF) {
1226 		zval_ptr_dtor(&EG(user_exception_handler));
1227 	}
1228 	if (zend_stack_is_empty(&EG(user_exception_handlers))) {
1229 		ZVAL_UNDEF(&EG(user_exception_handler));
1230 	} else {
1231 		zval *tmp = zend_stack_top(&EG(user_exception_handlers));
1232 		ZVAL_COPY_VALUE(&EG(user_exception_handler), tmp);
1233 		zend_stack_del_top(&EG(user_exception_handlers));
1234 	}
1235 
1236 	// TODO Change to void
1237 	RETURN_TRUE;
1238 }
1239 /* }}} */
1240 
get_declared_class_impl(INTERNAL_FUNCTION_PARAMETERS,int flags)1241 static inline void get_declared_class_impl(INTERNAL_FUNCTION_PARAMETERS, int flags) /* {{{ */
1242 {
1243 	zend_string *key;
1244 	zval *zv;
1245 	zend_class_entry *ce;
1246 
1247 	ZEND_PARSE_PARAMETERS_NONE();
1248 
1249 	array_init(return_value);
1250 	zend_hash_real_init_packed(Z_ARRVAL_P(return_value));
1251 	ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
1252 		ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(EG(class_table), key, zv) {
1253 			ce = Z_PTR_P(zv);
1254 			if ((ce->ce_flags & (ZEND_ACC_LINKED|ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT)) == flags
1255 			 && key
1256 			 && ZSTR_VAL(key)[0] != 0) {
1257 				ZEND_HASH_FILL_GROW();
1258 				if (EXPECTED(Z_TYPE_P(zv) == IS_PTR)) {
1259 					ZEND_HASH_FILL_SET_STR_COPY(ce->name);
1260 				} else {
1261 					ZEND_ASSERT(Z_TYPE_P(zv) == IS_ALIAS_PTR);
1262 					ZEND_HASH_FILL_SET_STR_COPY(key);
1263 				}
1264 				ZEND_HASH_FILL_NEXT();
1265 			}
1266 		} ZEND_HASH_FOREACH_END();
1267 	} ZEND_HASH_FILL_END();
1268 }
1269 /* {{{ */
1270 
1271 /* {{{ Returns an array of all declared traits. */
ZEND_FUNCTION(get_declared_traits)1272 ZEND_FUNCTION(get_declared_traits)
1273 {
1274 	get_declared_class_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_LINKED | ZEND_ACC_TRAIT);
1275 }
1276 /* }}} */
1277 
1278 /* {{{ Returns an array of all declared classes. */
ZEND_FUNCTION(get_declared_classes)1279 ZEND_FUNCTION(get_declared_classes)
1280 {
1281 	get_declared_class_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_LINKED);
1282 }
1283 /* }}} */
1284 
1285 /* {{{ Returns an array of all declared interfaces. */
ZEND_FUNCTION(get_declared_interfaces)1286 ZEND_FUNCTION(get_declared_interfaces)
1287 {
1288 	get_declared_class_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_LINKED | ZEND_ACC_INTERFACE);
1289 }
1290 /* }}} */
1291 
1292 /* {{{ Returns an array of all defined functions */
ZEND_FUNCTION(get_defined_functions)1293 ZEND_FUNCTION(get_defined_functions)
1294 {
1295 	zval internal, user;
1296 	zend_string *key;
1297 	zend_function *func;
1298 	bool exclude_disabled = 1;
1299 
1300 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &exclude_disabled) == FAILURE) {
1301 		RETURN_THROWS();
1302 	}
1303 
1304 	if (exclude_disabled == 0) {
1305 		zend_error(E_DEPRECATED,
1306 			"get_defined_functions(): Setting $exclude_disabled to false has no effect");
1307 	}
1308 
1309 	array_init(&internal);
1310 	array_init(&user);
1311 	array_init(return_value);
1312 
1313 	ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(EG(function_table), key, func) {
1314 		if (key && ZSTR_VAL(key)[0] != 0) {
1315 			if (func->type == ZEND_INTERNAL_FUNCTION) {
1316 				add_next_index_str(&internal, zend_string_copy(key));
1317 			} else if (func->type == ZEND_USER_FUNCTION) {
1318 				add_next_index_str(&user, zend_string_copy(key));
1319 			}
1320 		}
1321 	} ZEND_HASH_FOREACH_END();
1322 
1323 	zend_hash_str_add_new(Z_ARRVAL_P(return_value), "internal", sizeof("internal")-1, &internal);
1324 	zend_hash_str_add_new(Z_ARRVAL_P(return_value), "user", sizeof("user")-1, &user);
1325 }
1326 /* }}} */
1327 
1328 /* {{{ Returns an associative array of names and values of all currently defined variable names (variables in the current scope) */
ZEND_FUNCTION(get_defined_vars)1329 ZEND_FUNCTION(get_defined_vars)
1330 {
1331 	zend_array *symbol_table;
1332 
1333 	ZEND_PARSE_PARAMETERS_NONE();
1334 
1335 	if (zend_forbid_dynamic_call() == FAILURE) {
1336 		return;
1337 	}
1338 
1339 	symbol_table = zend_rebuild_symbol_table();
1340 	if (UNEXPECTED(symbol_table == NULL)) {
1341 		RETURN_EMPTY_ARRAY();
1342 	}
1343 
1344 	RETURN_ARR(zend_array_dup(symbol_table));
1345 }
1346 /* }}} */
1347 
1348 #if ZEND_DEBUG && defined(ZTS)
ZEND_FUNCTION(zend_thread_id)1349 ZEND_FUNCTION(zend_thread_id)
1350 {
1351 	ZEND_PARSE_PARAMETERS_NONE();
1352 
1353 	RETURN_LONG((zend_long)tsrm_thread_id());
1354 }
1355 #endif
1356 
1357 /* {{{ Get the resource type name for a given resource */
ZEND_FUNCTION(get_resource_type)1358 ZEND_FUNCTION(get_resource_type)
1359 {
1360 	const char *resource_type;
1361 	zval *z_resource_type;
1362 
1363 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &z_resource_type) == FAILURE) {
1364 		RETURN_THROWS();
1365 	}
1366 
1367 	resource_type = zend_rsrc_list_get_rsrc_type(Z_RES_P(z_resource_type));
1368 	if (resource_type) {
1369 		RETURN_STRING(resource_type);
1370 	} else {
1371 		RETURN_STRING("Unknown");
1372 	}
1373 }
1374 /* }}} */
1375 
1376 /* {{{ Get the resource ID for a given resource */
ZEND_FUNCTION(get_resource_id)1377 ZEND_FUNCTION(get_resource_id)
1378 {
1379 	zval *resource;
1380 
1381 	ZEND_PARSE_PARAMETERS_START(1, 1)
1382 		Z_PARAM_RESOURCE(resource)
1383 	ZEND_PARSE_PARAMETERS_END();
1384 
1385 	RETURN_LONG(Z_RES_HANDLE_P(resource));
1386 }
1387 /* }}} */
1388 
1389 /* {{{ Get an array with all active resources */
ZEND_FUNCTION(get_resources)1390 ZEND_FUNCTION(get_resources)
1391 {
1392 	zend_string *type = NULL;
1393 	zend_string *key;
1394 	zend_ulong index;
1395 	zval *val;
1396 
1397 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|S!", &type) == FAILURE) {
1398 		RETURN_THROWS();
1399 	}
1400 
1401 	if (!type) {
1402 		array_init(return_value);
1403 		ZEND_HASH_FOREACH_KEY_VAL(&EG(regular_list), index, key, val) {
1404 			if (!key) {
1405 				Z_ADDREF_P(val);
1406 				zend_hash_index_add_new(Z_ARRVAL_P(return_value), index, val);
1407 			}
1408 		} ZEND_HASH_FOREACH_END();
1409 	} else if (zend_string_equals_literal(type, "Unknown")) {
1410 		array_init(return_value);
1411 		ZEND_HASH_FOREACH_KEY_VAL(&EG(regular_list), index, key, val) {
1412 			if (!key && Z_RES_TYPE_P(val) <= 0) {
1413 				Z_ADDREF_P(val);
1414 				zend_hash_index_add_new(Z_ARRVAL_P(return_value), index, val);
1415 			}
1416 		} ZEND_HASH_FOREACH_END();
1417 	} else {
1418 		int id = zend_fetch_list_dtor_id(ZSTR_VAL(type));
1419 
1420 		if (id <= 0) {
1421 			zend_argument_value_error(1, "must be a valid resource type");
1422 			RETURN_THROWS();
1423 		}
1424 
1425 		array_init(return_value);
1426 		ZEND_HASH_FOREACH_KEY_VAL(&EG(regular_list), index, key, val) {
1427 			if (!key && Z_RES_TYPE_P(val) == id) {
1428 				Z_ADDREF_P(val);
1429 				zend_hash_index_add_new(Z_ARRVAL_P(return_value), index, val);
1430 			}
1431 		} ZEND_HASH_FOREACH_END();
1432 	}
1433 }
1434 /* }}} */
1435 
add_zendext_info(zend_extension * ext,void * arg)1436 static void add_zendext_info(zend_extension *ext, void *arg) /* {{{ */
1437 {
1438 	zval *name_array = (zval *)arg;
1439 	add_next_index_string(name_array, ext->name);
1440 }
1441 /* }}} */
1442 
1443 /* {{{ Return an array containing names of loaded extensions */
ZEND_FUNCTION(get_loaded_extensions)1444 ZEND_FUNCTION(get_loaded_extensions)
1445 {
1446 	bool zendext = 0;
1447 
1448 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &zendext) == FAILURE) {
1449 		RETURN_THROWS();
1450 	}
1451 
1452 	array_init(return_value);
1453 
1454 	if (zendext) {
1455 		zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) add_zendext_info, return_value);
1456 	} else {
1457 		zend_module_entry *module;
1458 
1459 		ZEND_HASH_MAP_FOREACH_PTR(&module_registry, module) {
1460 			add_next_index_string(return_value, module->name);
1461 		} ZEND_HASH_FOREACH_END();
1462 	}
1463 }
1464 /* }}} */
1465 
1466 /* {{{ Return an array containing the names and values of all defined constants */
ZEND_FUNCTION(get_defined_constants)1467 ZEND_FUNCTION(get_defined_constants)
1468 {
1469 	bool categorize = 0;
1470 
1471 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &categorize) == FAILURE) {
1472 		RETURN_THROWS();
1473 	}
1474 
1475 	array_init(return_value);
1476 
1477 	if (categorize) {
1478 		zend_constant *val;
1479 		int module_number;
1480 		zval *modules, const_val;
1481 		char **module_names;
1482 		zend_module_entry *module;
1483 		int i = 1;
1484 
1485 		modules = ecalloc(zend_hash_num_elements(&module_registry) + 2, sizeof(zval));
1486 		module_names = emalloc((zend_hash_num_elements(&module_registry) + 2) * sizeof(char *));
1487 
1488 		module_names[0] = "internal";
1489 		ZEND_HASH_MAP_FOREACH_PTR(&module_registry, module) {
1490 			module_names[module->module_number] = (char *)module->name;
1491 			i++;
1492 		} ZEND_HASH_FOREACH_END();
1493 		module_names[i] = "user";
1494 
1495 		ZEND_HASH_MAP_FOREACH_PTR(EG(zend_constants), val) {
1496 			if (!val->name) {
1497 				/* skip special constants */
1498 				continue;
1499 			}
1500 
1501 			if (ZEND_CONSTANT_MODULE_NUMBER(val) == PHP_USER_CONSTANT) {
1502 				module_number = i;
1503 			} else if (ZEND_CONSTANT_MODULE_NUMBER(val) > i) {
1504 				/* should not happen */
1505 				continue;
1506 			} else {
1507 				module_number = ZEND_CONSTANT_MODULE_NUMBER(val);
1508 			}
1509 
1510 			if (Z_TYPE(modules[module_number]) == IS_UNDEF) {
1511 				array_init(&modules[module_number]);
1512 				add_assoc_zval(return_value, module_names[module_number], &modules[module_number]);
1513 			}
1514 
1515 			ZVAL_COPY_OR_DUP(&const_val, &val->value);
1516 			zend_hash_add_new(Z_ARRVAL(modules[module_number]), val->name, &const_val);
1517 		} ZEND_HASH_FOREACH_END();
1518 
1519 		efree(module_names);
1520 		efree(modules);
1521 	} else {
1522 		zend_constant *constant;
1523 		zval const_val;
1524 
1525 		ZEND_HASH_MAP_FOREACH_PTR(EG(zend_constants), constant) {
1526 			if (!constant->name) {
1527 				/* skip special constants */
1528 				continue;
1529 			}
1530 			ZVAL_COPY_OR_DUP(&const_val, &constant->value);
1531 			zend_hash_add_new(Z_ARRVAL_P(return_value), constant->name, &const_val);
1532 		} ZEND_HASH_FOREACH_END();
1533 	}
1534 }
1535 /* }}} */
1536 
debug_backtrace_get_args(zend_execute_data * call,zval * arg_array)1537 static void debug_backtrace_get_args(zend_execute_data *call, zval *arg_array) /* {{{ */
1538 {
1539 	uint32_t num_args = ZEND_CALL_NUM_ARGS(call);
1540 
1541 	if (num_args) {
1542 		uint32_t i = 0;
1543 		zval *p = ZEND_CALL_ARG(call, 1);
1544 
1545 		array_init_size(arg_array, num_args);
1546 		zend_hash_real_init_packed(Z_ARRVAL_P(arg_array));
1547 		ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(arg_array)) {
1548 			if (call->func->type == ZEND_USER_FUNCTION) {
1549 				uint32_t first_extra_arg = MIN(num_args, call->func->op_array.num_args);
1550 
1551 				if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_HAS_SYMBOL_TABLE)) {
1552 					/* In case of attached symbol_table, values on stack may be invalid
1553 					 * and we have to access them through symbol_table
1554 					 * See: https://bugs.php.net/bug.php?id=73156
1555 					 */
1556 					while (i < first_extra_arg) {
1557 						zend_string *arg_name = call->func->op_array.vars[i];
1558 						zval original_arg;
1559 						zval *arg = zend_hash_find_ex_ind(call->symbol_table, arg_name, 1);
1560 						zend_attribute *attribute = zend_get_parameter_attribute_str(
1561 							call->func->common.attributes,
1562 							"sensitiveparameter",
1563 							sizeof("sensitiveparameter") - 1,
1564 							i
1565 						);
1566 
1567 						bool is_sensitive = attribute != NULL;
1568 
1569 						if (arg) {
1570 							ZVAL_DEREF(arg);
1571 							ZVAL_COPY_VALUE(&original_arg, arg);
1572 						} else {
1573 							ZVAL_NULL(&original_arg);
1574 						}
1575 
1576 						if (is_sensitive) {
1577 							zval redacted_arg;
1578 							object_init_ex(&redacted_arg, zend_ce_sensitive_parameter_value);
1579 							zend_call_method_with_1_params(Z_OBJ_P(&redacted_arg), zend_ce_sensitive_parameter_value, &zend_ce_sensitive_parameter_value->constructor, "__construct", NULL, &original_arg);
1580 							ZEND_HASH_FILL_SET(&redacted_arg);
1581 						} else {
1582 							Z_TRY_ADDREF_P(&original_arg);
1583 							ZEND_HASH_FILL_SET(&original_arg);
1584 						}
1585 
1586 						ZEND_HASH_FILL_NEXT();
1587 						i++;
1588 					}
1589 				} else {
1590 					while (i < first_extra_arg) {
1591 						zval original_arg;
1592 						zend_attribute *attribute = zend_get_parameter_attribute_str(
1593 							call->func->common.attributes,
1594 							"sensitiveparameter",
1595 							sizeof("sensitiveparameter") - 1,
1596 							i
1597 						);
1598 						bool is_sensitive = attribute != NULL;
1599 
1600 						if (EXPECTED(Z_TYPE_INFO_P(p) != IS_UNDEF)) {
1601 							zval *arg = p;
1602 							ZVAL_DEREF(arg);
1603 							ZVAL_COPY_VALUE(&original_arg, arg);
1604 						} else {
1605 							ZVAL_NULL(&original_arg);
1606 						}
1607 
1608 						if (is_sensitive) {
1609 							zval redacted_arg;
1610 							object_init_ex(&redacted_arg, zend_ce_sensitive_parameter_value);
1611 							zend_call_method_with_1_params(Z_OBJ_P(&redacted_arg), zend_ce_sensitive_parameter_value, &zend_ce_sensitive_parameter_value->constructor, "__construct", NULL, &original_arg);
1612 							ZEND_HASH_FILL_SET(&redacted_arg);
1613 						} else {
1614 							Z_TRY_ADDREF_P(&original_arg);
1615 							ZEND_HASH_FILL_SET(&original_arg);
1616 						}
1617 
1618 						ZEND_HASH_FILL_NEXT();
1619 						p++;
1620 						i++;
1621 					}
1622 				}
1623 				p = ZEND_CALL_VAR_NUM(call, call->func->op_array.last_var + call->func->op_array.T);
1624 			}
1625 
1626 			while (i < num_args) {
1627 				zval original_arg;
1628 				bool is_sensitive = 0;
1629 
1630 				if (i < call->func->common.num_args || call->func->common.fn_flags & ZEND_ACC_VARIADIC) {
1631 					zend_attribute *attribute = zend_get_parameter_attribute_str(
1632 						call->func->common.attributes,
1633 						"sensitiveparameter",
1634 						sizeof("sensitiveparameter") - 1,
1635 						MIN(i, call->func->common.num_args)
1636 					);
1637 					is_sensitive = attribute != NULL;
1638 				}
1639 
1640 				if (EXPECTED(Z_TYPE_INFO_P(p) != IS_UNDEF)) {
1641 					zval *arg = p;
1642 					ZVAL_DEREF(arg);
1643 					ZVAL_COPY_VALUE(&original_arg, arg);
1644 				} else {
1645 					ZVAL_NULL(&original_arg);
1646 				}
1647 
1648 				if (is_sensitive) {
1649 					zval redacted_arg;
1650 					object_init_ex(&redacted_arg, zend_ce_sensitive_parameter_value);
1651 					zend_call_method_with_1_params(Z_OBJ_P(&redacted_arg), zend_ce_sensitive_parameter_value, &zend_ce_sensitive_parameter_value->constructor, "__construct", NULL, &original_arg);
1652 					ZEND_HASH_FILL_SET(&redacted_arg);
1653 				} else {
1654 					Z_TRY_ADDREF_P(&original_arg);
1655 					ZEND_HASH_FILL_SET(&original_arg);
1656 				}
1657 
1658 				ZEND_HASH_FILL_NEXT();
1659 				p++;
1660 				i++;
1661 			}
1662 		} ZEND_HASH_FILL_END();
1663 		Z_ARRVAL_P(arg_array)->nNumOfElements = num_args;
1664 	} else {
1665 		ZVAL_EMPTY_ARRAY(arg_array);
1666 	}
1667 
1668 	if (ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS) {
1669 		zend_string *name;
1670 		zval *arg;
1671 		SEPARATE_ARRAY(arg_array);
1672 		ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(call->extra_named_params, name, arg) {
1673 			ZVAL_DEREF(arg);
1674 			Z_TRY_ADDREF_P(arg);
1675 			zend_hash_add_new(Z_ARRVAL_P(arg_array), name, arg);
1676 		} ZEND_HASH_FOREACH_END();
1677 	}
1678 }
1679 /* }}} */
1680 
1681 /* {{{ */
ZEND_FUNCTION(debug_print_backtrace)1682 ZEND_FUNCTION(debug_print_backtrace)
1683 {
1684 	zend_long options = 0;
1685 	zend_long limit = 0;
1686 	zval backtrace;
1687 
1688 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|ll", &options, &limit) == FAILURE) {
1689 		RETURN_THROWS();
1690 	}
1691 
1692 	zend_fetch_debug_backtrace(&backtrace, 1, options, limit);
1693 	ZEND_ASSERT(Z_TYPE(backtrace) == IS_ARRAY);
1694 
1695 	zend_string *str = zend_trace_to_string(Z_ARRVAL(backtrace), /* include_main */ false);
1696 	ZEND_WRITE(ZSTR_VAL(str), ZSTR_LEN(str));
1697 	zend_string_release(str);
1698 	zval_ptr_dtor(&backtrace);
1699 }
1700 
1701 /* }}} */
1702 
zend_fetch_debug_backtrace(zval * return_value,int skip_last,int options,int limit)1703 ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int options, int limit) /* {{{ */
1704 {
1705 	zend_execute_data *call;
1706 	zend_object *object;
1707 	bool fake_frame = 0;
1708 	int lineno, frameno = 0;
1709 	zend_function *func;
1710 	zend_string *filename;
1711 	zend_string *include_filename = NULL;
1712 	zval tmp;
1713 	HashTable *stack_frame;
1714 
1715 	array_init(return_value);
1716 
1717 	call = EG(current_execute_data);
1718 	if (!call) {
1719 		return;
1720 	}
1721 
1722 	if (skip_last) {
1723 		/* skip debug_backtrace() */
1724 		call = call->prev_execute_data;
1725 	}
1726 
1727 	while (call && (limit == 0 || frameno < limit)) {
1728 		if (UNEXPECTED(!call->func)) {
1729 			/* This is the fake frame inserted for nested generators. Normally,
1730 			 * this frame is preceded by the actual generator frame and then
1731 			 * replaced by zend_generator_check_placeholder_frame() below.
1732 			 * However, the frame is popped before cleaning the stack frame,
1733 			 * which is observable by destructors. */
1734 			call = zend_generator_check_placeholder_frame(call);
1735 			ZEND_ASSERT(call->func);
1736 		}
1737 
1738 		zend_execute_data *prev = call->prev_execute_data;
1739 
1740 		if (!prev) {
1741 			/* add frame for a handler call without {main} code */
1742 			if (EXPECTED((ZEND_CALL_INFO(call) & ZEND_CALL_TOP_FUNCTION) == 0)) {
1743 				break;
1744 			}
1745 		} else if (UNEXPECTED((ZEND_CALL_INFO(call) & ZEND_CALL_GENERATOR) != 0)) {
1746 			prev = zend_generator_check_placeholder_frame(prev);
1747 		}
1748 
1749 		frameno++;
1750 
1751 		/* We use _zend_hash_append*() and the array must be preallocated */
1752 		stack_frame = zend_new_array(8);
1753 		zend_hash_real_init_mixed(stack_frame);
1754 
1755 		if (prev && prev->func && ZEND_USER_CODE(prev->func->common.type)) {
1756 			filename = prev->func->op_array.filename;
1757 			if (prev->opline->opcode == ZEND_HANDLE_EXCEPTION) {
1758 				if (EG(opline_before_exception)) {
1759 					lineno = EG(opline_before_exception)->lineno;
1760 				} else {
1761 					lineno = prev->func->op_array.line_end;
1762 				}
1763 			} else {
1764 				lineno = prev->opline->lineno;
1765 			}
1766 			ZVAL_STR_COPY(&tmp, filename);
1767 			_zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_FILE), &tmp, 1);
1768 			ZVAL_LONG(&tmp, lineno);
1769 			_zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_LINE), &tmp, 1);
1770 
1771 			/* try to fetch args only if an FCALL was just made - elsewise we're in the middle of a function
1772 			 * and debug_backtrace() might have been called by the error_handler. in this case we don't
1773 			 * want to pop anything of the argument-stack */
1774 		} else {
1775 			zend_execute_data *prev_call = prev;
1776 
1777 			while (prev_call) {
1778 				zend_execute_data *prev;
1779 
1780 				if (prev_call &&
1781 					prev_call->func &&
1782 					!ZEND_USER_CODE(prev_call->func->common.type) &&
1783 					!(prev_call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
1784 					break;
1785 				}
1786 
1787 				prev = prev_call->prev_execute_data;
1788 				if (prev && prev->func && ZEND_USER_CODE(prev->func->common.type)) {
1789 					ZVAL_STR_COPY(&tmp, prev->func->op_array.filename);
1790 					_zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_FILE), &tmp, 1);
1791 					ZVAL_LONG(&tmp, prev->opline->lineno);
1792 					_zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_LINE), &tmp, 1);
1793 					break;
1794 				}
1795 				prev_call = prev;
1796 			}
1797 			filename = NULL;
1798 		}
1799 
1800 		func = call->func;
1801 		if (!fake_frame && func->common.function_name) {
1802 			ZVAL_STR_COPY(&tmp, func->common.function_name);
1803 			_zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_FUNCTION), &tmp, 1);
1804 
1805 			if (Z_TYPE(call->This) == IS_OBJECT) {
1806 				object = Z_OBJ(call->This);
1807 				/* $this may be passed into regular internal functions */
1808 				if (func->common.scope) {
1809 					ZVAL_STR_COPY(&tmp, func->common.scope->name);
1810 				} else if (object->handlers->get_class_name == zend_std_get_class_name) {
1811 					ZVAL_STR_COPY(&tmp, object->ce->name);
1812 				} else {
1813 					ZVAL_STR(&tmp, object->handlers->get_class_name(object));
1814 				}
1815 				_zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_CLASS), &tmp, 1);
1816 				if ((options & DEBUG_BACKTRACE_PROVIDE_OBJECT) != 0) {
1817 					ZVAL_OBJ_COPY(&tmp, object);
1818 					_zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_OBJECT), &tmp, 1);
1819 				}
1820 
1821 				ZVAL_INTERNED_STR(&tmp, ZSTR_KNOWN(ZEND_STR_OBJECT_OPERATOR));
1822 				_zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_TYPE), &tmp, 1);
1823 			} else if (func->common.scope) {
1824 				ZVAL_STR_COPY(&tmp, func->common.scope->name);
1825 				_zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_CLASS), &tmp, 1);
1826 				ZVAL_INTERNED_STR(&tmp, ZSTR_KNOWN(ZEND_STR_PAAMAYIM_NEKUDOTAYIM));
1827 				_zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_TYPE), &tmp, 1);
1828 			}
1829 
1830 			if ((options & DEBUG_BACKTRACE_IGNORE_ARGS) == 0 &&
1831 				func->type != ZEND_EVAL_CODE) {
1832 
1833 				debug_backtrace_get_args(call, &tmp);
1834 				_zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_ARGS), &tmp, 1);
1835 			}
1836 		} else {
1837 			/* i know this is kinda ugly, but i'm trying to avoid extra cycles in the main execution loop */
1838 			bool build_filename_arg = 1;
1839 			zend_string *pseudo_function_name;
1840 			uint32_t include_kind = 0;
1841 			if (prev && prev->func && ZEND_USER_CODE(prev->func->common.type) && prev->opline->opcode == ZEND_INCLUDE_OR_EVAL) {
1842 				include_kind = prev->opline->extended_value;
1843 			}
1844 
1845 			switch (include_kind) {
1846 				case ZEND_EVAL:
1847 					pseudo_function_name = ZSTR_KNOWN(ZEND_STR_EVAL);
1848 					build_filename_arg = 0;
1849 					break;
1850 				case ZEND_INCLUDE:
1851 					pseudo_function_name = ZSTR_KNOWN(ZEND_STR_INCLUDE);
1852 					break;
1853 				case ZEND_REQUIRE:
1854 					pseudo_function_name = ZSTR_KNOWN(ZEND_STR_REQUIRE);
1855 					break;
1856 				case ZEND_INCLUDE_ONCE:
1857 					pseudo_function_name = ZSTR_KNOWN(ZEND_STR_INCLUDE_ONCE);
1858 					break;
1859 				case ZEND_REQUIRE_ONCE:
1860 					pseudo_function_name = ZSTR_KNOWN(ZEND_STR_REQUIRE_ONCE);
1861 					break;
1862 				default:
1863 					/* Skip dummy frame unless it is needed to preserve filename/lineno info. */
1864 					if (!filename) {
1865 						zend_array_destroy(stack_frame);
1866 						goto skip_frame;
1867 					}
1868 
1869 					pseudo_function_name = ZSTR_KNOWN(ZEND_STR_UNKNOWN);
1870 					build_filename_arg = 0;
1871 					break;
1872 			}
1873 
1874 			if (build_filename_arg && include_filename) {
1875 				zval arg_array;
1876 
1877 				array_init(&arg_array);
1878 
1879 				/* include_filename always points to the last filename of the last last called-function.
1880 				   if we have called include in the frame above - this is the file we have included.
1881 				 */
1882 
1883 				ZVAL_STR_COPY(&tmp, include_filename);
1884 				zend_hash_next_index_insert_new(Z_ARRVAL(arg_array), &tmp);
1885 				_zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_ARGS), &arg_array, 1);
1886 			}
1887 
1888 			ZVAL_INTERNED_STR(&tmp, pseudo_function_name);
1889 			_zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_FUNCTION), &tmp, 1);
1890 		}
1891 
1892 		ZVAL_ARR(&tmp, stack_frame);
1893 		zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp);
1894 
1895 skip_frame:
1896 		if (UNEXPECTED(ZEND_CALL_KIND(call) == ZEND_CALL_TOP_FUNCTION)
1897 		 && !fake_frame
1898 		 && prev
1899 		 && prev->func
1900 		 && ZEND_USER_CODE(prev->func->common.type)
1901 		 && prev->opline->opcode == ZEND_INCLUDE_OR_EVAL) {
1902 			fake_frame = 1;
1903 		} else {
1904 			fake_frame = 0;
1905 			include_filename = filename;
1906 			call = prev;
1907 		}
1908 	}
1909 }
1910 /* }}} */
1911 
1912 /* {{{ Return backtrace as array */
ZEND_FUNCTION(debug_backtrace)1913 ZEND_FUNCTION(debug_backtrace)
1914 {
1915 	zend_long options = DEBUG_BACKTRACE_PROVIDE_OBJECT;
1916 	zend_long limit = 0;
1917 
1918 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|ll", &options, &limit) == FAILURE) {
1919 		RETURN_THROWS();
1920 	}
1921 
1922 	zend_fetch_debug_backtrace(return_value, 1, options, limit);
1923 }
1924 /* }}} */
1925 
1926 /* {{{ Returns true if the named extension is loaded */
ZEND_FUNCTION(extension_loaded)1927 ZEND_FUNCTION(extension_loaded)
1928 {
1929 	zend_string *extension_name;
1930 	zend_string *lcname;
1931 
1932 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &extension_name) == FAILURE) {
1933 		RETURN_THROWS();
1934 	}
1935 
1936 	lcname = zend_string_tolower(extension_name);
1937 	if (zend_hash_exists(&module_registry, lcname)) {
1938 		RETVAL_TRUE;
1939 	} else {
1940 		RETVAL_FALSE;
1941 	}
1942 	zend_string_release_ex(lcname, 0);
1943 }
1944 /* }}} */
1945 
1946 /* {{{ Returns an array with the names of functions belonging to the named extension */
ZEND_FUNCTION(get_extension_funcs)1947 ZEND_FUNCTION(get_extension_funcs)
1948 {
1949 	zend_string *extension_name;
1950 	zend_string *lcname;
1951 	bool array;
1952 	zend_module_entry *module;
1953 	zend_function *zif;
1954 
1955 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &extension_name) == FAILURE) {
1956 		RETURN_THROWS();
1957 	}
1958 	if (strncasecmp(ZSTR_VAL(extension_name), "zend", sizeof("zend"))) {
1959 		lcname = zend_string_tolower(extension_name);
1960 		module = zend_hash_find_ptr(&module_registry, lcname);
1961 		zend_string_release_ex(lcname, 0);
1962 	} else {
1963 		module = zend_hash_str_find_ptr(&module_registry, "core", sizeof("core") - 1);
1964 	}
1965 
1966 	if (!module) {
1967 		RETURN_FALSE;
1968 	}
1969 
1970 	if (module->functions) {
1971 		/* avoid BC break, if functions list is empty, will return an empty array */
1972 		array_init(return_value);
1973 		array = 1;
1974 	} else {
1975 		array = 0;
1976 	}
1977 
1978 	ZEND_HASH_MAP_FOREACH_PTR(CG(function_table), zif) {
1979 		if (zif->common.type == ZEND_INTERNAL_FUNCTION
1980 			&& zif->internal_function.module == module) {
1981 			if (!array) {
1982 				array_init(return_value);
1983 				array = 1;
1984 			}
1985 			add_next_index_str(return_value, zend_string_copy(zif->common.function_name));
1986 		}
1987 	} ZEND_HASH_FOREACH_END();
1988 
1989 	if (!array) {
1990 		RETURN_FALSE;
1991 	}
1992 }
1993 /* }}} */
1994