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