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