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