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