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