Coverage Report

Created: 2026-01-10 06:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libyang/src/tree_data_free.c
Line
Count
Source
1
/**
2
 * @file tree_data_free.c
3
 * @author Radek Krejci <rkrejci@cesnet.cz>
4
 * @brief Freeing functions for data tree structures
5
 *
6
 * Copyright (c) 2019 CESNET, z.s.p.o.
7
 *
8
 * This source code is licensed under BSD 3-Clause License (the "License").
9
 * You may not use this file except in compliance with the License.
10
 * You may obtain a copy of the License at
11
 *
12
 *     https://opensource.org/licenses/BSD-3-Clause
13
 */
14
15
#include <assert.h>
16
#include <stdlib.h>
17
18
#include "dict.h"
19
#include "hash_table.h"
20
#include "log.h"
21
#include "ly_common.h"
22
#include "plugins_exts/metadata.h"
23
#include "plugins_internal.h"
24
#include "plugins_types.h"
25
#include "tree.h"
26
#include "tree_data.h"
27
#include "tree_data_internal.h"
28
#include "tree_data_sorted.h"
29
#include "tree_schema.h"
30
31
static void
32
lyd_free_meta(struct lyd_meta *meta, ly_bool siblings)
33
1.93M
{
34
1.93M
    struct lyd_meta *iter;
35
36
1.93M
    if (!meta) {
37
1.90M
        return;
38
1.90M
    }
39
40
31.1k
    if (meta->parent) {
41
31.1k
        if (meta->parent->meta == meta) {
42
31.1k
            if (siblings) {
43
31.1k
                meta->parent->meta = NULL;
44
31.1k
            } else {
45
0
                meta->parent->meta = meta->next;
46
0
            }
47
31.1k
        } else {
48
0
            for (iter = meta->parent->meta; iter->next != meta; iter = iter->next) {}
49
0
            if (iter->next) {
50
0
                if (siblings) {
51
0
                    iter->next = NULL;
52
0
                } else {
53
0
                    iter->next = meta->next;
54
0
                }
55
0
            }
56
0
        }
57
31.1k
    }
58
59
31.1k
    if (!siblings) {
60
0
        meta->next = NULL;
61
0
    }
62
63
67.5k
    for (iter = meta; iter; ) {
64
36.3k
        meta = iter;
65
36.3k
        iter = iter->next;
66
67
36.3k
        lydict_remove(meta->annotation->module->ctx, meta->name);
68
36.3k
        LYSC_GET_TYPE_PLG(meta->value.realtype->plugin_ref)->free(meta->annotation->module->ctx, &meta->value);
69
36.3k
        free(meta);
70
36.3k
    }
71
31.1k
}
72
73
LIBYANG_API_DEF void
74
lyd_free_meta_single(struct lyd_meta *meta)
75
0
{
76
0
    lyd_free_meta(meta, 0);
77
0
}
78
79
LIBYANG_API_DEF void
80
lyd_free_meta_siblings(struct lyd_meta *meta)
81
1.93M
{
82
1.93M
    lyd_free_meta(meta, 1);
83
1.93M
}
84
85
static void
86
lyd_free_attr(const struct ly_ctx *ctx, struct lyd_attr *attr, ly_bool siblings)
87
939k
{
88
939k
    struct lyd_attr *iter;
89
90
939k
    LY_CHECK_ARG_RET(NULL, ctx, );
91
939k
    if (!attr) {
92
939k
        return;
93
939k
    }
94
95
113
    if (attr->parent) {
96
113
        if (attr->parent->attr == attr) {
97
113
            if (siblings) {
98
113
                attr->parent->attr = NULL;
99
113
            } else {
100
0
                attr->parent->attr = attr->next;
101
0
            }
102
113
        } else {
103
0
            for (iter = attr->parent->attr; iter->next != attr; iter = iter->next) {}
104
0
            if (iter->next) {
105
0
                if (siblings) {
106
0
                    iter->next = NULL;
107
0
                } else {
108
0
                    iter->next = attr->next;
109
0
                }
110
0
            }
111
0
        }
112
113
    }
113
114
113
    if (!siblings) {
115
0
        attr->next = NULL;
116
0
    }
117
118
2.86k
    for (iter = attr; iter; ) {
119
2.74k
        attr = iter;
120
2.74k
        iter = iter->next;
121
122
2.74k
        ly_free_prefix_data(attr->format, attr->val_prefix_data);
123
2.74k
        lydict_remove(ctx, attr->name.name);
124
2.74k
        lydict_remove(ctx, attr->name.prefix);
125
2.74k
        lydict_remove(ctx, attr->name.module_ns);
126
2.74k
        lydict_remove(ctx, attr->value);
127
2.74k
        free(attr);
128
2.74k
    }
129
113
}
130
131
LIBYANG_API_DEF void
132
lyd_free_attr_single(const struct ly_ctx *ctx, struct lyd_attr *attr)
133
0
{
134
0
    lyd_free_attr(ctx, attr, 0);
135
0
}
136
137
LIBYANG_API_DEF void
138
lyd_free_attr_siblings(const struct ly_ctx *ctx, struct lyd_attr *attr)
139
939k
{
140
939k
    lyd_free_attr(ctx, attr, 1);
141
939k
}
142
143
void
144
lyd_free_leafref_links_rec(struct lyd_leafref_links_rec *rec)
145
0
{
146
0
    LY_ARRAY_COUNT_TYPE u;
147
0
    struct lyd_leafref_links_rec *rec2;
148
149
0
    assert(rec);
150
151
    /* remove links of leafref nodes */
152
0
    LY_ARRAY_FOR(rec->leafref_nodes, u) {
153
0
        if (lyd_get_or_create_leafref_links_record(rec->leafref_nodes[u], &rec2, 0) == LY_SUCCESS) {
154
0
            LY_ARRAY_REMOVE_VALUE(rec2->target_nodes, rec->node);
155
0
            if ((LY_ARRAY_COUNT(rec2->leafref_nodes) == 0) && (LY_ARRAY_COUNT(rec2->target_nodes) == 0)) {
156
0
                lyd_free_leafref_nodes(rec->leafref_nodes[u]);
157
0
            }
158
0
        }
159
0
    }
160
0
    LY_ARRAY_FREE(rec->leafref_nodes);
161
0
    rec->leafref_nodes = NULL;
162
163
    /* remove links of target nodes */
164
0
    LY_ARRAY_FOR(rec->target_nodes, u) {
165
0
        if (lyd_get_or_create_leafref_links_record(rec->target_nodes[u], &rec2, 0) == LY_SUCCESS) {
166
0
            LY_ARRAY_REMOVE_VALUE(rec2->leafref_nodes, rec->node);
167
0
            if ((LY_ARRAY_COUNT(rec2->leafref_nodes) == 0) && (LY_ARRAY_COUNT(rec2->target_nodes) == 0)) {
168
0
                lyd_free_leafref_nodes(rec->target_nodes[u]);
169
0
            }
170
0
        }
171
0
    }
172
0
    LY_ARRAY_FREE(rec->target_nodes);
173
0
    rec->target_nodes = NULL;
174
0
}
175
176
void
177
lyd_free_leafref_nodes(const struct lyd_node_term *node)
178
1.10M
{
179
1.10M
    struct ly_ctx_shared_data *ctx_data;
180
1.10M
    uint32_t hash;
181
1.10M
    struct lyd_leafref_links_rec *rec;
182
183
1.10M
    assert(node);
184
185
1.10M
    if (lyd_get_or_create_leafref_links_record(node, &rec, 0)) {
186
1.10M
        return;
187
1.10M
    }
188
189
    /* free entry content */
190
0
    lyd_free_leafref_links_rec(rec);
191
192
    /* free entry itself from hash table */
193
0
    ctx_data = ly_ctx_shared_data_get(LYD_CTX(node));
194
0
    hash = lyht_hash((const char *)&node, sizeof node);
195
196
    /* LL LOCK */
197
0
    pthread_mutex_lock(&ctx_data->leafref_links_lock);
198
199
0
    lyht_remove(ctx_data->leafref_links_ht, &rec, hash);
200
201
    /* LL UNLOCK */
202
0
    pthread_mutex_unlock(&ctx_data->leafref_links_lock);
203
204
0
    free(rec);
205
0
}
206
207
/**
208
 * @brief Free Data (sub)tree.
209
 *
210
 * @param[in] node Data node to be freed.
211
 */
