Coverage Report

Created: 2026-02-09 07:07

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