Coverage Report

Created: 2026-02-14 06:52

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
198
{
76
198
  zend_object *zobj;
77
198
  HashTable *with = (HashTable*)&zend_empty_array;
78
79
594
  ZEND_PARSE_PARAMETERS_START(1, 2)
80
792
    Z_PARAM_OBJ(zobj)
81
198
    Z_PARAM_OPTIONAL
82
762
    Z_PARAM_ARRAY_HT(with)
83
198
  ZEND_PARSE_PARAMETERS_END();
84
85
  /* clone() also exists as the ZEND_CLONE OPcode and both implementations must be kept in sync. */
86
87
194
  zend_class_entry *scope = zend_get_executed_scope();
88
89
194
  zend_class_entry *ce = zobj->ce;
90
194
  zend_function *clone = ce->clone;
91
92
194
  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
189
  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
189
  zend_object *cloned;
103
189
  if (zend_hash_num_elements(with) > 0) {
104
174
    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
174
    cloned = zobj->handlers->clone_obj_with(zobj, scope, with);
110
174
  } else {
111
15
    cloned = zobj->handlers->clone_obj(zobj);
112
15
  }
113
114
189
  ZEND_ASSERT(cloned || EG(exception));
115
189
  if (EXPECTED(cloned)) {
116
189
    RETURN_OBJ(cloned);
117
189
  }
118
189
}
119
120
ZEND_FUNCTION(exit)
121
119
{
122
119
  zend_string *str = NULL;
123
119
  zend_long status = 0;
124
125
357
  ZEND_PARSE_PARAMETERS_START(0, 1)
126
357
    Z_PARAM_OPTIONAL
127
483
    Z_PARAM_STR_OR_LONG(str, status)
128
483
  ZEND_PARSE_PARAMETERS_END();
129
130
115
  if (str) {
131
76
    size_t len = ZSTR_LEN(str);
132
76
    if (len != 0) {
133
      /* An exception might be emitted by an output handler */
134
76
      zend_write(ZSTR_VAL(str), len);
135
76
      if (EG(exception)) {
136
5
        RETURN_THROWS();
137
5
      }
138
76
    }
139
76
  } else {
140
39
    EG(exit_status) = status;
141
39
  }
142
143
110
  ZEND_ASSERT(!EG(exception));
144
110
  zend_throw_unwind_exit();
145
110
}
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.36k
{
170
1.36k
  ZEND_PARSE_PARAMETERS_NONE();
171
172
1.36k
  RETURN_LONG(gc_collect_cycles());
173
1.36k
}
174
/* }}} */
175
176
/* {{{ Returns status of the circular reference collector */
177
ZEND_FUNCTION(gc_enabled)
178
88
{
179
88
  ZEND_PARSE_PARAMETERS_NONE();
180
181
88
  RETURN_BOOL(gc_enabled());
182
88
}
183
/* }}} */
184
185
/* {{{ Activates the circular reference collector */
186
ZEND_FUNCTION(gc_enable)
187
27
{
188
27
  zend_string *key;
189
190
27
  ZEND_PARSE_PARAMETERS_NONE();
191
192
27
  key = ZSTR_INIT_LITERAL("zend.enable_gc", 0);
193
27
  zend_alter_ini_entry_chars(key, "1", sizeof("1")-1, ZEND_INI_USER, ZEND_INI_STAGE_RUNTIME);
194
27
  zend_string_release_ex(key, 0);
195
27
}
196
/* }}} */
197
198
/* {{{ Deactivates the circular reference collector */
199
ZEND_FUNCTION(gc_disable)
200
68
{
201
68
  zend_string *key;
202
203
68
  ZEND_PARSE_PARAMETERS_NONE();
204
205
68
  key = ZSTR_INIT_LITERAL("zend.enable_gc", 0);
206
68
  zend_alter_ini_entry_chars(key, "0", sizeof("0")-1, ZEND_INI_USER, ZEND_INI_STAGE_RUNTIME);
207
68
  zend_string_release_ex(key, 0);
208
68
}
209
/* }}} */
210
211
/* {{{ Returns current GC statistics */
212
ZEND_FUNCTION(gc_status)
213
167
{
214
167
  zend_gc_status status;
215
216
167
  ZEND_PARSE_PARAMETERS_NONE();
217
218
167
  zend_gc_get_status(&status);
219
220
167
  array_init_size(return_value, 16);
221
222
167
  add_assoc_bool_ex(return_value, "running", sizeof("running")-1, status.active);
223
167
  add_assoc_bool_ex(return_value, "protected", sizeof("protected")-1, status.gc_protected);
224
167
  add_assoc_bool_ex(return_value, "full", sizeof("full")-1, status.full);
225
167
  add_assoc_long_ex(return_value, "runs", sizeof("runs")-1, (long)status.runs);
226
167
  add_assoc_long_ex(return_value, "collected", sizeof("collected")-1, (long)status.collected);
227
167
  add_assoc_long_ex(return_value, "threshold", sizeof("threshold")-1, (long)status.threshold);
228
167
  add_assoc_long_ex(return_value, "buffer_size", sizeof("buffer_size")-1, (long)status.buf_size);
229
167
  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
167
  add_assoc_double_ex(return_value, "application_time", sizeof("application_time")-1, (double) status.application_time / ZEND_NANO_IN_SEC);
233
167
  add_assoc_double_ex(return_value, "collector_time", sizeof("collector_time")-1, (double) status.collector_time / ZEND_NANO_IN_SEC);
234
167
  add_assoc_double_ex(return_value, "destructor_time", sizeof("destructor_time")-1, (double) status.dtor_time / ZEND_NANO_IN_SEC);
235
167
  add_assoc_double_ex(return_value, "free_time", sizeof("free_time")-1, (double) status.free_time / ZEND_NANO_IN_SEC);
236
167
}
237
/* }}} */
238
239
/* {{{ Get the number of arguments that were passed to the function */
240
ZEND_FUNCTION(func_num_args)
241
20
{
242
20
  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_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
25
{
308
25
  zval *p, *q;
309
25
  uint32_t arg_count, first_extra_arg;
310
25
  uint32_t i;
311
25
  zend_execute_data *ex = EX(prev_execute_data);
312
313
25
  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
79
{
378
79
  zend_string *s;
379
380
232
  ZEND_PARSE_PARAMETERS_START(1, 1)
381
296
    Z_PARAM_STR(s)
382
79
  ZEND_PARSE_PARAMETERS_END();
383
384
69
  RETVAL_LONG(ZSTR_LEN(s));
385
69
}
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
45
{
405
45
  zend_string *s1, *s2;
406
45
  zend_long len;
407
408
134
  ZEND_PARSE_PARAMETERS_START(3, 3)
409
176
    Z_PARAM_STR(s1)
410
220
    Z_PARAM_STR(s2)
411
220
    Z_PARAM_LONG(len)
412
45
  ZEND_PARSE_PARAMETERS_END();
413
414
44
  if (len < 0) {
415
7
    zend_argument_value_error(3, "must be greater than or equal to 0");
416
7
    RETURN_THROWS();
417
7
  }
418
419
37
  RETURN_LONG(zend_binary_strncmp(ZSTR_VAL(s1), ZSTR_LEN(s1), ZSTR_VAL(s2), ZSTR_LEN(s2), len));
420
37
}
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
538
{
461
538
  zend_long err;
462
538
  bool err_is_null = 1;
463
538
  int old_error_reporting;
464
465
1.61k
  ZEND_PARSE_PARAMETERS_START(0, 1)
466
1.61k
    Z_PARAM_OPTIONAL
467
1.97k
    Z_PARAM_LONG_OR_NULL(err, err_is_null)
468
538
  ZEND_PARSE_PARAMETERS_END();
469
470
532
  old_error_reporting = EG(error_reporting);
471
472
532
  if (!err_is_null && err != old_error_reporting) {
473
413
    zend_ini_entry *p = EG(error_reporting_ini_entry);
474
475
413
    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
413
    if (!p->modified) {
485
371
      if (!EG(modified_ini_directives)) {
486
94
        ALLOC_HASHTABLE(EG(modified_ini_directives));
487
94
        zend_hash_init(EG(modified_ini_directives), 8, NULL, NULL, 0);
488
94
      }
489
371
      if (EXPECTED(zend_hash_add_ptr(EG(modified_ini_directives), ZSTR_KNOWN(ZEND_STR_ERROR_REPORTING), p) != NULL)) {
490
371
        p->orig_value = p->value;
491
371
        p->orig_modifiable = p->modifiable;
492
371
        p->modified = 1;
493
371
      }
494
371
    } else if (p->orig_value != p->value) {
495
37
      zend_string_release_ex(p->value, 0);
496
37
    }
497
498
413
    p->value = zend_long_to_str(err);
499
413
    EG(error_reporting) = err;
500
413
  }
501
502
532
  RETURN_LONG(old_error_reporting);
503
532
}
504
/* }}} */
505
506
static bool validate_constant_array_argument(HashTable *ht, int argument_number) /* {{{ */
507
77
{
508
77
  bool ret = true;
509
77
  zval *val;
510
511
77
  GC_PROTECT_RECURSION(ht);
512
231
  ZEND_HASH_FOREACH_VAL(ht, val) {
513
231
    ZVAL_DEREF(val);
514
231
    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
231
  } ZEND_HASH_FOREACH_END();
525
77
  GC_UNPROTECT_RECURSION(ht);
526
77
  return ret;
527
77
}
528
/* }}} */
529
530
static void copy_constant_array(zval *dst, zval *src) /* {{{ */
531
67
{
532
67
  zend_string *key;
533
67
  zend_ulong idx;
534
67
  zval *new_val, *val;
535
536
67
  array_init_size(dst, zend_hash_num_elements(Z_ARRVAL_P(src)));
537
201
  ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(src), idx, key, val) {
538
    /* constant arrays can't contain references */
539
201
    ZVAL_DEREF(val);
540
201
    if (key) {
541
0
      new_val = zend_hash_add_new(Z_ARRVAL_P(dst), key, val);
542
67
    } else {
543
67
      new_val = zend_hash_index_add_new(Z_ARRVAL_P(dst), idx, val);
544
67
    }
545
201
    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
67
    } else {
550
67
      Z_TRY_ADDREF_P(val);
551
67
    }
552
201
  } ZEND_HASH_FOREACH_END();
553
67
}
554
/* }}} */
555
556
/* {{{ Define a new constant */
557
ZEND_FUNCTION(define)
558
514
{
559
514
  zend_string *name;
560
514
  zval *val;
561
514
  bool non_cs = 0;
562
514
  zend_constant c;
563
564
1.54k
  ZEND_PARSE_PARAMETERS_START(2, 3)
565
2.05k
    Z_PARAM_STR(name)
566
2.54k
    Z_PARAM_ZVAL(val)
567
2.54k
    Z_PARAM_OPTIONAL
568
2.54k
    Z_PARAM_BOOL(non_cs)
569
514
  ZEND_PARSE_PARAMETERS_END();
570
571
508
  if (zend_memnstr(ZSTR_VAL(name), "::", sizeof("::") - 1, ZSTR_VAL(name) + ZSTR_LEN(name))) {
572
13
    zend_argument_value_error(1, "cannot be a class constant");
573
13
    RETURN_THROWS();
574
13
  }
575
576
495
  if (non_cs) {
577
0
    zend_error(E_WARNING, "define(): Argument #3 ($case_insensitive) is ignored since declaration of case-insensitive constants is no longer supported");
578
0
  }
579
580
495
  if (Z_TYPE_P(val) == IS_ARRAY && Z_REFCOUNTED_P(val)) {
581
77
    if (!validate_constant_array_argument(Z_ARRVAL_P(val), 2)) {
582
10
      RETURN_THROWS();
583
67
    } else {
584
67
      copy_constant_array(&c.value, val);
585
67
    }
586
418
  } else {
587
418
    ZVAL_COPY(&c.value, val);
588
418
  }
589
590
  /* non persistent */
591
485
  ZEND_CONSTANT_SET_FLAGS(&c, 0, PHP_USER_CONSTANT);
592
485
  c.name = zend_string_copy(name);
593
485
  if (zend_register_constant(&c) != NULL) {
594
408
    RETURN_TRUE;
595
408
  } else {
596
77
    RETURN_FALSE;
597
77
  }
598
485
}
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
203
{
605
203
  zend_string *name;
606
607
608
  ZEND_PARSE_PARAMETERS_START(1, 1)
608
808
    Z_PARAM_STR(name)
609
203
  ZEND_PARSE_PARAMETERS_END();
610
611
202
  if (zend_get_constant_ex(name, zend_get_executed_scope(), ZEND_FETCH_CLASS_SILENT)) {
612
80
    RETURN_TRUE;
613
122
  } else {
614
122
    RETURN_FALSE;
615
122
  }
616
202
}
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
8
{
650
8
  zend_class_entry *called_scope;
651
652
8
  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
22
{
667
22
  zend_class_entry *ce = NULL;
668
669
66
  ZEND_PARSE_PARAMETERS_START(0, 1)
670
66
    Z_PARAM_OPTIONAL
671
80
    Z_PARAM_OBJ_OR_CLASS_NAME(ce)
672
80
  ZEND_PARSE_PARAMETERS_END();
673
674
22
  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
22
  if (ce && ce->parent) {
683
12
    RETURN_STR_COPY(ce->parent->name);
684
12
  } else {
685
10
    RETURN_FALSE;
686
10
  }
687
22
}
688
/* }}} */
689
690
static void is_a_impl(INTERNAL_FUNCTION_PARAMETERS, bool only_subclass) /* {{{ */
691
164
{
692
164
  zval *obj;
693
164
  zend_string *class_name;
694
164
  zend_class_entry *instance_ce;
695
164
  zend_class_entry *ce;
696
164
  bool allow_string = only_subclass;
697
164
  bool retval;
698
699
483
  ZEND_PARSE_PARAMETERS_START(2, 3)
700
620
    Z_PARAM_ZVAL(obj)
701
620
    Z_PARAM_STR(class_name)
702
155
    Z_PARAM_OPTIONAL
703
310
    Z_PARAM_BOOL(allow_string)
704
164
  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
155
  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
125
  } else if (Z_TYPE_P(obj) == IS_OBJECT) {
718
125
    instance_ce = Z_OBJCE_P(obj);
719
125
  } else {
720
0
    RETURN_FALSE;
721
0
  }
722
723
147
  if (!only_subclass && EXPECTED(zend_string_equals(instance_ce->name, class_name))) {
724
10
    retval = 1;
725
137
  } else {
726
137
    ce = zend_lookup_class_ex(class_name, NULL, ZEND_FETCH_CLASS_NO_AUTOLOAD);
727
137
    if (!ce) {
728
29
      retval = 0;
729
108
    } else {
730
108
      if (only_subclass && instance_ce == ce) {
731
35
        retval = 0;
732
73
      } else {
733
73
        retval = instanceof_function(instance_ce, ce);
734
73
      }
735
108
    }
736
137
  }
737
738
147
  RETURN_BOOL(retval);
739
147
}
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
52
{
752
52
  is_a_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
753
52
}
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
1
    if (UNEXPECTED(zend_update_class_constants(ce) != SUCCESS)) {
817
1
      return;
818
1
    }