212
static void
213
lyd_free_subtree(struct lyd_node *node)
214
1.30M
{
215
1.30M
    struct lyd_node *iter, *next;
216
1.30M
    struct lyd_node_opaq *opaq = NULL;
217
218
1.30M
    assert(node);
219
220
1.30M
    if (!node->schema) {
221
155k
        opaq = (struct lyd_node_opaq *)node;
222
223
        /* free the children */
224
155k
        LY_LIST_FOR_SAFE(lyd_child(node), next, iter) {
225
82.7k
            lyd_free_subtree(iter);
226
82.7k
        }
227
228
155k
        lydict_remove(LYD_CTX(opaq), opaq->name.name);
229
155k
        lydict_remove(LYD_CTX(opaq), opaq->name.prefix);
230
155k
        lydict_remove(LYD_CTX(opaq), opaq->name.module_ns);
231
155k
        lydict_remove(LYD_CTX(opaq), opaq->value);
232
155k
        ly_free_prefix_data(opaq->format, opaq->val_prefix_data);
233
1.15M
    } else if (node->schema->nodetype & LYD_NODE_INNER) {
234
        /* remove children hash table in case of inner data node */
235
44.5k
        lyht_free(((struct lyd_node_inner *)node)->children_ht, NULL);
236
237
        /* free the children */
238
1.01M
        LY_LIST_FOR_SAFE(lyd_child(node), next, iter) {
239
1.01M
            lyd_free_subtree(iter);
240
1.01M
        }
241
1.10M
    } else if (node->schema->nodetype & LYD_NODE_ANY) {
242
        /* only frees the value this way */
243
0
        lyd_any_copy_value(node, NULL, 0);
244
1.10M
    } else if (node->schema->nodetype & LYD_NODE_TERM) {
245
1.10M
        struct lyd_node_term *node_term = (struct lyd_node_term *)node;
246
247
1.10M
        LYSC_GET_TYPE_PLG(((struct lysc_node_leaf *)node->schema)->type->plugin_ref)->free(LYD_CTX(node), &node_term->value);
248
1.10M
        lyd_free_leafref_nodes(node_term);
249
1.10M
    }
250
251
1.30M
    if (!node->schema) {
252
155k
        lyd_free_attr_siblings(LYD_CTX(node), opaq->attr);
253
1.15M
    } else {
254
        /* free the node's metadata */
255
1.15M
        lyd_free_meta_siblings(node->meta);
256
1.15M
    }
257
258
1.30M
    free(node);
259
1.30M
}
260
261
LIBYANG_API_DEF void
262
lyd_free_tree(struct lyd_node *node)
263
81.5k
{
264
81.5k
    if (!node) {
265
17.8k
        return;
266
17.8k
    }
267
268
63.6k
    if (lysc_is_key(node->schema) && node->parent) {
269
0
        LOGERR(LYD_CTX(node), LY_EINVAL, "Cannot free a list key \"%s\", free the list instance instead.", LYD_NAME(node));
270
0
        return;
271
0
    }
272
273
63.6k
    lyd_unlink(node);
274
63.6k
    lyd_free_subtree(node);
275
63.6k
}
276
277
static void
278
lyd_free_(struct lyd_node *node)
279
3.16k
{
280
3.16k
    struct lyd_node *iter, *next, *first_sibling = NULL;
281
282
3.16k
    if (!node) {
283
0
        return;
284
0
    }
285
286
145k
    LY_LIST_FOR_SAFE(lyd_first_sibling(node), next, iter) {
287
145k
        if (lysc_is_key(iter->schema) && iter->parent) {
288
0
            LOGERR(LYD_CTX(iter), LY_EINVAL, "Cannot free a list key \"%s\", free the list instance instead.", LYD_NAME(iter));
289
0
            return;
290
0
        }
291
292
        /* in case of the top-level nodes (node->parent is NULL), no unlinking needed */
293
145k
        if (iter->parent) {
294
0
            lyds_free_metadata(iter);
295
0
            lyd_unlink_ignore_lyds(&first_sibling, iter);
296
0
        }
297
145k
        lyd_free_subtree(iter);
298
145k
    }
299
3.16k
}
300
301
LIBYANG_API_DEF void
302
lyd_free_siblings(struct lyd_node *node)
303
0
{
304
0
    lyd_free_(node);
305
0
}
306
307
LIBYANG_API_DEF void
308
lyd_free_all(struct lyd_node *node)
309
27.2k
{
310
27.2k
    if (!node) {
311
24.0k
        return;
312
24.0k
    }
313
314
    /* get top-level node */
315
3.16k
    for ( ; node->parent; node = lyd_parent(node)) {}
316
317
3.16k
    lyd_free_(node);
318
3.16k
}