xref: /php-src/Zend/zend_builtin_functions.c (revision ff472ce6)
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 (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 (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 (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_MAP_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 	char *message;
1112 	size_t message_len;
1113 
1114 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &message, &message_len, &error_type) == FAILURE) {
1115 		RETURN_THROWS();
1116 	}
1117 
1118 	switch (error_type) {
1119 		case E_USER_ERROR:
1120 		case E_USER_WARNING:
1121 		case E_USER_NOTICE:
1122 		case E_USER_DEPRECATED:
1123 			break;
1124 		default:
1125 			zend_argument_value_error(2, "must be one of E_USER_ERROR, E_USER_WARNING, E_USER_NOTICE,"
1126 				" or E_USER_DEPRECATED");
1127 			RETURN_THROWS();
1128 			break;
1129 	}
1130 
1131 	zend_error((int)error_type, "%s", message);
1132 	// TODO Change to void
1133 	RETURN_TRUE;
1134 }
1135 /* }}} */
1136 
1137 /* {{{ Sets a user-defined error handler function.  Returns the previously defined error handler, or false on error */
ZEND_FUNCTION(set_error_handler)1138 ZEND_FUNCTION(set_error_handler)
1139 {
1140 	zend_fcall_info fci;
1141 	zend_fcall_info_cache fcc;
1142 	zend_long error_type = E_ALL;
1143 
1144 	ZEND_PARSE_PARAMETERS_START(1, 2)
1145 		Z_PARAM_FUNC_OR_NULL(fci, fcc)
1146 		Z_PARAM_OPTIONAL
1147 		Z_PARAM_LONG(error_type)
1148 	ZEND_PARSE_PARAMETERS_END();
1149 
1150 	if (Z_TYPE(EG(user_error_handler)) != IS_UNDEF) {
1151 		ZVAL_COPY(return_value, &EG(user_error_handler));
1152 	}
1153 
1154 	zend_stack_push(&EG(user_error_handlers_error_reporting), &EG(user_error_handler_error_reporting));
1155 	zend_stack_push(&EG(user_error_handlers), &EG(user_error_handler));
1156 
1157 	if (!ZEND_FCI_INITIALIZED(fci)) { /* unset user-defined handler */
1158 		ZVAL_UNDEF(&EG(user_error_handler));
1159 		return;
1160 	}
1161 
1162 	ZVAL_COPY(&EG(user_error_handler), &(fci.function_name));
1163 	EG(user_error_handler_error_reporting) = (int)error_type;
1164 }
1165 /* }}} */
1166 
1167 /* {{{ Restores the previously defined error handler function */
ZEND_FUNCTION(restore_error_handler)1168 ZEND_FUNCTION(restore_error_handler)
1169 {
1170 	ZEND_PARSE_PARAMETERS_NONE();
1171 
1172 	if (Z_TYPE(EG(user_error_handler)) != IS_UNDEF) {
1173 		zval zeh;
1174 
1175 		ZVAL_COPY_VALUE(&zeh, &EG(user_error_handler));
1176 		ZVAL_UNDEF(&EG(user_error_handler));
1177 		zval_ptr_dtor(&zeh);
1178 	}
1179 
1180 	if (zend_stack_is_empty(&EG(user_error_handlers))) {
1181 		ZVAL_UNDEF(&EG(user_error_handler));
1182 	} else {
1183 		zval *tmp;
1184 		EG(user_error_handler_error_reporting) = zend_stack_int_top(&EG(user_error_handlers_error_reporting));
1185 		zend_stack_del_top(&EG(user_error_handlers_error_reporting));
1186 		tmp = zend_stack_top(&EG(user_error_handlers));
1187 		ZVAL_COPY_VALUE(&EG(user_error_handler), tmp);
1188 		zend_stack_del_top(&EG(user_error_handlers));
1189 	}
1190 
1191 	// TODO Change to void
1192 	RETURN_TRUE;
1193 }
1194 /* }}} */
1195 
1196 /* {{{ Sets a user-defined exception handler function. Returns the previously defined exception handler, or false on error */
ZEND_FUNCTION(set_exception_handler)1197 ZEND_FUNCTION(set_exception_handler)
1198 {
1199 	zend_fcall_info fci;
1200 	zend_fcall_info_cache fcc;
1201 
1202 	ZEND_PARSE_PARAMETERS_START(1, 1)
1203 		Z_PARAM_FUNC_OR_NULL(fci, fcc)
1204 	ZEND_PARSE_PARAMETERS_END();
1205 
1206 	if (Z_TYPE(EG(user_exception_handler)) != IS_UNDEF) {
1207 		ZVAL_COPY(return_value, &EG(user_exception_handler));
1208 	}
1209 
1210 	zend_stack_push(&EG(user_exception_handlers), &EG(user_exception_handler));
1211 
1212 	if (!ZEND_FCI_INITIALIZED(fci)) { /* unset user-defined handler */
1213 		ZVAL_UNDEF(&EG(user_exception_handler));
1214 		return;
1215 	}
1216 
1217 	ZVAL_COPY(&EG(user_exception_handler), &(fci.function_name));
1218 }
1219 /* }}} */
1220 
1221 /* {{{ Restores the previously defined exception handler function */
ZEND_FUNCTION(restore_exception_handler)1222 ZEND_FUNCTION(restore_exception_handler)
1223 {
1224 	ZEND_PARSE_PARAMETERS_NONE();
1225 
1226 	if (Z_TYPE(EG(user_exception_handler)) != IS_UNDEF) {
1227 		zval_ptr_dtor(&EG(user_exception_handler));
1228 	}
1229 	if (zend_stack_is_empty(&EG(user_exception_handlers))) {
1230 		ZVAL_UNDEF(&EG(user_exception_handler));
1231 	} else {
1232 		zval *tmp = zend_stack_top(&EG(user_exception_handlers));
1233 		ZVAL_COPY_VALUE(&EG(user_exception_handler), tmp);
1234 		zend_stack_del_top(&EG(user_exception_handlers));
1235 	}
1236 
1237 	// TODO Change to void
1238 	RETURN_TRUE;
1239 }
1240 /* }}} */
1241 
get_declared_class_impl(INTERNAL_FUNCTION_PARAMETERS,int flags)1242 static inline void get_declared_class_impl(INTERNAL_FUNCTION_PARAMETERS, int flags) /* {{{ */
1243 {
1244 	zend_string *key;
1245 	zval *zv;
1246 	zend_class_entry *ce;
1247 
1248 	ZEND_PARSE_PARAMETERS_NONE();
1249 
1250 	array_init(return_value);
1251 	zend_hash_real_init_packed(Z_ARRVAL_P(return_value));
1252 	ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
1253 		ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(EG(class_table), key, zv) {
1254 			ce = Z_PTR_P(zv);
1255 			if ((ce->ce_flags & (ZEND_ACC_LINKED|ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT)) == flags
1256 			 && key
1257 			 && ZSTR_VAL(key)[0] != 0) {
1258 				ZEND_HASH_FILL_GROW();
1259 				if (EXPECTED(Z_TYPE_P(zv) == IS_PTR)) {
1260 					ZEND_HASH_FILL_SET_STR_COPY(ce->name);
1261 				} else {
1262 					ZEND_ASSERT(Z_TYPE_P(zv) == IS_ALIAS_PTR);
1263 					ZEND_HASH_FILL_SET_STR_COPY(key);
1264 				}
1265 				ZEND_HASH_FILL_NEXT();
1266 			}
1267 		} ZEND_HASH_FOREACH_END();
1268 	} ZEND_HASH_FILL_END();
1269 }
1270 /* {{{ */
1271 
1272 /* {{{ Returns an array of all declared traits. */
ZEND_FUNCTION(get_declared_traits)1273 ZEND_FUNCTION(get_declared_traits)
1274 {
1275 	get_declared_class_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_LINKED | ZEND_ACC_TRAIT);
1276 }
1277 /* }}} */
1278 
1279 /* {{{ Returns an array of all declared classes. */
ZEND_FUNCTION(get_declared_classes)1280 ZEND_FUNCTION(get_declared_classes)
1281 {
1282 	get_declared_class_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_LINKED);
1283 }
1284 /* }}} */
1285 
1286 /* {{{ Returns an array of all declared interfaces. */
ZEND_FUNCTION(get_declared_interfaces)1287 ZEND_FUNCTION(get_declared_interfaces)
1288 {
1289 	get_declared_class_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_LINKED | ZEND_ACC_INTERFACE);
1290 }
1291 /* }}} */
1292 
1293 /* {{{ Returns an array of all defined functions */
ZEND_FUNCTION(get_defined_functions)1294 ZEND_FUNCTION(get_defined_functions)
1295 {
1296 	zval internal, user;
1297 	zend_string *key;
1298 	zend_function *func;
1299 	bool exclude_disabled = 1;
1300 
1301 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &exclude_disabled) == FAILURE) {
1302 		RETURN_THROWS();
1303 	}
1304 
1305 	if (exclude_disabled == 0) {
1306 		zend_error(E_DEPRECATED,
1307 			"get_defined_functions(): Setting $exclude_disabled to false has no effect");
1308 	}
1309 
1310 	array_init(&internal);
1311 	array_init(&user);
1312 	array_init(return_value);
1313 
1314 	ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(EG(function_table), key, func) {
1315 		if (key && ZSTR_VAL(key)[0] != 0) {
1316 			if (func->type == ZEND_INTERNAL_FUNCTION) {
1317 				add_next_index_str(&internal, zend_string_copy(key));
1318 			} else if (func->type == ZEND_USER_FUNCTION) {
1319 				add_next_index_str(&user, zend_string_copy(key));
1320 			}
1321 		}
1322 	} ZEND_HASH_FOREACH_END();
1323 
1324 	zend_hash_str_add_new(Z_ARRVAL_P(return_value), "internal", sizeof("internal")-1, &internal);
1325 	zend_hash_str_add_new(Z_ARRVAL_P(return_value), "user", sizeof("user")-1, &user);
1326 }
1327 /* }}} */
1328 
1329 /* {{{ Returns an associative array of names and values of all currently defined variable names (variables in the current scope) */
ZEND_FUNCTION(get_defined_vars)1330 ZEND_FUNCTION(get_defined_vars)
1331 {
1332 	zend_array *symbol_table;
1333 
1334 	ZEND_PARSE_PARAMETERS_NONE();
1335 
1336 	if (zend_forbid_dynamic_call() == FAILURE) {
1337 		return;
1338 	}
1339 
1340 	symbol_table = zend_rebuild_symbol_table();
1341 	if (UNEXPECTED(symbol_table == NULL)) {
1342 		RETURN_EMPTY_ARRAY();
1343 	}
1344 
1345 	RETURN_ARR(zend_array_dup(symbol_table));
1346 }
1347 /* }}} */
1348 
1349 #if ZEND_DEBUG && defined(ZTS)
ZEND_FUNCTION(zend_thread_id)1350 ZEND_FUNCTION(zend_thread_id)
1351 {
1352 	ZEND_PARSE_PARAMETERS_NONE();
1353 
1354 	RETURN_LONG((zend_long)tsrm_thread_id());
1355 }
1356 #endif
1357 
1358 /* {{{ Get the resource type name for a given resource */
ZEND_FUNCTION(get_resource_type)1359 ZEND_FUNCTION(get_resource_type)
1360 {
1361 	const char *resource_type;
1362 	zval *z_resource_type;
1363 
1364 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &z_resource_type) == FAILURE) {
1365 		RETURN_THROWS();
1366 	}
1367 
1368 	resource_type = zend_rsrc_list_get_rsrc_type(Z_RES_P(z_resource_type));
1369 	if (resource_type) {
1370 		RETURN_STRING(resource_type);
1371 	} else {
1372 		RETURN_STRING("Unknown");
1373 	}
1374 }
1375 /* }}} */
1376 
1377 /* {{{ Get the resource ID for a given resource */
ZEND_FUNCTION(get_resource_id)1378 ZEND_FUNCTION(get_resource_id)
1379 {
1380 	zval *resource;
1381 
1382 	ZEND_PARSE_PARAMETERS_START(1, 1)
1383 		Z_PARAM_RESOURCE(resource)
1384 	ZEND_PARSE_PARAMETERS_END();
1385 
1386 	RETURN_LONG(Z_RES_HANDLE_P(resource));
1387 }
1388 /* }}} */
1389 
1390 /* {{{ Get an array with all active resources */
ZEND_FUNCTION(get_resources)1391 ZEND_FUNCTION(get_resources)
1392 {
1393 	zend_string *type = NULL;
1394 	zend_string *key;
1395 	zend_ulong index;
1396 	zval *val;
1397 
1398 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|S!", &type) == FAILURE) {
1399 		RETURN_THROWS();
1400 	}
1401 
1402 	if (!type) {
1403 		array_init(return_value);
1404 		ZEND_HASH_FOREACH_KEY_VAL(&EG(regular_list), index, key, val) {
1405 			if (!key) {
1406 				Z_ADDREF_P(val);
1407 				zend_hash_index_add_new(Z_ARRVAL_P(return_value), index, val);
1408 			}
1409 		} ZEND_HASH_FOREACH_END();
1410 	} else if (zend_string_equals_literal(type, "Unknown")) {
1411 		array_init(return_value);
1412 		ZEND_HASH_FOREACH_KEY_VAL(&EG(regular_list), index, key, val) {
1413 			if (!key && Z_RES_TYPE_P(val) <= 0) {
1414 				Z_ADDREF_P(val);
1415 				zend_hash_index_add_new(Z_ARRVAL_P(return_value), index, val);
1416 			}
1417 		} ZEND_HASH_FOREACH_END();
1418 	} else {
1419 		int id = zend_fetch_list_dtor_id(ZSTR_VAL(type));
1420 
1421 		if (id <= 0) {
1422 			zend_argument_value_error(1, "must be a valid resource type");
1423 			RETURN_THROWS();
1424 		}
1425 
1426 		array_init(return_value);
1427 		ZEND_HASH_FOREACH_KEY_VAL(&EG(regular_list), index, key, val) {
1428 			if (!key && Z_RES_TYPE_P(val) == id) {
1429 				Z_ADDREF_P(val);
1430 				zend_hash_index_add_new(Z_ARRVAL_P(return_value), index, val);
1431 			}
1432 		} ZEND_HASH_FOREACH_END();
1433 	}
1434 }
1435 /* }}} */
1436 
add_zendext_info(zend_extension * ext,void * arg)1437 static void add_zendext_info(zend_extension *ext, void *arg) /* {{{ */
1438 {
1439 	zval *name_array = (zval *)arg;
1440 	add_next_index_string(name_array, ext->name);
1441 }
1442 /* }}} */
1443 
1444 /* {{{ Return an array containing names of loaded extensions */
ZEND_FUNCTION(get_loaded_extensions)1445 ZEND_FUNCTION(get_loaded_extensions)
1446 {
1447 	bool zendext = 0;
1448 
1449 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &zendext) == FAILURE) {
1450 		RETURN_THROWS();
1451 	}
1452 
1453 	array_init(return_value);
1454 
1455 	if (zendext) {
1456 		zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) add_zendext_info, return_value);
1457 	} else {
1458 		zend_module_entry *module;
1459 
1460 		ZEND_HASH_MAP_FOREACH_PTR(&module_registry, module) {
1461 			add_next_index_string(return_value, module->name);
1462 		} ZEND_HASH_FOREACH_END();
1463 	}
1464 }
1465 /* }}} */
1466 
1467 /* {{{ Return an array containing the names and values of all defined constants */
ZEND_FUNCTION(get_defined_constants)1468 ZEND_FUNCTION(get_defined_constants)
1469 {
1470 	bool categorize = 0;
1471 
1472 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &categorize) == FAILURE) {
1473 		RETURN_THROWS();
1474 	}
1475 
1476 	array_init(return_value);
1477 
1478 	if (categorize) {
1479 		zend_constant *val;
1480 		int module_number;
1481 		zval *modules, const_val;
1482 		char **module_names;
1483 		zend_module_entry *module;
1484 		int i = 1;
1485 
1486 		modules = ecalloc(zend_hash_num_elements(&module_registry) + 2, sizeof(zval));
1487 		module_names = emalloc((zend_hash_num_elements(&module_registry) + 2) * sizeof(char *));
1488 
1489 		module_names[0] = "internal";
1490 		ZEND_HASH_MAP_FOREACH_PTR(&module_registry, module) {
1491 			module_names[module->module_number] = (char *)module->name;
1492 			i++;
1493 		} ZEND_HASH_FOREACH_END();
1494 		module_names[i] = "user";
1495 
1496 		ZEND_HASH_MAP_FOREACH_PTR(EG(zend_constants), val) {
1497 			if (!val->name) {
1498 				/* skip special constants */
1499 				continue;
1500 			}
1501 
1502 			if (ZEND_CONSTANT_MODULE_NUMBER(val) == PHP_USER_CONSTANT) {
1503 				module_number = i;
1504 			} else if (ZEND_CONSTANT_MODULE_NUMBER(val) > i) {
1505 				/* should not happen */
1506 				continue;
1507 			} else {
1508 				module_number = ZEND_CONSTANT_MODULE_NUMBER(val);
1509 			}
1510 
1511 			if (Z_TYPE(modules[module_number]) == IS_UNDEF) {
1512 				array_init(&modules[module_number]);
1513 				add_assoc_zval(return_value, module_names[module_number], &modules[module_number]);
1514 			}
1515 
1516 			ZVAL_COPY_OR_DUP(&const_val, &val->value);
1517 			zend_hash_add_new(Z_ARRVAL(modules[module_number]), val->name, &const_val);
1518 		} ZEND_HASH_FOREACH_END();
1519 
1520 		efree(module_names);
1521 		efree(modules);
1522 	} else {
1523 		zend_constant *constant;
1524 		zval const_val;
1525 
1526 		ZEND_HASH_MAP_FOREACH_PTR(EG(zend_constants), constant) {
1527 			if (!constant->name) {
1528 				/* skip special constants */
1529 				continue;
1530 			}
1531 			ZVAL_COPY_OR_DUP(&const_val, &constant->value);
1532 			zend_hash_add_new(Z_ARRVAL_P(return_value), constant->name, &const_val);
1533 		} ZEND_HASH_FOREACH_END();
1534 	}
1535 }
1536 /* }}} */
1537 
debug_backtrace_get_args(zend_execute_data * call,zval * arg_array)1538 static void debug_backtrace_get_args(zend_execute_data *call, zval *arg_array) /* {{{ */
1539 {
1540 	uint32_t num_args = ZEND_CALL_NUM_ARGS(call);
1541 
1542 	if (num_args) {
1543 		uint32_t i = 0;
1544 		zval *p = ZEND_CALL_ARG(call, 1);
1545 
1546 		array_init_size(arg_array, num_args);
1547 		zend_hash_real_init_packed(Z_ARRVAL_P(arg_array));
1548 		ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(arg_array)) {
1549 			if (call->func->type == ZEND_USER_FUNCTION) {
1550 				uint32_t first_extra_arg = MIN(num_args, call->func->op_array.num_args);
1551 
1552 				if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_HAS_SYMBOL_TABLE)) {
1553 					/* In case of attached symbol_table, values on stack may be invalid
1554 					 * and we have to access them through symbol_table
1555 					 * See: https://bugs.php.net/bug.php?id=73156
1556 					 */
1557 					while (i < first_extra_arg) {
1558 						zend_string *arg_name = call->func->op_array.vars[i];
1559 						zval original_arg;
1560 						zval *arg = zend_hash_find_ex_ind(call->symbol_table, arg_name, 1);
1561 						zend_attribute *attribute = zend_get_parameter_attribute_str(
1562 							call->func->common.attributes,
1563 							"sensitiveparameter",
1564 							sizeof("sensitiveparameter") - 1,
1565 							i
1566 						);
1567 
1568 						bool is_sensitive = attribute != NULL;
1569 
1570 						if (arg) {
1571 							ZVAL_DEREF(arg);
1572 							ZVAL_COPY_VALUE(&original_arg, arg);
1573 						} else {
1574 							ZVAL_NULL(&original_arg);
1575 						}
1576 
1577 						if (is_sensitive) {
1578 							zval redacted_arg;
1579 							object_init_ex(&redacted_arg, zend_ce_sensitive_parameter_value);
1580 							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);
1581 							ZEND_HASH_FILL_SET(&redacted_arg);
1582 						} else {
1583 							Z_TRY_ADDREF_P(&original_arg);
1584 							ZEND_HASH_FILL_SET(&original_arg);
1585 						}
1586 
1587 						ZEND_HASH_FILL_NEXT();
1588 						i++;
1589 					}
1590 				} else {
1591 					while (i < first_extra_arg) {
1592 						zval original_arg;
1593 						zend_attribute *attribute = zend_get_parameter_attribute_str(
1594 							call->func->common.attributes,
1595 							"sensitiveparameter",
1596 							sizeof("sensitiveparameter") - 1,
1597 							i
1598 						);
1599 						bool is_sensitive = attribute != NULL;
1600 
1601 						if (EXPECTED(Z_TYPE_INFO_P(p) != IS_UNDEF)) {
1602 							zval *arg = p;
1603 							ZVAL_DEREF(arg);
1604 							ZVAL_COPY_VALUE(&original_arg, arg);
1605 						} else {
1606 							ZVAL_NULL(&original_arg);
1607 						}
1608 
1609 						if (is_sensitive) {
1610 							zval redacted_arg;
1611 							object_init_ex(&redacted_arg, zend_ce_sensitive_parameter_value);
1612 							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);
1613 							ZEND_HASH_FILL_SET(&redacted_arg);
1614 						} else {
1615 							Z_TRY_ADDREF_P(&original_arg);
1616 							ZEND_HASH_FILL_SET(&original_arg);
1617 						}
1618 
1619 						ZEND_HASH_FILL_NEXT();
1620 						p++;
1621 						i++;
1622 					}
1623 				}
1624 				p = ZEND_CALL_VAR_NUM(call, call->func->op_array.last_var + call->func->op_array.T);
1625 			}
1626 
1627 			while (i < num_args) {
1628 				zval original_arg;
1629 				bool is_sensitive = 0;
1630 
1631 				if (i < call->func->common.num_args || call->func->common.fn_flags & ZEND_ACC_VARIADIC) {
1632 					zend_attribute *attribute = zend_get_parameter_attribute_str(
1633 						call->func->common.attributes,
1634 						"sensitiveparameter",
1635 						sizeof("sensitiveparameter") - 1,
1636 						MIN(i, call->func->common.num_args)
1637 					);
1638 					is_sensitive = attribute != NULL;
1639 				}
1640 
1641 				if (EXPECTED(Z_TYPE_INFO_P(p) != IS_UNDEF)) {
1642 					zval *arg = p;
1643 					ZVAL_DEREF(arg);
1644 					ZVAL_COPY_VALUE(&original_arg, arg);
1645 				} else {
1646 					ZVAL_NULL(&original_arg);
1647 				}
1648 
1649 				if (is_sensitive) {
1650 					zval redacted_arg;
1651 					object_init_ex(&redacted_arg, zend_ce_sensitive_parameter_value);
1652 					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);
1653 					ZEND_HASH_FILL_SET(&redacted_arg);
1654 				} else {
1655 					Z_TRY_ADDREF_P(&original_arg);
1656 					ZEND_HASH_FILL_SET(&original_arg);
1657 				}
1658 
1659 				ZEND_HASH_FILL_NEXT();
1660 				p++;
1661 				i++;
1662 			}
1663 		} ZEND_HASH_FILL_END();
1664 		Z_ARRVAL_P(arg_array)->nNumOfElements = num_args;
1665 	} else {
1666 		ZVAL_EMPTY_ARRAY(arg_array);
1667 	}
1668 
1669 	if (ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS) {
1670 		zend_string *name;
1671 		zval *arg;
1672 		SEPARATE_ARRAY(arg_array);
1673 		ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(call->extra_named_params, name, arg) {
1674 			ZVAL_DEREF(arg);
1675 			Z_TRY_ADDREF_P(arg);
1676 			zend_hash_add_new(Z_ARRVAL_P(arg_array), name, arg);
1677 		} ZEND_HASH_FOREACH_END();
1678 	}
1679 }
1680 /* }}} */
1681 
1682 /* {{{ */
ZEND_FUNCTION(debug_print_backtrace)1683 ZEND_FUNCTION(debug_print_backtrace)
1684 {
1685 	zend_long options = 0;
1686 	zend_long limit = 0;
1687 	zval backtrace;
1688 
1689 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|ll", &options, &limit) == FAILURE) {
1690 		RETURN_THROWS();
1691 	}
1692 
1693 	zend_fetch_debug_backtrace(&backtrace, 1, options, limit);
1694 	ZEND_ASSERT(Z_TYPE(backtrace) == IS_ARRAY);
1695 
1696 	zend_string *str = zend_trace_to_string(Z_ARRVAL(backtrace), /* include_main */ false);
1697 	ZEND_WRITE(ZSTR_VAL(str), ZSTR_LEN(str));
1698 	zend_string_release(str);
1699 	zval_ptr_dtor(&backtrace);
1700 }
1701 
1702 /* }}} */
1703 
zend_fetch_debug_backtrace(zval * return_value,int skip_last,int options,int limit)1704 ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int options, int limit) /* {{{ */
1705 {
1706 	zend_execute_data *call;
1707 	zend_object *object;
1708 	bool fake_frame = 0;
1709 	int lineno, frameno = 0;
1710 	zend_function *func;
1711 	zend_string *filename;
1712 	zend_string *include_filename = NULL;
1713 	zval tmp;
1714 	HashTable *stack_frame;
1715 
1716 	array_init(return_value);
1717 
1718 	call = EG(current_execute_data);
1719 	if (!call) {
1720 		return;
1721 	}
1722 
1723 	if (skip_last) {
1724 		/* skip debug_backtrace() */
1725 		call = call->prev_execute_data;
1726 	}
1727 
1728 	while (call && (limit == 0 || frameno < limit)) {
1729 		zend_execute_data *prev = call->prev_execute_data;
1730 
1731 		if (!prev) {
1732 			/* add frame for a handler call without {main} code */
1733 			if (EXPECTED((ZEND_CALL_INFO(call) & ZEND_CALL_TOP_FUNCTION) == 0)) {
1734 				break;
1735 			}
1736 		} else if (UNEXPECTED((ZEND_CALL_INFO(call) & ZEND_CALL_GENERATOR) != 0)) {
1737 			prev = zend_generator_check_placeholder_frame(prev);
1738 		}
1739 
1740 		frameno++;
1741 
1742 		/* We use _zend_hash_append*() and the array must be preallocated */
1743 		stack_frame = zend_new_array(8);
1744 		zend_hash_real_init_mixed(stack_frame);
1745 
1746 		if (prev && prev->func && ZEND_USER_CODE(prev->func->common.type)) {
1747 			filename = prev->func->op_array.filename;
1748 			if (prev->opline->opcode == ZEND_HANDLE_EXCEPTION) {
1749 				if (EG(opline_before_exception)) {
1750 					lineno = EG(opline_before_exception)->lineno;
1751 				} else {
1752 					lineno = prev->func->op_array.line_end;
1753 				}
1754 			} else {
1755 				lineno = prev->opline->lineno;
1756 			}
1757 			ZVAL_STR_COPY(&tmp, filename);
1758 			_zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_FILE), &tmp, 1);
1759 			ZVAL_LONG(&tmp, lineno);
1760 			_zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_LINE), &tmp, 1);
1761 
1762 			/* try to fetch args only if an FCALL was just made - elsewise we're in the middle of a function
1763 			 * and debug_backtrace() might have been called by the error_handler. in this case we don't
1764 			 * want to pop anything of the argument-stack */
1765 		} else {
1766 			zend_execute_data *prev_call = prev;
1767 
1768 			while (prev_call) {
1769 				zend_execute_data *prev;
1770 
1771 				if (prev_call &&
1772 					prev_call->func &&
1773 					!ZEND_USER_CODE(prev_call->func->common.type) &&
1774 					!(prev_call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
1775 					break;
1776 				}
1777 
1778 				prev = prev_call->prev_execute_data;
1779 				if (prev && prev->func && ZEND_USER_CODE(prev->func->common.type)) {
1780 					ZVAL_STR_COPY(&tmp, prev->func->op_array.filename);
1781 					_zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_FILE), &tmp, 1);
1782 					ZVAL_LONG(&tmp, prev->opline->lineno);
1783 					_zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_LINE), &tmp, 1);
1784 					break;
1785 				}
1786 				prev_call = prev;
1787 			}
1788 			filename = NULL;
1789 		}
1790 
1791 		func = call->func;
1792 		if (!fake_frame && func->common.function_name) {
1793 			ZVAL_STR_COPY(&tmp, func->common.function_name);
1794 			_zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_FUNCTION), &tmp, 1);
1795 
1796 			if (Z_TYPE(call->This) == IS_OBJECT) {
1797 				object = Z_OBJ(call->This);
1798 				/* $this may be passed into regular internal functions */
1799 				if (func->common.scope) {
1800 					ZVAL_STR_COPY(&tmp, func->common.scope->name);
1801 				} else if (object->handlers->get_class_name == zend_std_get_class_name) {
1802 					ZVAL_STR_COPY(&tmp, object->ce->name);
1803 				} else {
1804 					ZVAL_STR(&tmp, object->handlers->get_class_name(object));
1805 				}
1806 				_zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_CLASS), &tmp, 1);
1807 				if ((options & DEBUG_BACKTRACE_PROVIDE_OBJECT) != 0) {
1808 					ZVAL_OBJ_COPY(&tmp, object);
1809 					_zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_OBJECT), &tmp, 1);
1810 				}
1811 
1812 				ZVAL_INTERNED_STR(&tmp, ZSTR_KNOWN(ZEND_STR_OBJECT_OPERATOR));
1813 				_zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_TYPE), &tmp, 1);
1814 			} else if (func->common.scope) {
1815 				ZVAL_STR_COPY(&tmp, func->common.scope->name);
1816 				_zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_CLASS), &tmp, 1);
1817 				ZVAL_INTERNED_STR(&tmp, ZSTR_KNOWN(ZEND_STR_PAAMAYIM_NEKUDOTAYIM));
1818 				_zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_TYPE), &tmp, 1);
1819 			}
1820 
1821 			if ((options & DEBUG_BACKTRACE_IGNORE_ARGS) == 0 &&
1822 				func->type != ZEND_EVAL_CODE) {
1823 
1824 				debug_backtrace_get_args(call, &tmp);
1825 				_zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_ARGS), &tmp, 1);
1826 			}
1827 		} else {
1828 			/* i know this is kinda ugly, but i'm trying to avoid extra cycles in the main execution loop */
1829 			bool build_filename_arg = 1;
1830 			zend_string *pseudo_function_name;
1831 			uint32_t include_kind = 0;
1832 			if (prev && prev->func && ZEND_USER_CODE(prev->func->common.type) && prev->opline->opcode == ZEND_INCLUDE_OR_EVAL) {
1833 				include_kind = prev->opline->extended_value;
1834 			}
1835 
1836 			switch (include_kind) {
1837 				case ZEND_EVAL:
1838 					pseudo_function_name = ZSTR_KNOWN(ZEND_STR_EVAL);
1839 					build_filename_arg = 0;
1840 					break;
1841 				case ZEND_INCLUDE:
1842 					pseudo_function_name = ZSTR_KNOWN(ZEND_STR_INCLUDE);
1843 					break;
1844 				case ZEND_REQUIRE:
1845 					pseudo_function_name = ZSTR_KNOWN(ZEND_STR_REQUIRE);
1846 					break;
1847 				case ZEND_INCLUDE_ONCE:
1848 					pseudo_function_name = ZSTR_KNOWN(ZEND_STR_INCLUDE_ONCE);
1849 					break;
1850 				case ZEND_REQUIRE_ONCE:
1851 					pseudo_function_name = ZSTR_KNOWN(ZEND_STR_REQUIRE_ONCE);
1852 					break;
1853 				default:
1854 					/* Skip dummy frame unless it is needed to preserve filename/lineno info. */
1855 					if (!filename) {
1856 						zend_array_destroy(stack_frame);
1857 						goto skip_frame;
1858 					}
1859 
1860 					pseudo_function_name = ZSTR_KNOWN(ZEND_STR_UNKNOWN);
1861 					build_filename_arg = 0;
1862 					break;
1863 			}
1864 
1865 			if (build_filename_arg && include_filename) {
1866 				zval arg_array;
1867 
1868 				array_init(&arg_array);
1869 
1870 				/* include_filename always points to the last filename of the last last called-function.
1871 				   if we have called include in the frame above - this is the file we have included.
1872 				 */
1873 
1874 				ZVAL_STR_COPY(&tmp, include_filename);
1875 				zend_hash_next_index_insert_new(Z_ARRVAL(arg_array), &tmp);
1876 				_zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_ARGS), &arg_array, 1);
1877 			}
1878 
1879 			ZVAL_INTERNED_STR(&tmp, pseudo_function_name);
1880 			_zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_FUNCTION), &tmp, 1);
1881 		}
1882 
1883 		ZVAL_ARR(&tmp, stack_frame);
1884 		zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp);
1885 
1886 skip_frame:
1887 		if (UNEXPECTED(ZEND_CALL_KIND(call) == ZEND_CALL_TOP_FUNCTION)
1888 		 && !fake_frame
1889 		 && prev
1890 		 && prev->func
1891 		 && ZEND_USER_CODE(prev->func->common.type)
1892 		 && prev->opline->opcode == ZEND_INCLUDE_OR_EVAL) {
1893 			fake_frame = 1;
1894 		} else {
1895 			fake_frame = 0;
1896 			include_filename = filename;
1897 			call = prev;
1898 		}
1899 	}
1900 }
1901 /* }}} */
1902 
1903 /* {{{ Return backtrace as array */
ZEND_FUNCTION(debug_backtrace)1904 ZEND_FUNCTION(debug_backtrace)
1905 {
1906 	zend_long options = DEBUG_BACKTRACE_PROVIDE_OBJECT;
1907 	zend_long limit = 0;
1908 
1909 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "|ll", &options, &limit) == FAILURE) {
1910 		RETURN_THROWS();
1911 	}
1912 
1913 	zend_fetch_debug_backtrace(return_value, 1, options, limit);
1914 }
1915 /* }}} */
1916 
1917 /* {{{ Returns true if the named extension is loaded */
ZEND_FUNCTION(extension_loaded)1918 ZEND_FUNCTION(extension_loaded)
1919 {
1920 	zend_string *extension_name;
1921 	zend_string *lcname;
1922 
1923 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &extension_name) == FAILURE) {
1924 		RETURN_THROWS();
1925 	}
1926 
1927 	lcname = zend_string_tolower(extension_name);
1928 	if (zend_hash_exists(&module_registry, lcname)) {
1929 		RETVAL_TRUE;
1930 	} else {
1931 		RETVAL_FALSE;
1932 	}
1933 	zend_string_release_ex(lcname, 0);
1934 }
1935 /* }}} */
1936 
1937 /* {{{ Returns an array with the names of functions belonging to the named extension */
ZEND_FUNCTION(get_extension_funcs)1938 ZEND_FUNCTION(get_extension_funcs)
1939 {
1940 	zend_string *extension_name;
1941 	zend_string *lcname;
1942 	bool array;
1943 	zend_module_entry *module;
1944 	zend_function *zif;
1945 
1946 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &extension_name) == FAILURE) {
1947 		RETURN_THROWS();
1948 	}
1949 	if (strncasecmp(ZSTR_VAL(extension_name), "zend", sizeof("zend"))) {
1950 		lcname = zend_string_tolower(extension_name);
1951 		module = zend_hash_find_ptr(&module_registry, lcname);
1952 		zend_string_release_ex(lcname, 0);
1953 	} else {
1954 		module = zend_hash_str_find_ptr(&module_registry, "core", sizeof("core") - 1);
1955 	}
1956 
1957 	if (!module) {
1958 		RETURN_FALSE;
1959 	}
1960 
1961 	if (module->functions) {
1962 		/* avoid BC break, if functions list is empty, will return an empty array */
1963 		array_init(return_value);
1964 		array = 1;
1965 	} else {
1966 		array = 0;
1967 	}
1968 
1969 	ZEND_HASH_MAP_FOREACH_PTR(CG(function_table), zif) {
1970 		if (zif->common.type == ZEND_INTERNAL_FUNCTION
1971 			&& zif->internal_function.module == module) {
1972 			if (!array) {
1973 				array_init(return_value);
1974 				array = 1;
1975 			}
1976 			add_next_index_str(return_value, zend_string_copy(zif->common.function_name));
1977 		}
1978 	} ZEND_HASH_FOREACH_END();
1979 
1980 	if (!array) {
1981 		RETURN_FALSE;
1982 	}
1983 }
1984 /* }}} */
1985