819
1
  }
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
241
{
830
241
  zval *value;
831
241
  HashTable *properties;
832
241
  zend_string *key;
833
241
  zend_object *zobj;
834
241
  zend_ulong num_key;
835
836
723
  ZEND_PARSE_PARAMETERS_START(1, 1)
837
964
    Z_PARAM_OBJ(zobj)
838
241
  ZEND_PARSE_PARAMETERS_END();
839
840
239
  zval obj_zv;
841
239
  ZVAL_OBJ(&obj_zv, zobj);
842
239
  properties = zend_get_properties_for(&obj_zv, ZEND_PROP_PURPOSE_GET_OBJECT_VARS);
843
239
  if (properties == NULL) {
844
0
    RETURN_EMPTY_ARRAY();
845
0
  }
846
847
239
  if (!zobj->ce->default_properties_count && properties == zobj->properties && !GC_IS_RECURSIVE(properties)) {
848
    /* fast copy */
849
10
    bool always_duplicate = zobj->handlers != &std_object_handlers;
850
10
    RETVAL_ARR(zend_proptable_to_symtable(properties, always_duplicate));
851
229
  } else {
852
229
    array_init_size(return_value, zend_hash_num_elements(properties));
853
854
1.63k
    ZEND_HASH_FOREACH_KEY_VAL(properties, num_key, key, value) {
855
1.63k
      bool is_dynamic = 1;
856
1.63k
      zval tmp;
857
1.63k
      ZVAL_UNDEF(&tmp);
858
1.63k
      if (Z_TYPE_P(value) == IS_INDIRECT) {
859
265
        value = Z_INDIRECT_P(value);
860
265
        if (UNEXPECTED(Z_ISUNDEF_P(value))) {
861
4
          continue;
862
4
        }
863
864
261
        is_dynamic = 0;
865
437
      } else if (Z_TYPE_P(value) == IS_PTR) {
866
426
        is_dynamic = 0;
867
426
      }
868
869
698
      if (key && zend_check_property_access(zobj, key, is_dynamic) == FAILURE) {
870
196
        continue;
871
196
      }
872
873
502
      if (Z_ISREF_P(value) && Z_REFCOUNT_P(value) == 1) {
874
11
        value = Z_REFVAL_P(value);
875
11
      }
876
502
      if (Z_TYPE_P(value) == IS_PTR) {
877
        /* value is IS_PTR for properties with hooks. */
878
299
        zend_property_info *prop_info = Z_PTR_P(value);
879
299
        if ((prop_info->flags & ZEND_ACC_VIRTUAL) && !prop_info->hooks[ZEND_PROPERTY_HOOK_GET]) {
880
61
          continue;
881
61
        }
882
238
        const char *unmangled_name_cstr = zend_get_unmangled_property_name(prop_info->name);
883
238
        zend_string *unmangled_name = zend_string_init(unmangled_name_cstr, strlen(unmangled_name_cstr), false);
884
238
        value = zend_read_property_ex(prop_info->ce, zobj, unmangled_name, /* silent */ true, &tmp);
885
238
        zend_string_release_ex(unmangled_name, false);
886
238
        if (EG(exception)) {
887
0
          zend_release_properties(properties);
888
0
          zval_ptr_dtor(return_value);
889
0
          ZVAL_UNDEF(return_value);
890
0
          RETURN_THROWS();
891
0
        }
892
238
      }
893
441
      Z_TRY_ADDREF_P(value);
894
895
441
      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
441
      } else if (!is_dynamic && ZSTR_VAL(key)[0] == 0) {
899
154
        const char *prop_name, *class_name;
900
154
        size_t prop_len;
901
154
        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
154
        zend_hash_str_add_new(Z_ARRVAL_P(return_value), prop_name, prop_len, value);
908
287
      } else {
909
287
        zend_symtable_add_new(Z_ARRVAL_P(return_value), key, value);
910
287
      }
911
441
      zval_ptr_dtor(&tmp);
912
441
    } ZEND_HASH_FOREACH_END();
913
229
  }
