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