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