914
239
  zend_release_properties(properties);
915
239
}
916
/* }}} */
917
918
/* {{{ Returns an array of mangled object properties. Does not respect property visibility. */
919
ZEND_FUNCTION(get_mangled_object_vars)
920
86
{
921
86
  zend_object *obj;
922
86
  HashTable *properties;
923
924
258
  ZEND_PARSE_PARAMETERS_START(1, 1)
925
344
    Z_PARAM_OBJ(obj)
926
86
  ZEND_PARSE_PARAMETERS_END();
927
928
86
  properties = zend_get_properties_no_lazy_init(obj);
929
86
  if (!properties) {
930
0
    ZVAL_EMPTY_ARRAY(return_value);
931
0
    return;
932
0
  }
933
934
86
  properties = zend_proptable_to_symtable(properties,
935
86
    (obj->ce->default_properties_count ||
936
0
     obj->handlers != &std_object_handlers ||
937
0
     GC_IS_RECURSIVE(properties)));
938
86
  RETURN_ARR(properties);
939
86
}
940
/* }}} */
941
942
/* {{{ Returns an array of method names for class or class instance. */
943
ZEND_FUNCTION(get_class_methods)
944
97
{
945
97
  zval method_name;
946
97
  zend_class_entry *ce = NULL;
947
97
  zend_class_entry *scope;
948
97
  zend_function *mptr;
949
950
291
  ZEND_PARSE_PARAMETERS_START(1, 1)
951
480
    Z_PARAM_OBJ_OR_CLASS_NAME(ce)
952
480
  ZEND_PARSE_PARAMETERS_END();
953
954
92
  array_init(return_value);
955
92
  scope = zend_get_executed_scope();
956
957
896
  ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, mptr) {
958
896
    if (zend_check_method_accessible(mptr, scope)) {
959
261
      ZVAL_STR_COPY(&method_name, mptr->common.function_name);
960
261
      zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &method_name);
961
261
    }
