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