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 (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 (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 (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_MAP_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 char *message;
1112 size_t message_len;
1113
1114 if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &message, &message_len, &error_type) == FAILURE) {
1115 RETURN_THROWS();
1116 }
1117
1118 switch (error_type) {
1119 case E_USER_ERROR:
1120 case E_USER_WARNING:
1121 case E_USER_NOTICE:
1122 case E_USER_DEPRECATED:
1123 break;
1124 default:
1125 zend_argument_value_error(2, "must be one of E_USER_ERROR, E_USER_WARNING, E_USER_NOTICE,"
1126 " or E_USER_DEPRECATED");
1127 RETURN_THROWS();
1128 break;
1129 }
1130
1131 zend_error((int)error_type, "%s", message);
1132 // TODO Change to void
1133 RETURN_TRUE;
1134 }
1135 /* }}} */
1136
1137 /* {{{ Sets a user-defined error handler function. Returns the previously defined error handler, or false on error */
ZEND_FUNCTION(set_error_handler)1138 ZEND_FUNCTION(set_error_handler)
1139 {
1140 zend_fcall_info fci;
1141 zend_fcall_info_cache fcc;
1142 zend_long error_type = E_ALL;
1143
1144 ZEND_PARSE_PARAMETERS_START(1, 2)
1145 Z_PARAM_FUNC_OR_NULL(fci, fcc)
1146 Z_PARAM_OPTIONAL
1147 Z_PARAM_LONG(error_type)
1148 ZEND_PARSE_PARAMETERS_END();
1149
1150 if (Z_TYPE(EG(user_error_handler)) != IS_UNDEF) {
1151 ZVAL_COPY(return_value, &EG(user_error_handler));
1152 }
1153
1154 zend_stack_push(&EG(user_error_handlers_error_reporting), &EG(user_error_handler_error_reporting));
1155 zend_stack_push(&EG(user_error_handlers), &EG(user_error_handler));
1156
1157 if (!ZEND_FCI_INITIALIZED(fci)) { /* unset user-defined handler */
1158 ZVAL_UNDEF(&EG(user_error_handler));
1159 return;
1160 }
1161
1162 ZVAL_COPY(&EG(user_error_handler), &(fci.function_name));
1163 EG(user_error_handler_error_reporting) = (int)error_type;
1164 }
1165 /* }}} */
1166
1167 /* {{{ Restores the previously defined error handler function */
ZEND_FUNCTION(restore_error_handler)1168 ZEND_FUNCTION(restore_error_handler)
1169 {
1170 ZEND_PARSE_PARAMETERS_NONE();
1171
1172 if (Z_TYPE(EG(user_error_handler)) != IS_UNDEF) {
1173 zval zeh;
1174
1175 ZVAL_COPY_VALUE(&zeh, &EG(user_error_handler));
1176 ZVAL_UNDEF(&EG(user_error_handler));
1177 zval_ptr_dtor(&zeh);
1178 }
1179
1180 if (zend_stack_is_empty(&EG(user_error_handlers))) {
1181 ZVAL_UNDEF(&EG(user_error_handler));
1182 } else {
1183 zval *tmp;
1184 EG(user_error_handler_error_reporting) = zend_stack_int_top(&EG(user_error_handlers_error_reporting));
1185 zend_stack_del_top(&EG(user_error_handlers_error_reporting));
1186 tmp = zend_stack_top(&EG(user_error_handlers));
1187 ZVAL_COPY_VALUE(&EG(user_error_handler), tmp);
1188 zend_stack_del_top(&EG(user_error_handlers));
1189 }
1190
1191 // TODO Change to void
1192 RETURN_TRUE;
1193 }
1194 /* }}} */
1195
1196 /* {{{ Sets a user-defined exception handler function. Returns the previously defined exception handler, or false on error */
ZEND_FUNCTION(set_exception_handler)1197 ZEND_FUNCTION(set_exception_handler)
1198 {
1199 zend_fcall_info fci;
1200 zend_fcall_info_cache fcc;
1201
1202 ZEND_PARSE_PARAMETERS_START(1, 1)
1203 Z_PARAM_FUNC_OR_NULL(fci, fcc)
1204 ZEND_PARSE_PARAMETERS_END();
1205
1206 if (Z_TYPE(EG(user_exception_handler)) != IS_UNDEF) {
1207 ZVAL_COPY(return_value, &EG(user_exception_handler));
1208 }
1209
1210 zend_stack_push(&EG(user_exception_handlers), &EG(user_exception_handler));
1211
1212 if (!ZEND_FCI_INITIALIZED(fci)) { /* unset user-defined handler */
1213 ZVAL_UNDEF(&EG(user_exception_handler));
1214 return;
1215 }
1216
1217 ZVAL_COPY(&EG(user_exception_handler), &(fci.function_name));
1218 }
1219 /* }}} */
1220
1221 /* {{{ Restores the previously defined exception handler function */
ZEND_FUNCTION(restore_exception_handler)1222 ZEND_FUNCTION(restore_exception_handler)
1223 {
1224 ZEND_PARSE_PARAMETERS_NONE();
1225
1226 if (Z_TYPE(EG(user_exception_handler)) != IS_UNDEF) {
1227 zval_ptr_dtor(&EG(user_exception_handler));
1228 }
1229 if (zend_stack_is_empty(&EG(user_exception_handlers))) {
1230 ZVAL_UNDEF(&EG(user_exception_handler));
1231 } else {
1232 zval *tmp = zend_stack_top(&EG(user_exception_handlers));
1233 ZVAL_COPY_VALUE(&EG(user_exception_handler), tmp);
1234 zend_stack_del_top(&EG(user_exception_handlers));
1235 }
1236
1237 // TODO Change to void
1238 RETURN_TRUE;
1239 }
1240 /* }}} */
1241
get_declared_class_impl(INTERNAL_FUNCTION_PARAMETERS,int flags)1242 static inline void get_declared_class_impl(INTERNAL_FUNCTION_PARAMETERS, int flags) /* {{{ */
1243 {
1244 zend_string *key;
1245 zval *zv;
1246 zend_class_entry *ce;
1247
1248 ZEND_PARSE_PARAMETERS_NONE();
1249
1250 array_init(return_value);
1251 zend_hash_real_init_packed(Z_ARRVAL_P(return_value));
1252 ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
1253 ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(EG(class_table), key, zv) {
1254 ce = Z_PTR_P(zv);
1255 if ((ce->ce_flags & (ZEND_ACC_LINKED|ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT)) == flags
1256 && key
1257 && ZSTR_VAL(key)[0] != 0) {
1258 ZEND_HASH_FILL_GROW();
1259 if (EXPECTED(Z_TYPE_P(zv) == IS_PTR)) {
1260 ZEND_HASH_FILL_SET_STR_COPY(ce->name);
1261 } else {
1262 ZEND_ASSERT(Z_TYPE_P(zv) == IS_ALIAS_PTR);
1263 ZEND_HASH_FILL_SET_STR_COPY(key);
1264 }
1265 ZEND_HASH_FILL_NEXT();
1266 }
1267 } ZEND_HASH_FOREACH_END();
1268 } ZEND_HASH_FILL_END();
1269 }
1270 /* {{{ */
1271
1272 /* {{{ Returns an array of all declared traits. */
ZEND_FUNCTION(get_declared_traits)1273 ZEND_FUNCTION(get_declared_traits)
1274 {
1275 get_declared_class_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_LINKED | ZEND_ACC_TRAIT);
1276 }
1277 /* }}} */
1278
1279 /* {{{ Returns an array of all declared classes. */
ZEND_FUNCTION(get_declared_classes)1280 ZEND_FUNCTION(get_declared_classes)
1281 {
1282 get_declared_class_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_LINKED);
1283 }
1284 /* }}} */
1285
1286 /* {{{ Returns an array of all declared interfaces. */
ZEND_FUNCTION(get_declared_interfaces)1287 ZEND_FUNCTION(get_declared_interfaces)
1288 {
1289 get_declared_class_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_LINKED | ZEND_ACC_INTERFACE);
1290 }
1291 /* }}} */
1292
1293 /* {{{ Returns an array of all defined functions */
ZEND_FUNCTION(get_defined_functions)1294 ZEND_FUNCTION(get_defined_functions)
1295 {
1296 zval internal, user;
1297 zend_string *key;
1298 zend_function *func;
1299 bool exclude_disabled = 1;
1300
1301 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &exclude_disabled) == FAILURE) {
1302 RETURN_THROWS();
1303 }
1304
1305 if (exclude_disabled == 0) {
1306 zend_error(E_DEPRECATED,
1307 "get_defined_functions(): Setting $exclude_disabled to false has no effect");
1308 }
1309
1310 array_init(&internal);
1311 array_init(&user);
1312 array_init(return_value);
1313
1314 ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(EG(function_table), key, func) {
1315 if (key && ZSTR_VAL(key)[0] != 0) {
1316 if (func->type == ZEND_INTERNAL_FUNCTION) {
1317 add_next_index_str(&internal, zend_string_copy(key));
1318 } else if (func->type == ZEND_USER_FUNCTION) {
1319 add_next_index_str(&user, zend_string_copy(key));
1320 }
1321 }
1322 } ZEND_HASH_FOREACH_END();
1323
1324 zend_hash_str_add_new(Z_ARRVAL_P(return_value), "internal", sizeof("internal")-1, &internal);
1325 zend_hash_str_add_new(Z_ARRVAL_P(return_value), "user", sizeof("user")-1, &user);
1326 }
1327 /* }}} */
1328
1329 /* {{{ Returns an associative array of names and values of all currently defined variable names (variables in the current scope) */
ZEND_FUNCTION(get_defined_vars)1330 ZEND_FUNCTION(get_defined_vars)
1331 {
1332 zend_array *symbol_table;
1333
1334 ZEND_PARSE_PARAMETERS_NONE();
1335
1336 if (zend_forbid_dynamic_call() == FAILURE) {
1337 return;
1338 }
1339
1340 symbol_table = zend_rebuild_symbol_table();
1341 if (UNEXPECTED(symbol_table == NULL)) {
1342 RETURN_EMPTY_ARRAY();
1343 }
1344
1345 RETURN_ARR(zend_array_dup(symbol_table));
1346 }
1347 /* }}} */
1348
1349 #if ZEND_DEBUG && defined(ZTS)
ZEND_FUNCTION(zend_thread_id)1350 ZEND_FUNCTION(zend_thread_id)
1351 {
1352 ZEND_PARSE_PARAMETERS_NONE();
1353
1354 RETURN_LONG((zend_long)tsrm_thread_id());
1355 }
1356 #endif
1357
1358 /* {{{ Get the resource type name for a given resource */
ZEND_FUNCTION(get_resource_type)1359 ZEND_FUNCTION(get_resource_type)
1360 {
1361 const char *resource_type;
1362 zval *z_resource_type;
1363
1364 if (zend_parse_parameters(ZEND_NUM_ARGS(), "r", &z_resource_type) == FAILURE) {
1365 RETURN_THROWS();
1366 }
1367
1368 resource_type = zend_rsrc_list_get_rsrc_type(Z_RES_P(z_resource_type));
1369 if (resource_type) {
1370 RETURN_STRING(resource_type);
1371 } else {
1372 RETURN_STRING("Unknown");
1373 }
1374 }
1375 /* }}} */
1376
1377 /* {{{ Get the resource ID for a given resource */
ZEND_FUNCTION(get_resource_id)1378 ZEND_FUNCTION(get_resource_id)
1379 {
1380 zval *resource;
1381
1382 ZEND_PARSE_PARAMETERS_START(1, 1)
1383 Z_PARAM_RESOURCE(resource)
1384 ZEND_PARSE_PARAMETERS_END();
1385
1386 RETURN_LONG(Z_RES_HANDLE_P(resource));
1387 }
1388 /* }}} */
1389
1390 /* {{{ Get an array with all active resources */
ZEND_FUNCTION(get_resources)1391 ZEND_FUNCTION(get_resources)
1392 {
1393 zend_string *type = NULL;
1394 zend_string *key;
1395 zend_ulong index;
1396 zval *val;
1397
1398 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|S!", &type) == FAILURE) {
1399 RETURN_THROWS();
1400 }
1401
1402 if (!type) {
1403 array_init(return_value);
1404 ZEND_HASH_FOREACH_KEY_VAL(&EG(regular_list), index, key, val) {
1405 if (!key) {
1406 Z_ADDREF_P(val);
1407 zend_hash_index_add_new(Z_ARRVAL_P(return_value), index, val);
1408 }
1409 } ZEND_HASH_FOREACH_END();
1410 } else if (zend_string_equals_literal(type, "Unknown")) {
1411 array_init(return_value);
1412 ZEND_HASH_FOREACH_KEY_VAL(&EG(regular_list), index, key, val) {
1413 if (!key && Z_RES_TYPE_P(val) <= 0) {
1414 Z_ADDREF_P(val);
1415 zend_hash_index_add_new(Z_ARRVAL_P(return_value), index, val);
1416 }
1417 } ZEND_HASH_FOREACH_END();
1418 } else {
1419 int id = zend_fetch_list_dtor_id(ZSTR_VAL(type));
1420
1421 if (id <= 0) {
1422 zend_argument_value_error(1, "must be a valid resource type");
1423 RETURN_THROWS();
1424 }
1425
1426 array_init(return_value);
1427 ZEND_HASH_FOREACH_KEY_VAL(&EG(regular_list), index, key, val) {
1428 if (!key && Z_RES_TYPE_P(val) == id) {
1429 Z_ADDREF_P(val);
1430 zend_hash_index_add_new(Z_ARRVAL_P(return_value), index, val);
1431 }
1432 } ZEND_HASH_FOREACH_END();
1433 }
1434 }
1435 /* }}} */
1436
add_zendext_info(zend_extension * ext,void * arg)1437 static void add_zendext_info(zend_extension *ext, void *arg) /* {{{ */
1438 {
1439 zval *name_array = (zval *)arg;
1440 add_next_index_string(name_array, ext->name);
1441 }
1442 /* }}} */
1443
1444 /* {{{ Return an array containing names of loaded extensions */
ZEND_FUNCTION(get_loaded_extensions)1445 ZEND_FUNCTION(get_loaded_extensions)
1446 {
1447 bool zendext = 0;
1448
1449 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &zendext) == FAILURE) {
1450 RETURN_THROWS();
1451 }
1452
1453 array_init(return_value);
1454
1455 if (zendext) {
1456 zend_llist_apply_with_argument(&zend_extensions, (llist_apply_with_arg_func_t) add_zendext_info, return_value);
1457 } else {
1458 zend_module_entry *module;
1459
1460 ZEND_HASH_MAP_FOREACH_PTR(&module_registry, module) {
1461 add_next_index_string(return_value, module->name);
1462 } ZEND_HASH_FOREACH_END();
1463 }
1464 }
1465 /* }}} */
1466
1467 /* {{{ Return an array containing the names and values of all defined constants */
ZEND_FUNCTION(get_defined_constants)1468 ZEND_FUNCTION(get_defined_constants)
1469 {
1470 bool categorize = 0;
1471
1472 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &categorize) == FAILURE) {
1473 RETURN_THROWS();
1474 }
1475
1476 array_init(return_value);
1477
1478 if (categorize) {
1479 zend_constant *val;
1480 int module_number;
1481 zval *modules, const_val;
1482 char **module_names;
1483 zend_module_entry *module;
1484 int i = 1;
1485
1486 modules = ecalloc(zend_hash_num_elements(&module_registry) + 2, sizeof(zval));
1487 module_names = emalloc((zend_hash_num_elements(&module_registry) + 2) * sizeof(char *));
1488
1489 module_names[0] = "internal";
1490 ZEND_HASH_MAP_FOREACH_PTR(&module_registry, module) {
1491 module_names[module->module_number] = (char *)module->name;
1492 i++;
1493 } ZEND_HASH_FOREACH_END();
1494 module_names[i] = "user";
1495
1496 ZEND_HASH_MAP_FOREACH_PTR(EG(zend_constants), val) {
1497 if (!val->name) {
1498 /* skip special constants */
1499 continue;
1500 }
1501
1502 if (ZEND_CONSTANT_MODULE_NUMBER(val) == PHP_USER_CONSTANT) {
1503 module_number = i;
1504 } else if (ZEND_CONSTANT_MODULE_NUMBER(val) > i) {
1505 /* should not happen */
1506 continue;
1507 } else {
1508 module_number = ZEND_CONSTANT_MODULE_NUMBER(val);
1509 }
1510
1511 if (Z_TYPE(modules[module_number]) == IS_UNDEF) {
1512 array_init(&modules[module_number]);
1513 add_assoc_zval(return_value, module_names[module_number], &modules[module_number]);
1514 }
1515
1516 ZVAL_COPY_OR_DUP(&const_val, &val->value);
1517 zend_hash_add_new(Z_ARRVAL(modules[module_number]), val->name, &const_val);
1518 } ZEND_HASH_FOREACH_END();
1519
1520 efree(module_names);
1521 efree(modules);
1522 } else {
1523 zend_constant *constant;
1524 zval const_val;
1525
1526 ZEND_HASH_MAP_FOREACH_PTR(EG(zend_constants), constant) {
1527 if (!constant->name) {
1528 /* skip special constants */
1529 continue;
1530 }
1531 ZVAL_COPY_OR_DUP(&const_val, &constant->value);
1532 zend_hash_add_new(Z_ARRVAL_P(return_value), constant->name, &const_val);
1533 } ZEND_HASH_FOREACH_END();
1534 }
1535 }
1536 /* }}} */
1537
debug_backtrace_get_args(zend_execute_data * call,zval * arg_array)1538 static void debug_backtrace_get_args(zend_execute_data *call, zval *arg_array) /* {{{ */
1539 {
1540 uint32_t num_args = ZEND_CALL_NUM_ARGS(call);
1541
1542 if (num_args) {
1543 uint32_t i = 0;
1544 zval *p = ZEND_CALL_ARG(call, 1);
1545
1546 array_init_size(arg_array, num_args);
1547 zend_hash_real_init_packed(Z_ARRVAL_P(arg_array));
1548 ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(arg_array)) {
1549 if (call->func->type == ZEND_USER_FUNCTION) {
1550 uint32_t first_extra_arg = MIN(num_args, call->func->op_array.num_args);
1551
1552 if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_HAS_SYMBOL_TABLE)) {
1553 /* In case of attached symbol_table, values on stack may be invalid
1554 * and we have to access them through symbol_table
1555 * See: https://bugs.php.net/bug.php?id=73156
1556 */
1557 while (i < first_extra_arg) {
1558 zend_string *arg_name = call->func->op_array.vars[i];
1559 zval original_arg;
1560 zval *arg = zend_hash_find_ex_ind(call->symbol_table, arg_name, 1);
1561 zend_attribute *attribute = zend_get_parameter_attribute_str(
1562 call->func->common.attributes,
1563 "sensitiveparameter",
1564 sizeof("sensitiveparameter") - 1,
1565 i
1566 );
1567
1568 bool is_sensitive = attribute != NULL;
1569
1570 if (arg) {
1571 ZVAL_DEREF(arg);
1572 ZVAL_COPY_VALUE(&original_arg, arg);
1573 } else {
1574 ZVAL_NULL(&original_arg);
1575 }
1576
1577 if (is_sensitive) {
1578 zval redacted_arg;
1579 object_init_ex(&redacted_arg, zend_ce_sensitive_parameter_value);
1580 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);
1581 ZEND_HASH_FILL_SET(&redacted_arg);
1582 } else {
1583 Z_TRY_ADDREF_P(&original_arg);
1584 ZEND_HASH_FILL_SET(&original_arg);
1585 }
1586
1587 ZEND_HASH_FILL_NEXT();
1588 i++;
1589 }
1590 } else {
1591 while (i < first_extra_arg) {
1592 zval original_arg;
1593 zend_attribute *attribute = zend_get_parameter_attribute_str(
1594 call->func->common.attributes,
1595 "sensitiveparameter",
1596 sizeof("sensitiveparameter") - 1,
1597 i
1598 );
1599 bool is_sensitive = attribute != NULL;
1600
1601 if (EXPECTED(Z_TYPE_INFO_P(p) != IS_UNDEF)) {
1602 zval *arg = p;
1603 ZVAL_DEREF(arg);
1604 ZVAL_COPY_VALUE(&original_arg, arg);
1605 } else {
1606 ZVAL_NULL(&original_arg);
1607 }
1608
1609 if (is_sensitive) {
1610 zval redacted_arg;
1611 object_init_ex(&redacted_arg, zend_ce_sensitive_parameter_value);
1612 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);
1613 ZEND_HASH_FILL_SET(&redacted_arg);
1614 } else {
1615 Z_TRY_ADDREF_P(&original_arg);
1616 ZEND_HASH_FILL_SET(&original_arg);
1617 }
1618
1619 ZEND_HASH_FILL_NEXT();
1620 p++;
1621 i++;
1622 }
1623 }
1624 p = ZEND_CALL_VAR_NUM(call, call->func->op_array.last_var + call->func->op_array.T);
1625 }
1626
1627 while (i < num_args) {
1628 zval original_arg;
1629 bool is_sensitive = 0;
1630
1631 if (i < call->func->common.num_args || call->func->common.fn_flags & ZEND_ACC_VARIADIC) {
1632 zend_attribute *attribute = zend_get_parameter_attribute_str(
1633 call->func->common.attributes,
1634 "sensitiveparameter",
1635 sizeof("sensitiveparameter") - 1,
1636 MIN(i, call->func->common.num_args)
1637 );
1638 is_sensitive = attribute != NULL;
1639 }
1640
1641 if (EXPECTED(Z_TYPE_INFO_P(p) != IS_UNDEF)) {
1642 zval *arg = p;
1643 ZVAL_DEREF(arg);
1644 ZVAL_COPY_VALUE(&original_arg, arg);
1645 } else {
1646 ZVAL_NULL(&original_arg);
1647 }
1648
1649 if (is_sensitive) {
1650 zval redacted_arg;
1651 object_init_ex(&redacted_arg, zend_ce_sensitive_parameter_value);
1652 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);
1653 ZEND_HASH_FILL_SET(&redacted_arg);
1654 } else {
1655 Z_TRY_ADDREF_P(&original_arg);
1656 ZEND_HASH_FILL_SET(&original_arg);
1657 }
1658
1659 ZEND_HASH_FILL_NEXT();
1660 p++;
1661 i++;
1662 }
1663 } ZEND_HASH_FILL_END();
1664 Z_ARRVAL_P(arg_array)->nNumOfElements = num_args;
1665 } else {
1666 ZVAL_EMPTY_ARRAY(arg_array);
1667 }
1668
1669 if (ZEND_CALL_INFO(call) & ZEND_CALL_HAS_EXTRA_NAMED_PARAMS) {
1670 zend_string *name;
1671 zval *arg;
1672 SEPARATE_ARRAY(arg_array);
1673 ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(call->extra_named_params, name, arg) {
1674 ZVAL_DEREF(arg);
1675 Z_TRY_ADDREF_P(arg);
1676 zend_hash_add_new(Z_ARRVAL_P(arg_array), name, arg);
1677 } ZEND_HASH_FOREACH_END();
1678 }
1679 }
1680 /* }}} */
1681
1682 /* {{{ */
ZEND_FUNCTION(debug_print_backtrace)1683 ZEND_FUNCTION(debug_print_backtrace)
1684 {
1685 zend_long options = 0;
1686 zend_long limit = 0;
1687 zval backtrace;
1688
1689 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|ll", &options, &limit) == FAILURE) {
1690 RETURN_THROWS();
1691 }
1692
1693 zend_fetch_debug_backtrace(&backtrace, 1, options, limit);
1694 ZEND_ASSERT(Z_TYPE(backtrace) == IS_ARRAY);
1695
1696 zend_string *str = zend_trace_to_string(Z_ARRVAL(backtrace), /* include_main */ false);
1697 ZEND_WRITE(ZSTR_VAL(str), ZSTR_LEN(str));
1698 zend_string_release(str);
1699 zval_ptr_dtor(&backtrace);
1700 }
1701
1702 /* }}} */
1703
zend_fetch_debug_backtrace(zval * return_value,int skip_last,int options,int limit)1704 ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int options, int limit) /* {{{ */
1705 {
1706 zend_execute_data *call;
1707 zend_object *object;
1708 bool fake_frame = 0;
1709 int lineno, frameno = 0;
1710 zend_function *func;
1711 zend_string *filename;
1712 zend_string *include_filename = NULL;
1713 zval tmp;
1714 HashTable *stack_frame;
1715
1716 array_init(return_value);
1717
1718 call = EG(current_execute_data);
1719 if (!call) {
1720 return;
1721 }
1722
1723 if (skip_last) {
1724 /* skip debug_backtrace() */
1725 call = call->prev_execute_data;
1726 }
1727
1728 while (call && (limit == 0 || frameno < limit)) {
1729 zend_execute_data *prev = call->prev_execute_data;
1730
1731 if (!prev) {
1732 /* add frame for a handler call without {main} code */
1733 if (EXPECTED((ZEND_CALL_INFO(call) & ZEND_CALL_TOP_FUNCTION) == 0)) {
1734 break;
1735 }
1736 } else if (UNEXPECTED((ZEND_CALL_INFO(call) & ZEND_CALL_GENERATOR) != 0)) {
1737 prev = zend_generator_check_placeholder_frame(prev);
1738 }
1739
1740 frameno++;
1741
1742 /* We use _zend_hash_append*() and the array must be preallocated */
1743 stack_frame = zend_new_array(8);
1744 zend_hash_real_init_mixed(stack_frame);
1745
1746 if (prev && prev->func && ZEND_USER_CODE(prev->func->common.type)) {
1747 filename = prev->func->op_array.filename;
1748 if (prev->opline->opcode == ZEND_HANDLE_EXCEPTION) {
1749 if (EG(opline_before_exception)) {
1750 lineno = EG(opline_before_exception)->lineno;
1751 } else {
1752 lineno = prev->func->op_array.line_end;
1753 }
1754 } else {
1755 lineno = prev->opline->lineno;
1756 }
1757 ZVAL_STR_COPY(&tmp, filename);
1758 _zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_FILE), &tmp, 1);
1759 ZVAL_LONG(&tmp, lineno);
1760 _zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_LINE), &tmp, 1);
1761
1762 /* try to fetch args only if an FCALL was just made - elsewise we're in the middle of a function
1763 * and debug_backtrace() might have been called by the error_handler. in this case we don't
1764 * want to pop anything of the argument-stack */
1765 } else {
1766 zend_execute_data *prev_call = prev;
1767
1768 while (prev_call) {
1769 zend_execute_data *prev;
1770
1771 if (prev_call &&
1772 prev_call->func &&
1773 !ZEND_USER_CODE(prev_call->func->common.type) &&
1774 !(prev_call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
1775 break;
1776 }
1777
1778 prev = prev_call->prev_execute_data;
1779 if (prev && prev->func && ZEND_USER_CODE(prev->func->common.type)) {
1780 ZVAL_STR_COPY(&tmp, prev->func->op_array.filename);
1781 _zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_FILE), &tmp, 1);
1782 ZVAL_LONG(&tmp, prev->opline->lineno);
1783 _zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_LINE), &tmp, 1);
1784 break;
1785 }
1786 prev_call = prev;
1787 }
1788 filename = NULL;
1789 }
1790
1791 func = call->func;
1792 if (!fake_frame && func->common.function_name) {
1793 ZVAL_STR_COPY(&tmp, func->common.function_name);
1794 _zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_FUNCTION), &tmp, 1);
1795
1796 if (Z_TYPE(call->This) == IS_OBJECT) {
1797 object = Z_OBJ(call->This);
1798 /* $this may be passed into regular internal functions */
1799 if (func->common.scope) {
1800 ZVAL_STR_COPY(&tmp, func->common.scope->name);
1801 } else if (object->handlers->get_class_name == zend_std_get_class_name) {
1802 ZVAL_STR_COPY(&tmp, object->ce->name);
1803 } else {
1804 ZVAL_STR(&tmp, object->handlers->get_class_name(object));
1805 }
1806 _zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_CLASS), &tmp, 1);
1807 if ((options & DEBUG_BACKTRACE_PROVIDE_OBJECT) != 0) {
1808 ZVAL_OBJ_COPY(&tmp, object);
1809 _zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_OBJECT), &tmp, 1);
1810 }
1811
1812 ZVAL_INTERNED_STR(&tmp, ZSTR_KNOWN(ZEND_STR_OBJECT_OPERATOR));
1813 _zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_TYPE), &tmp, 1);
1814 } else if (func->common.scope) {
1815 ZVAL_STR_COPY(&tmp, func->common.scope->name);
1816 _zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_CLASS), &tmp, 1);
1817 ZVAL_INTERNED_STR(&tmp, ZSTR_KNOWN(ZEND_STR_PAAMAYIM_NEKUDOTAYIM));
1818 _zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_TYPE), &tmp, 1);
1819 }
1820
1821 if ((options & DEBUG_BACKTRACE_IGNORE_ARGS) == 0 &&
1822 func->type != ZEND_EVAL_CODE) {
1823
1824 debug_backtrace_get_args(call, &tmp);
1825 _zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_ARGS), &tmp, 1);
1826 }
1827 } else {
1828 /* i know this is kinda ugly, but i'm trying to avoid extra cycles in the main execution loop */
1829 bool build_filename_arg = 1;
1830 zend_string *pseudo_function_name;
1831 uint32_t include_kind = 0;
1832 if (prev && prev->func && ZEND_USER_CODE(prev->func->common.type) && prev->opline->opcode == ZEND_INCLUDE_OR_EVAL) {
1833 include_kind = prev->opline->extended_value;
1834 }
1835
1836 switch (include_kind) {
1837 case ZEND_EVAL:
1838 pseudo_function_name = ZSTR_KNOWN(ZEND_STR_EVAL);
1839 build_filename_arg = 0;
1840 break;
1841 case ZEND_INCLUDE:
1842 pseudo_function_name = ZSTR_KNOWN(ZEND_STR_INCLUDE);
1843 break;
1844 case ZEND_REQUIRE:
1845 pseudo_function_name = ZSTR_KNOWN(ZEND_STR_REQUIRE);
1846 break;
1847 case ZEND_INCLUDE_ONCE:
1848 pseudo_function_name = ZSTR_KNOWN(ZEND_STR_INCLUDE_ONCE);
1849 break;
1850 case ZEND_REQUIRE_ONCE:
1851 pseudo_function_name = ZSTR_KNOWN(ZEND_STR_REQUIRE_ONCE);
1852 break;
1853 default:
1854 /* Skip dummy frame unless it is needed to preserve filename/lineno info. */
1855 if (!filename) {
1856 zend_array_destroy(stack_frame);
1857 goto skip_frame;
1858 }
1859
1860 pseudo_function_name = ZSTR_KNOWN(ZEND_STR_UNKNOWN);
1861 build_filename_arg = 0;
1862 break;
1863 }
1864
1865 if (build_filename_arg && include_filename) {
1866 zval arg_array;
1867
1868 array_init(&arg_array);
1869
1870 /* include_filename always points to the last filename of the last last called-function.
1871 if we have called include in the frame above - this is the file we have included.
1872 */
1873
1874 ZVAL_STR_COPY(&tmp, include_filename);
1875 zend_hash_next_index_insert_new(Z_ARRVAL(arg_array), &tmp);
1876 _zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_ARGS), &arg_array, 1);
1877 }
1878
1879 ZVAL_INTERNED_STR(&tmp, pseudo_function_name);
1880 _zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_FUNCTION), &tmp, 1);
1881 }
1882
1883 ZVAL_ARR(&tmp, stack_frame);
1884 zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp);
1885
1886 skip_frame:
1887 if (UNEXPECTED(ZEND_CALL_KIND(call) == ZEND_CALL_TOP_FUNCTION)
1888 && !fake_frame
1889 && prev
1890 && prev->func
1891 && ZEND_USER_CODE(prev->func->common.type)
1892 && prev->opline->opcode == ZEND_INCLUDE_OR_EVAL) {
1893 fake_frame = 1;
1894 } else {
1895 fake_frame = 0;
1896 include_filename = filename;
1897 call = prev;
1898 }
1899 }
1900 }
1901 /* }}} */
1902
1903 /* {{{ Return backtrace as array */
ZEND_FUNCTION(debug_backtrace)1904 ZEND_FUNCTION(debug_backtrace)
1905 {
1906 zend_long options = DEBUG_BACKTRACE_PROVIDE_OBJECT;
1907 zend_long limit = 0;
1908
1909 if (zend_parse_parameters(ZEND_NUM_ARGS(), "|ll", &options, &limit) == FAILURE) {
1910 RETURN_THROWS();
1911 }
1912
1913 zend_fetch_debug_backtrace(return_value, 1, options, limit);
1914 }
1915 /* }}} */
1916
1917 /* {{{ Returns true if the named extension is loaded */
ZEND_FUNCTION(extension_loaded)1918 ZEND_FUNCTION(extension_loaded)
1919 {
1920 zend_string *extension_name;
1921 zend_string *lcname;
1922
1923 if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &extension_name) == FAILURE) {
1924 RETURN_THROWS();
1925 }
1926
1927 lcname = zend_string_tolower(extension_name);
1928 if (zend_hash_exists(&module_registry, lcname)) {
1929 RETVAL_TRUE;
1930 } else {
1931 RETVAL_FALSE;
1932 }
1933 zend_string_release_ex(lcname, 0);
1934 }
1935 /* }}} */
1936
1937 /* {{{ Returns an array with the names of functions belonging to the named extension */
ZEND_FUNCTION(get_extension_funcs)1938 ZEND_FUNCTION(get_extension_funcs)
1939 {
1940 zend_string *extension_name;
1941 zend_string *lcname;
1942 bool array;
1943 zend_module_entry *module;
1944 zend_function *zif;
1945
1946 if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &extension_name) == FAILURE) {
1947 RETURN_THROWS();
1948 }
1949 if (strncasecmp(ZSTR_VAL(extension_name), "zend", sizeof("zend"))) {
1950 lcname = zend_string_tolower(extension_name);
1951 module = zend_hash_find_ptr(&module_registry, lcname);
1952 zend_string_release_ex(lcname, 0);
1953 } else {
1954 module = zend_hash_str_find_ptr(&module_registry, "core", sizeof("core") - 1);
1955 }
1956
1957 if (!module) {
1958 RETURN_FALSE;
1959 }
1960
1961 if (module->functions) {
1962 /* avoid BC break, if functions list is empty, will return an empty array */
1963 array_init(return_value);
1964 array = 1;
1965 } else {
1966 array = 0;
1967 }
1968
1969 ZEND_HASH_MAP_FOREACH_PTR(CG(function_table), zif) {
1970 if (zif->common.type == ZEND_INTERNAL_FUNCTION
1971 && zif->internal_function.module == module) {
1972 if (!array) {
1973 array_init(return_value);
1974 array = 1;
1975 }
1976 add_next_index_str(return_value, zend_string_copy(zif->common.function_name));
1977 }
1978 } ZEND_HASH_FOREACH_END();
1979
1980 if (!array) {
1981 RETURN_FALSE;
1982 }
1983 }
1984 /* }}} */
1985