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