962
896
  } ZEND_HASH_FOREACH_END();
963
92
}
964
/* }}} */
965
966
/* {{{ Checks if the class method exists */
967
ZEND_FUNCTION(method_exists)
968
216
{
969
216
  zval *klass;
970
216
  zend_string *method_name;
971
216
  zend_string *lcname;
972
216
  zend_class_entry *ce;
973
216
  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
648
  ZEND_PARSE_PARAMETERS_START(2, 2)
977
864
    Z_PARAM_ZVAL(klass)
978
864
    Z_PARAM_STR(method_name)
979
216
  ZEND_PARSE_PARAMETERS_END();
980
981
216
  if (Z_TYPE_P(klass) == IS_OBJECT) {
982
135
    ce = Z_OBJCE_P(klass);
983
135
  } else if (Z_TYPE_P(klass) == IS_STRING) {
984
81
    if ((ce = zend_lookup_class(Z_STR_P(klass))) == NULL) {
985
4
      RETURN_FALSE;
986
4
    }
987
81
  } else {
988
0
    zend_argument_type_error(1, "must be of type object|string, %s given", zend_zval_value_name(klass));
989
0
    RETURN_THROWS();
990
0
  }
991
992
212
  lcname = zend_string_tolower(method_name);
993
212
  func = zend_hash_find_ptr(&ce->function_table, lcname);
994
212
  zend_string_release_ex(lcname, 0);
995
996
212
  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
136
  if (Z_TYPE_P(klass) == IS_OBJECT) {
1005
95
    zend_object *obj = Z_OBJ_P(klass);
1006
95
    func = Z_OBJ_HT_P(klass)->get_method(&obj, method_name, NULL);
1007
95
    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
95
  } else {
1020
      /* Returns true for fake Closure::__invoke */
1021
41
      if (ce == zend_ce_closure
1022
34
          && zend_string_equals_literal_ci(method_name, ZEND_INVOKE_FUNC_NAME)) {
1023
21
          RETURN_TRUE;
1024
21
      }
1025
41
  }
1026
50
  RETURN_FALSE;
1027
50
}
1028
/* }}} */
1029
1030
static void _property_exists(zval *return_value, zval *object, zend_string *property)
1031
427
{
1032
427
  zend_class_entry *ce;
1033
427
  zend_property_info *property_info;
1034
1035
427
  if (Z_TYPE_P(object) == IS_STRING) {
1036
250
    ce = zend_lookup_class(Z_STR_P(object));
1037
250
    if (!ce) {
1038
39
      RETURN_FALSE;
1039
39
    }
1040
250
  } else if (Z_TYPE_P(object) == IS_OBJECT) {
1041
136
    ce = Z_OBJCE_P(object);
1042
136
  } 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
347
  property_info = zend_hash_find_ptr(&ce->properties_info, property);
1048
347
  if (property_info != NULL
1049
260
   && (!(property_info->flags & ZEND_ACC_PRIVATE)
1050
255
    || property_info->ce == ce)) {
1051
255
    RETURN_TRUE;
1052
255
  }
1053
1054
92
  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
87
  RETURN_FALSE;
1059
87
}
1060
1061
/* {{{ Checks if the object or class has a property */
1062
ZEND_FUNCTION(property_exists)
1063
427
{
1064
427
  zval *object;
1065
427
  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
427
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "zS", &object, &property) == FAILURE) {
1069
0
    RETURN_THROWS();
1070
0
  }
1071
1072
427
  _property_exists(return_value, object, property);
1073
427
}
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.68k
{
1093
1.68k
  zend_string *lcname;
1094
1.68k
  zend_class_entry *ce;
1095
1096
1.68k
  if (ZSTR_HAS_CE_CACHE(name)) {
1097
1.49k
    ce = ZSTR_GET_CE_CACHE(name);
1098
1.49k
    if (ce) {
1099
150
      RETURN_BOOL(((ce->ce_flags & flags) == flags) && !(ce->ce_flags & skip_flags));
1100
150
    }
1101
1.49k
  }
1102
1103
1.53k
  if (!autoload) {
1104
128
    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
128
    } else {
1109
128
      lcname = zend_string_tolower(name);
1110
128
    }
1111
1112
128
    ce = zend_hash_find_ptr(EG(class_table), lcname);
1113
128
    zend_string_release_ex(lcname, 0);
1114
1.41k
  } else {
1115
1.41k
    ce = zend_lookup_class(name);
1116
1.41k
  }
1117
1118
1.53k
  if (ce) {
1119
1.27k
    RETURN_BOOL(((ce->ce_flags & flags) == flags) && !(ce->ce_flags & skip_flags));
1120
1.27k
  } else {
1121
269
    RETURN_FALSE;
1122
269
  }
1123
1.53k
}
1124
/* {{{ */
1125
1126
static inline void class_exists_impl(INTERNAL_FUNCTION_PARAMETERS, int flags, int skip_flags) /* {{{ */
1127
1.68k
{
1128
1.68k
  zend_string *name;
1129
1.68k
  bool autoload = true;
1130
1131
5.06k
  ZEND_PARSE_PARAMETERS_START(1, 2)
1132
6.75k
    Z_PARAM_STR(name)
1133
1.68k
    Z_PARAM_OPTIONAL
1134
3.77k
    Z_PARAM_BOOL(autoload)
1135
1.68k
  ZEND_PARSE_PARAMETERS_END();
1136
1137
1.68k
  _class_exists_impl(return_value, name, autoload, flags, skip_flags);
1138
1.68k
}
1139
1140
/* {{{ Checks if the class exists */
1141
ZEND_FUNCTION(class_exists)
1142
1.42k
{
1143
1.42k
  class_exists_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_LINKED, ZEND_ACC_INTERFACE | ZEND_ACC_TRAIT);
1144
1.42k
}
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
143
{
1178
143
  class_exists_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_LINKED|ZEND_ACC_INTERFACE, 0);
1179
143
}
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
64
{
1191
64
  class_exists_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_ENUM, 0);
