diff --git a/src/context.c b/src/context.c index 2345cf233..7a57e6285 100644 --- a/src/context.c +++ b/src/context.c @@ -272,9 +272,9 @@ ly_ctx_ht_err_equal_cb(void *val1_p, void *val2_p, ly_bool UNUSED(mod), void *UN static ly_bool ly_ctx_ht_leafref_links_equal_cb(void *val1_p, void *val2_p, ly_bool UNUSED(mod), void *UNUSED(cb_data)) { - struct lyd_leafref_links_rec *rec1 = val1_p, *rec2 = val2_p; + struct lyd_leafref_links_rec **rec1 = val1_p, **rec2 = val2_p; - return rec1->node == rec2->node; + return (*rec1)->node == (*rec2)->node; } /** @@ -285,9 +285,10 @@ ly_ctx_ht_leafref_links_equal_cb(void *val1_p, void *val2_p, ly_bool UNUSED(mod) static void ly_ctx_ht_leafref_links_rec_free(void *val_p) { - struct lyd_leafref_links_rec *rec = val_p; + struct lyd_leafref_links_rec **rec = val_p; - lyd_free_leafref_links_rec(rec); + lyd_free_leafref_links_rec(*rec); + free(*rec); } LIBYANG_API_DEF LY_ERR @@ -316,7 +317,12 @@ ly_ctx_new(const char *search_dir, uint16_t options, struct ly_ctx **new_ctx) LY_CHECK_ERR_GOTO(lyplg_init(builtin_plugins_only), LOGINT(NULL); rc = LY_EINT, cleanup); if (options & LY_CTX_LEAFREF_LINKING) { - ctx->leafref_links_ht = lyht_new(1, sizeof(struct lyd_leafref_links_rec), ly_ctx_ht_leafref_links_equal_cb, NULL, 1); + /** + * storing the pointer instead of record itself is needed to avoid invalid memory reads. Hash table can reallocate + * its memory completely during various manipulation function (e.g. remove, insert). In case of using pointers, the + * pointer can be reallocated safely, while record itself remains untouched and can be accessed/modified freely + * */ + ctx->leafref_links_ht = lyht_new(1, sizeof(struct lyd_leafref_links_rec *), ly_ctx_ht_leafref_links_equal_cb, NULL, 1); LY_CHECK_ERR_GOTO(!ctx->leafref_links_ht, rc = LY_EMEM, cleanup); } @@ -654,7 +660,7 @@ ly_ctx_set_options(struct ly_ctx *ctx, uint16_t option) } if (!(ctx->flags & LY_CTX_LEAFREF_LINKING) && (option & LY_CTX_LEAFREF_LINKING)) { - ctx->leafref_links_ht = lyht_new(1, sizeof(struct lyd_leafref_links_rec), ly_ctx_ht_leafref_links_equal_cb, NULL, 1); + ctx->leafref_links_ht = lyht_new(1, sizeof(struct lyd_leafref_links_rec *), ly_ctx_ht_leafref_links_equal_cb, NULL, 1); LY_CHECK_ERR_RET(!ctx->leafref_links_ht, LOGARG(ctx, option), LY_EMEM); } diff --git a/src/tree_data.c b/src/tree_data.c index b53a1a195..cb2edd834 100644 --- a/src/tree_data.c +++ b/src/tree_data.c @@ -3610,8 +3610,11 @@ LY_ERR lyd_get_or_create_leafref_links_record(const struct lyd_node_term *node, struct lyd_leafref_links_rec **record, ly_bool create) { struct ly_ht *ht; + LY_ERR ret = LY_SUCCESS; uint32_t hash; struct lyd_leafref_links_rec rec = {0}; + struct lyd_leafref_links_rec *rec_p = &rec; + struct lyd_leafref_links_rec **rec_p2; assert(node); assert(record); @@ -3626,15 +3629,23 @@ lyd_get_or_create_leafref_links_record(const struct lyd_node_term *node, struct ht = LYD_CTX(node)->leafref_links_ht; hash = lyht_hash((const char *)&node, sizeof node); - if (lyht_find(ht, &rec, hash, (void **)record) == LY_ENOTFOUND) { + if (lyht_find(ht, &rec_p, hash, (void **)&rec_p2) == LY_ENOTFOUND) { if (create) { - LY_CHECK_RET(lyht_insert_no_check(ht, &rec, hash, (void **)record)); + rec_p = calloc(1, sizeof rec); + rec_p->node = node; + LY_CHECK_ERR_RET(!rec_p, LOGMEM(LYD_CTX(node)), LY_EMEM); + ret = lyht_insert_no_check(ht, &rec_p, hash, (void **)&rec_p2); + LY_CHECK_ERR_GOTO(ret, free(rec_p), cleanup); } else { return LY_ENOTFOUND; } } - return LY_SUCCESS; +cleanup: + if (!ret) { + *record = *rec_p2; + } + return ret; } LIBYANG_API_DEF LY_ERR diff --git a/src/tree_data_free.c b/src/tree_data_free.c index 32d32cc4e..893dfec46 100644 --- a/src/tree_data_free.c +++ b/src/tree_data_free.c @@ -191,7 +191,8 @@ lyd_free_leafref_nodes(const struct lyd_node_term *node) /* free entry itself from hash table */ ht = LYD_CTX(node)->leafref_links_ht; hash = lyht_hash((const char *)&node, sizeof node); - lyht_remove(ht, rec, hash); + lyht_remove(ht, &rec, hash); + free(rec); } /**