Coverage Report

Created: 2026-06-02 06:36

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/php-src/Zend/zend_variables.c
Line
Count
Source
1
/*
2
   +----------------------------------------------------------------------+
3
   | Zend Engine                                                          |
4
   +----------------------------------------------------------------------+
5
   | Copyright © Zend Technologies Ltd., a subsidiary company of          |
6
   |     Perforce Software, Inc., and Contributors.                       |
7
   +----------------------------------------------------------------------+
8
   | This source file is subject to the Modified BSD License that is      |
9
   | bundled with this package in the file LICENSE, and is available      |
10
   | through the World Wide Web at <https://www.php.net/license/>.        |
11
   |                                                                      |
12
   | SPDX-License-Identifier: BSD-3-Clause                                |
13
   +----------------------------------------------------------------------+
14
   | Authors: Andi Gutmans <andi@php.net>                                 |
15
   |          Zeev Suraski <zeev@php.net>                                 |
16
   |          Dmitry Stogov <dmitry@php.net>                              |
17
   +----------------------------------------------------------------------+
18
*/
19
20
#include <stdio.h>
21
#include "zend.h"
22
#include "zend_API.h"
23
#include "zend_ast.h"
24
#include "zend_globals.h"
25
#include "zend_constants.h"
26
#include "zend_list.h"
27
28
#if ZEND_DEBUG
29
static void ZEND_FASTCALL zend_string_destroy(zend_string *str);
30
#else
31
# define zend_string_destroy _efree
32
#endif
33
static void ZEND_FASTCALL zend_reference_destroy(zend_reference *ref);
34
static void ZEND_FASTCALL zend_empty_destroy(zend_reference *ref);
35
36
typedef void (ZEND_FASTCALL *zend_rc_dtor_func_t)(zend_refcounted *p);
37
38
static const zend_rc_dtor_func_t zend_rc_dtor_func[] = {
39
  [IS_UNDEF] =        (zend_rc_dtor_func_t)zend_empty_destroy,
40
  [IS_NULL] =         (zend_rc_dtor_func_t)zend_empty_destroy,
41
  [IS_FALSE] =        (zend_rc_dtor_func_t)zend_empty_destroy,
42
  [IS_TRUE] =         (zend_rc_dtor_func_t)zend_empty_destroy,
43
  [IS_LONG] =         (zend_rc_dtor_func_t)zend_empty_destroy,
44
  [IS_DOUBLE] =       (zend_rc_dtor_func_t)zend_empty_destroy,
45
  [IS_STRING] =       (zend_rc_dtor_func_t)zend_string_destroy,
46
  [IS_ARRAY] =        (zend_rc_dtor_func_t)zend_array_destroy,
47
  [IS_OBJECT] =       (zend_rc_dtor_func_t)zend_objects_store_del,
48
  [IS_RESOURCE] =     (zend_rc_dtor_func_t)zend_list_free,
49
  [IS_REFERENCE] =    (zend_rc_dtor_func_t)zend_reference_destroy,
50
  [IS_CONSTANT_AST] = (zend_rc_dtor_func_t)zend_ast_ref_destroy
51
};
52
53
ZEND_API void ZEND_FASTCALL rc_dtor_func(zend_refcounted *p)
54
346k
{
55
346k
  ZEND_ASSERT(GC_TYPE(p) <= IS_CONSTANT_AST);
56
346k
  zend_rc_dtor_func[GC_TYPE(p)](p);
57
346k
}
58
59
#if ZEND_DEBUG
60
static void ZEND_FASTCALL zend_string_destroy(zend_string *str)
61
154k
{
62
154k
  CHECK_ZVAL_STRING(str);
63
154k
  ZEND_ASSERT(!ZSTR_IS_INTERNED(str));
64
154k
  ZEND_ASSERT(GC_REFCOUNT(str) == 0);
65
154k
  ZEND_ASSERT(!(GC_FLAGS(str) & IS_STR_PERSISTENT));
66
154k
  efree(str);
67
154k
}
68
#endif
69
70
static void ZEND_FASTCALL zend_reference_destroy(zend_reference *ref)
71
1.90k
{
72
1.90k
  ZEND_ASSERT(!ZEND_REF_HAS_TYPE_SOURCES(ref));
73
1.90k
  i_zval_ptr_dtor(&ref->val);
74
1.90k
  efree_size(ref, sizeof(zend_reference));
75
1.90k
}
76
77
static void ZEND_FASTCALL zend_empty_destroy(zend_reference *ref)
78
42
{
79
42
}
80
81
ZEND_API void zval_ptr_dtor(zval *zval_ptr) /* {{{ */
82
2.67M
{
83
2.67M
  i_zval_ptr_dtor(zval_ptr);
84
2.67M
}
85
/* }}} */
86
87
ZEND_API void zval_ptr_safe_dtor(zval *zval_ptr)
88
56.9k
{
89
56.9k
  if (Z_REFCOUNTED_P(zval_ptr)) {
90
2
    zend_refcounted *ref = Z_COUNTED_P(zval_ptr);
91
92
2
    if (GC_DELREF(ref) == 0) {
93
1
      ZVAL_NULL(zval_ptr);
94
1
      rc_dtor_func(ref);
95
1
    } else {
96
1
      gc_check_possible_root(ref);
97
1
    }
98
2
  }
99
56.9k
}
100
101
ZEND_API void zval_internal_ptr_dtor(zval *zval_ptr) /* {{{ */
102
0
{
103
0
  if (Z_REFCOUNTED_P(zval_ptr)) {
104
0
    zend_refcounted *ref = Z_COUNTED_P(zval_ptr);
105
106
0
    if (GC_DELREF(ref) == 0) {
107
0
      if (Z_TYPE_P(zval_ptr) == IS_STRING) {
108
0
        zend_string *str = (zend_string*)ref;
109
110
0
        CHECK_ZVAL_STRING(str);
111
0
        ZEND_ASSERT(!ZSTR_IS_INTERNED(str));
112
0
        ZEND_ASSERT((GC_FLAGS(str) & IS_STR_PERSISTENT));
113
0
        free(str);
114
0
      } else {
115
0
        zend_error_noreturn(E_CORE_ERROR, "Internal zval's can't be arrays, objects, resources or reference");
116
0
      }
117
0
    }
118
0
  }
119
0
}
120
/* }}} */
121
122
/* This function should only be used as a copy constructor, i.e. it
123
 * should only be called AFTER a zval has been copied to another
124
 * location using ZVAL_COPY_VALUE. Do not call it before copying,
125
 * otherwise a reference may be leaked. */