1192
64
}
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
211
{
1223
211
  zend_string *class_name;
1224
211
  zend_string *alias_name;
1225
211
  zend_class_entry *ce;
1226
211
  bool autoload = 1;
1227
1228
632
  ZEND_PARSE_PARAMETERS_START(2, 3)
1229
840
    Z_PARAM_STR(class_name)
1230
1.05k
    Z_PARAM_STR(alias_name)
1231
210
    Z_PARAM_OPTIONAL
1232
432
    Z_PARAM_BOOL(autoload)
1233
211
  ZEND_PARSE_PARAMETERS_END();
1234
1235
210
  ce = zend_lookup_class_ex(class_name, NULL, !autoload ? ZEND_FETCH_CLASS_NO_AUTOLOAD : 0);
1236
1237
210
  if (ce) {
1238
197
    if (zend_register_class_alias_ex(ZSTR_VAL(alias_name), ZSTR_LEN(alias_name), ce, false) == SUCCESS) {
1239
166
      RETURN_TRUE;
1240
166
    } else {
1241
31
      zend_class_redeclaration_error_ex(E_WARNING, alias_name, ce);
1242
31
      RETURN_FALSE;
1243
31
    }
1244
197
  } else {
1245
13
    zend_error(E_WARNING, "Class \"%s\" not found", ZSTR_VAL(class_name));
1246
13
    RETURN_FALSE;
1247
13
  }
1248
210
}
1249
/* }}} */
1250
1251
/* {{{ Returns an array with the file names that were include_once()'d */
1252
ZEND_FUNCTION(get_included_files)
1253
30
{
1254
30
  zend_string *entry;
1255
1256
30
  ZEND_PARSE_PARAMETERS_NONE();
1257
1258
30
  array_init(return_value);
1259
70
  ZEND_HASH_MAP_FOREACH_STR_KEY(&EG(included_files), entry) {
1260
70
    if (entry) {
1261
5
      add_next_index_str(return_value, zend_string_copy(entry));
1262
5
    }
1263
70
  } ZEND_HASH_FOREACH_END();
1264
30
}
1265
/* }}} */
1266
1267
/* {{{ Generates a user-level error/warning/notice message */
1268
ZEND_FUNCTION(trigger_error)
1269
121
{
1270
121
  zend_long error_type = E_USER_NOTICE;
1271
121
  zend_string *message;
1272
1273
121
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "S|l", &message, &error_type) == FAILURE) {
1274
0
    RETURN_THROWS();
1275
0
  }
1276
1277
121
  switch (error_type) {
1278
56
    case E_USER_ERROR:
1279
56
      zend_error(E_DEPRECATED, "Passing E_USER_ERROR to trigger_error() is deprecated since 8.4,"
1280
56
        " throw an exception or call exit with a string message instead");
1281
56
      if (UNEXPECTED(EG(exception))) {
1282
0
        RETURN_THROWS();
1283
0
      }
1284
91
    case E_USER_WARNING:
1285
106
    case E_USER_NOTICE:
1286
111
    case E_USER_DEPRECATED:
1287
111
      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
121
  }
1294
1295
111
  zend_error_zstr_at(error_type, zend_get_executed_filename_ex(), zend_get_executed_lineno(), message);
1296
  // TODO Change to void
1297
111
  RETURN_TRUE;
1298
111
}
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
186
{
1372
186
  zend_fcall_info fci;
1373
186
  zend_fcall_info_cache fcc;
1374
1375
558
  ZEND_PARSE_PARAMETERS_START(1, 1)
1376
744
    Z_PARAM_FUNC_OR_NULL(fci, fcc)
1377
186
  ZEND_PARSE_PARAMETERS_END();
1378
1379
176
  if (Z_TYPE(EG(user_exception_handler)) != IS_UNDEF) {
1380
74
    ZVAL_COPY(return_value, &EG(user_exception_handler));
1381
74
  }
1382
1383
176
  zend_stack_push(&EG(user_exception_handlers), &EG(user_exception_handler));
1384
1385
176
  if (!ZEND_FCI_INITIALIZED(fci)) { /* unset user-defined handler */
1386
29
    ZVAL_UNDEF(&EG(user_exception_handler));
1387
29
    return;
1388
29
  }
1389
1390
147
  ZVAL_COPY(&EG(user_exception_handler), &(fci.function_name));
1391
147
}
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
64
{
1426
64
  zend_string *key;
1427
64
  zval *zv;
1428
64
  zend_class_entry *ce;
1429
1430
64
  ZEND_PARSE_PARAMETERS_NONE();
1431
1432
64
  array_init(return_value);
1433
64
  zend_hash_real_init_packed(Z_ARRVAL_P(return_value));
1434
64
  ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
1435
21.5k
    ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(EG(class_table), key, zv) {
1436
21.5k
      ce = Z_PTR_P(zv);
1437
21.5k
      if ((ce->ce_flags & (ZEND_ACC_LINKED|ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT)) == flags
1438
6.01k
       && key
1439
6.01k
       && ZSTR_VAL(key)[0] != 0) {
1440
6.01k
        ZEND_HASH_FILL_GROW();
1441
6.01k
        if (EXPECTED(Z_TYPE_P(zv) == IS_PTR)) {
1442
6.00k
          ZEND_HASH_FILL_SET_STR_COPY(ce->name);
1443
6.00k
        } 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.01k
        ZEND_HASH_FILL_NEXT();
1448
6.01k
      }
1449
21.5k
    } ZEND_HASH_FOREACH_END();
1450
64
  } ZEND_HASH_FILL_END();
1451
64
}
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
41
{
1464
41
  get_declared_class_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_ACC_LINKED);
1465
41
}
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
47
{
1478
47
  zval internal, user;
1479
47
  zend_string *key;
1480
47
  zend_function *func;
1481
47
  bool exclude_disabled = true;
1482
1483
47
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &exclude_disabled) == FAILURE) {
1484
0
    RETURN_THROWS();
1485
0
  }
1486
1487
47
  if (ZEND_NUM_ARGS() == 1) {
1488
25
    zend_error(E_DEPRECATED,
1489
25
      "get_defined_functions(): The $exclude_disabled parameter has no effect since PHP 8.0");
1490
25
  }
1491
1492
47
  array_init(&internal);
1493
47
  array_init(&user);
1494
47
  array_init(return_value);
1495
1496
64.8k
  ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(EG(function_table), key, func) {
1497
64.8k
    if (key && ZSTR_VAL(key)[0] != 0) {
1498
32.3k
      if (func->type == ZEND_INTERNAL_FUNCTION) {
1499
32.3k
        add_next_index_str(&internal, zend_string_copy(key));
1500
32.3k
      } else if (func->type == ZEND_USER_FUNCTION) {
1501
32
        add_next_index_str(&user, zend_string_copy(key));
1502
32
      }
1503
32.3k
    }
1504
64.8k
  } ZEND_HASH_FOREACH_END();
1505
1506
47
  zend_hash_str_add_new(Z_ARRVAL_P(return_value), "internal", sizeof("internal")-1, &internal);
1507
47
  zend_hash_add_new(Z_ARRVAL_P(return_value), ZSTR_KNOWN(ZEND_STR_USER), &user);
