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