Coverage Report

Created: 2026-09-14 06:25

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