1508
47
}
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
84
{
1514
84
  zend_array *symbol_table;
1515
1516
84
  ZEND_PARSE_PARAMETERS_NONE();
1517
1518
84
  if (zend_forbid_dynamic_call() == FAILURE) {
1519
12
    return;
1520
12
  }
1521
1522
72
  symbol_table = zend_rebuild_symbol_table();
1523
72
  if (UNEXPECTED(symbol_table == NULL)) {
1524
0
    RETURN_EMPTY_ARRAY();
1525
0
  }
1526
1527
72
  RETURN_ARR(zend_array_dup(symbol_table));
1528
72
}
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
868k
{
1722
868k
  zend_attribute *attribute = zend_get_parameter_attribute_str(
1723
868k
    call->func->common.attributes,
1724
868k
    "sensitiveparameter",
1725
868k
    sizeof("sensitiveparameter") - 1,
1726
868k
    offset
1727
868k
  );
1728
1729
868k
  return attribute != NULL;
1730
868k
}
1731
1732
static void debug_backtrace_get_args(zend_execute_data *call, zval *arg_array) /* {{{ */
1733
632k
{
1734
632k
  uint32_t num_args = ZEND_CALL_NUM_ARGS(call);
1735
1736
632k
  if (num_args) {
1737
509k
    uint32_t i = 0;
1738
509k
    zval *p = ZEND_CALL_ARG(call, 1);
1739
1740
509k
    array_init_size(arg_array, num_args);
1741
509k
    zend_hash_real_init_packed(Z_ARRVAL_P(arg_array));
1742
509k
    ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(arg_array)) {
1743
509k
      if (call->func->type == ZEND_USER_FUNCTION) {
1744
13.3k
        uint32_t first_extra_arg = MIN(num_args, call->func->op_array.num_args);
1745
1746
13.3k
        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.39k
          while (i < first_extra_arg) {
1752
764
            zend_string *arg_name = call->func->op_array.vars[i];
1753
764
            zval original_arg;
1754
764
            zval *arg = zend_hash_find_ex_ind(call->symbol_table, arg_name, 1);
1755
764
            bool is_sensitive = backtrace_is_arg_sensitive(call, i);
1756
1757
764
            if (arg) {
1758
764
              ZVAL_DEREF(arg);
1759
764
              ZVAL_COPY_VALUE(&original_arg, arg);
1760
764
            } else {
1761
0
              ZVAL_NULL(&original_arg);
1762
0
            }
1763
1764
764
            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
760
            } else {
1769
760
              Z_TRY_ADDREF_P(&original_arg);
1770
760
              ZEND_HASH_FILL_SET(&original_arg);
1771
760
            }
1772
1773
764
            ZEND_HASH_FILL_NEXT();
1774
764
            i++;
1775
764
          }
1776
12.7k
        } else {
1777
28.3k
          while (i < first_extra_arg) {
1778
15.6k
            zval original_arg;
1779
15.6k
            bool is_sensitive = backtrace_is_arg_sensitive(call, i);
1780
1781
15.6k
            if (EXPECTED(Z_TYPE_INFO_P(p) != IS_UNDEF)) {
1782
15.4k
              zval *arg = p;
1783
15.4k
              ZVAL_DEREF(arg);
1784
15.4k
              ZVAL_COPY_VALUE(&original_arg, arg);
1785
15.4k
            } else {
1786
163
              ZVAL_NULL(&original_arg);
1787
163
            }
1788
1789
15.6k
            if (is_sensitive) {
1790
212
              zval redacted_arg;
1791
212
              object_init_with_constructor(&redacted_arg, zend_ce_sensitive_parameter_value, 1, &original_arg, NULL);
1792
212
              ZEND_HASH_FILL_SET(&redacted_arg);
1793
15.4k
            } else {
1794
15.4k
              Z_TRY_ADDREF_P(&original_arg);
1795
15.4k
              ZEND_HASH_FILL_SET(&original_arg);
1796
15.4k
            }
1797
1798
15.6k
            ZEND_HASH_FILL_NEXT();
1799
15.6k
            p++;
1800
15.6k
            i++;
1801
15.6k
          }
1802
12.7k
        }
1803
13.3k
        p = ZEND_CALL_VAR_NUM(call, call->func->op_array.last_var + call->func->op_array.T);
1804
13.3k
      }
1805
1806
1.41M
      while (i < num_args) {
1807
902k
        zval original_arg;
1808
902k
        bool is_sensitive = 0;
1809
1810
902k
        if (i < call->func->common.num_args || call->func->common.fn_flags & ZEND_ACC_VARIADIC) {
1811
852k
          is_sensitive = backtrace_is_arg_sensitive(call, MIN(i, call->func->common.num_args));
1812
852k
        }
1813
1814
902k
        if (EXPECTED(Z_TYPE_INFO_P(p) != IS_UNDEF)) {
1815
902k
          zval *arg = p;
1816
902k
          ZVAL_DEREF(arg);
1817
902k
          ZVAL_COPY_VALUE(&original_arg, arg);
1818
902k
        } else {
1819
29
          ZVAL_NULL(&original_arg);
1820
29
        }
1821
1822
902k
        if (is_sensitive) {
1823
81
          zval redacted_arg;
1824
81
          object_init_with_constructor(&redacted_arg, zend_ce_sensitive_parameter_value, 1, &original_arg, NULL);
1825
81
          ZEND_HASH_FILL_SET(&redacted_arg);
1826
901k
        } else {
1827
901k
          Z_TRY_ADDREF_P(&original_arg);
1828
901k
          ZEND_HASH_FILL_SET(&original_arg);
1829
901k
        }
1830
1831
902k
        ZEND_HASH_FILL_NEXT();
1832
902k
        p++;
1833
902k
        i++;
1834
902k
      }
1835
509k
    } ZEND_HASH_FILL_END();
1836
509k
    Z_ARRVAL_P(arg_array)->nNumOfElements = num_args;
1837
509k
  } else {
1838
122k
    ZVAL_EMPTY_ARRAY(arg_array);
1839
122k
  }
1840
1841
632k
  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
106
   && (call->func->common.fn_flags & ZEND_ACC_VARIADIC)) {
1846
82
    zend_string *name;
1847
82
    zval *arg;
1848
1849
82
    bool is_sensitive = backtrace_is_arg_sensitive(call, call->func->common.num_args);
1850
1851
82
    SEPARATE_ARRAY(arg_array);
1852
380
    ZEND_HASH_MAP_FOREACH_STR_KEY_VAL(call->extra_named_params, name, arg) {
1853
380
      ZVAL_DEREF(arg);
1854
380
      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
100
      } else {
1859
100
        Z_TRY_ADDREF_P(arg);
1860
100
        zend_hash_add_new(Z_ARRVAL_P(arg_array), name, arg);
1861
100
      }
1862
380
    } ZEND_HASH_FOREACH_END();
1863
82
  }
1864
632k
}
1865
/* }}} */
1866
1867
/* {{{ */
1868
ZEND_FUNCTION(debug_print_backtrace)
1869
288
{
1870
288
  zend_long options = 0;
1871
288
  zend_long limit = 0;
1872
288
  zval backtrace;
1873
1874
288
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "|ll", &options, &limit) == FAILURE) {
1875
0
    RETURN_THROWS();
1876
0
  }
1877
1878
288
  zend_fetch_debug_backtrace(&backtrace, 1, options, limit);