126
ZEND_API void zval_add_ref(zval *p)
127
31
{
128
31
  if (Z_REFCOUNTED_P(p)) {
129
22
    if (Z_ISREF_P(p) && Z_REFCOUNT_P(p) == 1) {
130
1
      ZVAL_COPY(p, Z_REFVAL_P(p));
131
21
    } else {
132
21
      Z_ADDREF_P(p);
133
21
    }
134
22
  }
135
31
}
136
137
ZEND_API void ZEND_FASTCALL zval_copy_ctor_func(zval *zvalue)
138
19
{
139
19
  if (EXPECTED(Z_TYPE_P(zvalue) == IS_ARRAY)) {
140
0
    ZVAL_ARR(zvalue, zend_array_dup(Z_ARRVAL_P(zvalue)));
141
19
  } else if (EXPECTED(Z_TYPE_P(zvalue) == IS_STRING)) {
142
19
    ZEND_ASSERT(!ZSTR_IS_INTERNED(Z_STR_P(zvalue)));
143
19
    CHECK_ZVAL_STRING(Z_STR_P(zvalue));
144
19
    ZVAL_NEW_STR(zvalue, zend_string_dup(Z_STR_P(zvalue), 0));
145
19
  } else {
146
    ZEND_UNREACHABLE();
147
0
  }
148
19
}