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