1879
288
  ZEND_ASSERT(Z_TYPE(backtrace) == IS_ARRAY);
1880
1881
288
  zend_string *str = zend_trace_to_string(Z_ARRVAL(backtrace), /* include_main */ false);
1882
288
  ZEND_WRITE(ZSTR_VAL(str), ZSTR_LEN(str));
1883
288
  zend_string_release(str);
1884
288
  zval_ptr_dtor(&backtrace);
1885
288
}
1886
1887
/* }}} */
1888
1889
ZEND_API void zend_fetch_debug_backtrace(zval *return_value, int skip_last, int options, int limit) /* {{{ */
1890
645k
{
1891
645k
  zend_execute_data *call, *last_call = NULL;
1892
645k
  zend_object *object;
1893
645k
  bool fake_frame = false;
1894
645k
  int lineno, frameno = 0;
1895
645k
  zend_function *func;
1896
645k
  zend_string *filename;
1897
645k
  zend_string *include_filename = NULL;
1898
645k
  zval tmp;
1899
645k
  HashTable *stack_frame, *prev_stack_frame = NULL;
1900
1901
645k
  array_init(return_value);
1902
1903
645k
  call = EG(current_execute_data);
1904
645k
  if (!call) {
1905
4.93k
    return;
1906
4.93k
  }
1907
1908
640k
  if (EG(filename_override)) {
1909
    // Add the current execution point to the frame so we don't lose it
1910
133
    zend_string *filename_override = EG(filename_override);
1911
133
    zend_long lineno_override = EG(lineno_override);
1912
133
    EG(filename_override) = NULL;
1913
133
    EG(lineno_override) = -1;
1914
1915
133
    zend_string *filename = zend_get_executed_filename_ex();
1916
133
    zend_long lineno = zend_get_executed_lineno();
1917
133
    if (filename && (!zend_string_equals(filename, filename_override) || lineno != lineno_override)) {
1918
121
      stack_frame = zend_new_array(8);
1919
121
      zend_hash_real_init_mixed(stack_frame);
1920
121
      ZVAL_STR_COPY(&tmp, filename);
1921
121
      _zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_FILE), &tmp, 1);
1922
121
      ZVAL_LONG(&tmp, lineno);
1923
121
      _zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_LINE), &tmp, 1);
1924
121
      ZVAL_STR_COPY(&tmp, ZSTR_KNOWN(ZEND_STR_CONST_EXPR_PLACEHOLDER));
1925
121
      _zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_FUNCTION), &tmp, 1);
1926
121
      ZVAL_ARR(&tmp, stack_frame);
1927
121
      zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp);
1928
121
    }
1929
1930
133
    EG(filename_override) = filename_override;
1931
133
    EG(lineno_override) = lineno_override;
1932
133
  }
1933
1934
640k
  if (skip_last) {
1935
    /* skip debug_backtrace() */
1936
598
    last_call = call;
1937
598
    call = call->prev_execute_data;
1938
598
  }
1939
1940
2.66M
  while (call && (limit == 0 || frameno < limit)) {
1941
2.16M
    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
11
      call = zend_generator_check_placeholder_frame(call);
1948
11
      ZEND_ASSERT(call->func);
1949
11
    }
1950
1951
2.16M
    zend_execute_data *prev = call->prev_execute_data;
1952
1953
2.16M
    if (!prev) {
1954
      /* add frame for a handler call without {main} code */
1955
640k
      if (EXPECTED((ZEND_CALL_INFO(call) & ZEND_CALL_TOP_FUNCTION) == 0)) {
1956
136k
        break;
1957
136k
      }
1958
1.52M
    } else if (UNEXPECTED((ZEND_CALL_INFO(call) & ZEND_CALL_GENERATOR) != 0)) {
1959
422
      prev = zend_generator_check_placeholder_frame(prev);
1960
422
    }
1961
1962
    /* For frameless calls we add an additional frame for the call itself. */
1963
2.02M
    if (ZEND_USER_CODE(call->func->type)) {
1964
1.52M
      const zend_op *opline = call->opline;
1965
1.52M
      if (!ZEND_OP_IS_FRAMELESS_ICALL(opline->opcode)) {
1966
1.52M
        goto not_frameless_call;
1967
1.52M
      }
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.02M
not_frameless_call:
2041
2042
    /* We use _zend_hash_append*() and the array must be preallocated */
2043
2.02M
    stack_frame = zend_new_array(8);
2044
2.02M
    zend_hash_real_init_mixed(stack_frame);
2045
2046
2.02M
    if (prev && prev->func && ZEND_USER_CODE(prev->func->common.type)) {
2047
1.47M
      filename = prev->func->op_array.filename;
2048
1.47M
      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.47M
      } else {
2055
1.47M
        lineno = prev->opline->lineno;
2056
1.47M
      }
2057
1.47M
      ZVAL_STR_COPY(&tmp, filename);
2058
1.47M
      _zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_FILE), &tmp, 1);
2059
1.47M
      ZVAL_LONG(&tmp, lineno);
2060
1.47M
      _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.47M
    } else {
2066
553k
      zend_execute_data *prev_call = prev;
2067
2068
553k
      while (prev_call) {
2069
49.6k
        zend_execute_data *prev;
2070
2071
49.6k
        if (prev_call &&
2072
49.6k
          prev_call->func &&
2073
49.5k
          !ZEND_USER_CODE(prev_call->func->common.type) &&
2074
49.5k
          !(prev_call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
2075
49.5k
          break;
2076
49.5k
        }
2077
2078
22
        prev = prev_call->prev_execute_data;
2079
22
        if (prev && prev->func && ZEND_USER_CODE(prev->func->common.type)) {
2080
22
          ZVAL_STR_COPY(&tmp, prev->func->op_array.filename);
2081
22
          _zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_FILE), &tmp, 1);
2082
22
          ZVAL_LONG(&tmp, prev->opline->lineno);
2083
22
          _zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_LINE), &tmp, 1);
2084
22
          break;
2085
22
        }
2086
0
        prev_call = prev;
2087
0
      }
2088
553k
      filename = NULL;
2089
553k
    }
2090
2091
2.02M
    func = call->func;
2092
2.02M
    if (!fake_frame && func->common.function_name) {
2093
632k
      ZVAL_STR_COPY(&tmp, func->common.function_name);
2094
632k
      _zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_FUNCTION), &tmp, 1);
2095
2096
632k
      if (Z_TYPE(call->This) == IS_OBJECT) {
2097
478k
        object = Z_OBJ(call->This);
2098
        /* $this may be passed into regular internal functions */
2099
478k
        if (func->common.scope) {
2100
478k
          ZVAL_STR_COPY(&tmp, func->common.scope->name);
2101
478k
        } 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
478k
        _zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_CLASS), &tmp, 1);
2107
478k
        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
478k
        ZVAL_INTERNED_STR(&tmp, ZSTR_KNOWN(ZEND_STR_OBJECT_OPERATOR));
2113
478k
        _zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_TYPE), &tmp, 1);
