Coverage Report

Created: 2026-08-12 06:45

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