2114
478k
      } else if (func->common.scope) {
2115
684
        ZVAL_STR_COPY(&tmp, func->common.scope->name);
2116
684
        _zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_CLASS), &tmp, 1);
2117
684
        ZVAL_INTERNED_STR(&tmp, ZSTR_KNOWN(ZEND_STR_PAAMAYIM_NEKUDOTAYIM));
2118
684
        _zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_TYPE), &tmp, 1);
2119
684
      }
2120
2121
632k
      if ((options & DEBUG_BACKTRACE_IGNORE_ARGS) == 0 &&
2122
632k
        func->type != ZEND_EVAL_CODE) {
2123
2124
632k
        debug_backtrace_get_args(call, &tmp);
2125
632k
        _zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_ARGS), &tmp, 1);
2126
632k
      }
2127
1.39M
    } else {
2128
      /* i know this is kinda ugly, but i'm trying to avoid extra cycles in the main execution loop */
2129
1.39M
      bool build_filename_arg = true;
2130
1.39M
      zend_string *pseudo_function_name;
2131
1.39M
      uint32_t include_kind = 0;
2132
1.39M
      if (prev && prev->func && ZEND_USER_CODE(prev->func->common.type) && prev->opline->opcode == ZEND_INCLUDE_OR_EVAL) {
2133
933k
        include_kind = prev->opline->extended_value;
2134
933k
      }
2135
2136
1.39M
      switch (include_kind) {
2137
621
        case ZEND_EVAL:
2138
621
          pseudo_function_name = ZSTR_KNOWN(ZEND_STR_EVAL);
2139
621
          build_filename_arg = false;
2140
621
          break;
2141
53
        case ZEND_INCLUDE:
2142
53
          pseudo_function_name = ZSTR_KNOWN(ZEND_STR_INCLUDE);
2143
53
          break;
2144
932k
        case ZEND_REQUIRE:
2145
932k
          pseudo_function_name = ZSTR_KNOWN(ZEND_STR_REQUIRE);
2146
932k
          break;
2147
5
        case ZEND_INCLUDE_ONCE:
2148
5
          pseudo_function_name = ZSTR_KNOWN(ZEND_STR_INCLUDE_ONCE);
2149
5
          break;
2150
13
        case ZEND_REQUIRE_ONCE:
2151
13
          pseudo_function_name = ZSTR_KNOWN(ZEND_STR_REQUIRE_ONCE);
2152
13
          break;
2153
458k
        default:
2154
          /* Skip dummy frame unless it is needed to preserve filename/lineno info. */
2155
458k
          if (!filename) {
2156
458k
            zend_array_destroy(stack_frame);
2157
458k
            goto skip_frame;
2158
458k
          }
2159
2160
0
          pseudo_function_name = ZSTR_KNOWN(ZEND_STR_UNKNOWN);
2161
0
          build_filename_arg = false;
2162
0
          break;
2163
1.39M
      }
2164
2165
933k
      if (build_filename_arg && include_filename) {
2166
932k
        zval arg_array;
2167
2168
932k
        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
932k
        ZVAL_STR_COPY(&tmp, include_filename);
2175
932k
        zend_hash_next_index_insert_new(Z_ARRVAL(arg_array), &tmp);
2176
932k
        _zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_ARGS), &arg_array, 1);
2177
932k
      }
2178
2179
933k
      ZVAL_INTERNED_STR(&tmp, pseudo_function_name);
2180
933k
      _zend_hash_append_ex(stack_frame, ZSTR_KNOWN(ZEND_STR_FUNCTION), &tmp, 1);
2181
933k
    }
2182
2183
1.56M
    ZVAL_ARR(&tmp, stack_frame);
2184
1.56M
    zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &tmp);
2185
1.56M
    frameno++;
2186
1.56M
    prev_stack_frame = stack_frame;
2187
2188
2.02M
skip_frame:
2189
2.02M
    if (UNEXPECTED(ZEND_CALL_KIND(call) == ZEND_CALL_TOP_FUNCTION)
2190
176k
     && !fake_frame
2191
176k
     && prev
2192
130k
     && prev->func
2193
130k
     && ZEND_USER_CODE(prev->func->common.type)
2194
81.6k
     && prev->opline->opcode == ZEND_INCLUDE_OR_EVAL) {
2195
84
      fake_frame = true;
2196
2.02M
    } else {
2197
2.02M
      fake_frame = false;
2198
2.02M
      include_filename = filename;
2199
2.02M
      last_call = call;
2200
2.02M
      call = prev;
2201
2.02M
    }
2202
2.02M
  }
2203
640k
}
2204
/* }}} */
2205
2206
/* {{{ Return backtrace as array */
2207
ZEND_FUNCTION(debug_backtrace)
2208
310
{
2209
310
  zend_long options = DEBUG_BACKTRACE_PROVIDE_OBJECT;
2210
310
  zend_long limit = 0;
2211
2212
310
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "|ll", &options, &limit) == FAILURE) {
2213
0
    RETURN_THROWS();
2214
0
  }
2215
2216
310
  zend_fetch_debug_backtrace(return_value, 1, options, limit);
2217
310
}
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
8
{
2243
8
  zend_string *extension_name;
2244
8
  zend_string *lcname;
2245
8
  bool array;
2246
8
  zend_module_entry *module;
2247
8
  zend_function *zif;
2248
2249
8
  if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &extension_name) == FAILURE) {
2250
0
    RETURN_THROWS();
2251
0
  }
2252
8
  if (strncasecmp(ZSTR_VAL(extension_name), "zend", sizeof("zend"))) {
2253
8
    lcname = zend_string_tolower(extension_name);
2254
8
    module = zend_hash_find_ptr(&module_registry, lcname);
2255
8
    zend_string_release_ex(lcname, 0);
2256
8
  } else {
2257
0
    module = zend_hash_str_find_ptr(&module_registry, "core", sizeof("core") - 1);
2258
0
  }
2259
2260
8
  if (!module) {
2261
1
    RETURN_FALSE;
2262
1
  }
2263
2264
7
  if (module->functions) {
2265
    /* avoid BC break, if functions list is empty, will return an empty array */
2266
7
    array_init(return_value);
2267
7
    array = true;
2268
7
  } else {
2269
0
    array = false;
2270
0
  }
2271
2272
9.64k
  ZEND_HASH_MAP_FOREACH_PTR(CG(function_table), zif) {
2273
9.64k
    if (zif->common.type == ZEND_INTERNAL_FUNCTION
2274
4.81k
      && zif->internal_function.module == module) {
2275
3.58k
      if (!array) {
2276
0
        array_init(return_value);
2277
0
        array = true;
2278
0
      }
2279
3.58k
      add_next_index_str(return_value, zend_string_copy(zif->common.function_name));
2280
3.58k
    }
2281
9.64k
  } ZEND_HASH_FOREACH_END();
2282
2283
7
  if (!array) {
2284
0
    RETURN_FALSE;
2285
0
  }
2286
7
}
2287
/* }}} */