From 2f445d56286d14554ab0ed9992c75596956ebd67 Mon Sep 17 00:00:00 2001 From: Affan Ziya Date: Tue, 27 Oct 2026 07:37:47 +0530 Subject: [PATCH] printer cbor BUGFIX double free when printing opaque lists --- src/printer_cbor.c | 46 +++++++++++++++++++---------------- tests/utests/data/test_cbor.c | 35 ++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 21 deletions(-) diff --git a/src/printer_cbor.c b/src/printer_cbor.c index d4a4a80f9..4b22b5d36 100644 --- a/src/printer_cbor.c +++ b/src/printer_cbor.c @@ -1148,15 +1148,15 @@ cbor_print_opaq(struct cborpr_ctx *pctx, const struct lyd_node_opaq *node, cbor_ } if (first) { - key = cbor_print_member_name2(pctx, pctx->parent, node->format, &node->name, 0); - LY_CHECK_RET(!key, LY_EMEM); - if (hints & (LYD_NODEHINT_LIST | LYD_NODEHINT_LEAFLIST)) { + /* start new array, the member name is generated once the array is completed */ cbor_item_t *new_array = cbor_new_indefinite_array(); - LY_CHECK_ERR_RET(!new_array, free(key), LY_EMEM); - LY_CHECK_ERR_RET(cbor_print_array_open(pctx, &node->node, new_array), - cbor_decref(&new_array); free(key), LY_EINVAL); + LY_CHECK_RET(!new_array, LY_EMEM); + LY_CHECK_ERR_RET(cbor_print_array_open(pctx, &node->node, new_array), cbor_decref(&new_array), LY_EINVAL); + } else { + key = cbor_print_member_name2(pctx, pctx->parent, node->format, &node->name, 0); + LY_CHECK_RET(!key, LY_EMEM); } } @@ -1238,25 +1238,29 @@ cbor_print_opaq(struct cborpr_ctx *pctx, const struct lyd_node_opaq *node, cbor_ } if (last && (hints & (LYD_NODEHINT_LIST | LYD_NODEHINT_LEAFLIST))) { - if (key) { - struct cbor_pair pair = { - .key = cbor_move(cbor_build_string(key)), - .value = cbor_move(cbor_current_array(pctx)) - }; + cbor_item_t *array = cbor_current_array(pctx); - free(key); - - if (!cbor_map_add(parent_map, pair)) { - cbor_decref(&pair.key); - cbor_decref(&pair.value); - return LY_EMEM; - } + key = cbor_print_member_name2(pctx, pctx->parent, node->format, &node->name, 0); + if (!key) { + cbor_decref(&array); + cbor_print_array_close(pctx); + return LY_EMEM; } - cbor_print_array_close(pctx); - } - if (key) { + /* add completed array to parent map */ + struct cbor_pair pair = { + .key = cbor_move(cbor_build_string(key)), + .value = cbor_move(array) + }; + free(key); + + if (!cbor_map_add(parent_map, pair)) { + cbor_decref(&pair.key); + cbor_decref(&pair.value); + return LY_EMEM; + } + cbor_print_array_close(pctx); } return LY_SUCCESS; diff --git a/tests/utests/data/test_cbor.c b/tests/utests/data/test_cbor.c index 135ed9e1c..e141e960d 100644 --- a/tests/utests/data/test_cbor.c +++ b/tests/utests/data/test_cbor.c @@ -365,6 +365,40 @@ test_opaque(void **state) lyd_free_all(tree); } +static void +test_opaque_list(void **state) +{ + struct lyd_node *tree; + char *buffer, *json; + struct ly_out *out; + size_t i; + + /* invalid leaf-list values are stored as opaque nodes, one and more instances */ + const struct test_case tests[] = { + {"single", "{\"cbor-test:ll-intg32\":[\"not a number\"]}"}, + {"multiple", "{\"cbor-test:ll-intg32\":[\"x\",\"y\",\"z\"]}"}, + {"nested", "{\"cbor-test:list-nested\":[{\"id\":\"a\",\"inner\":[{\"iid\":1,\"vals\":[\"q\"]}]}]}"}, + }; + + for (i = 0; i < sizeof tests / sizeof *tests; ++i) { + CHECK_PARSE_LYD_PARAM(tests[i].json, LYD_JSON, LYD_PARSE_ONLY | LYD_PARSE_OPAQ, 0, LY_SUCCESS, tree); + + assert_int_equal(LY_SUCCESS, ly_out_new_memory(&buffer, 0, &out)); + assert_int_equal(LY_SUCCESS, lyd_print_all(out, tree, LYD_CBOR, 0)); + lyd_free_all(tree); + + assert_int_equal(LY_SUCCESS, lyd_parse_data_mem_len(UTEST_LYCTX, buffer, (uint32_t)ly_out_printed(out), LYD_CBOR, + LYD_PARSE_ONLY | LYD_PARSE_OPAQ, 0, &tree)); + ly_out_free(out, NULL, 0); + free(buffer); + + assert_int_equal(LY_SUCCESS, lyd_print_mem(&json, tree, LYD_JSON, LYD_PRINT_SHRINK | LYD_PRINT_SIBLINGS)); + assert_string_equal(json, tests[i].json); + free(json); + lyd_free_all(tree); + } +} + static void test_attributes(void **state) { @@ -404,6 +438,7 @@ main(void) UTEST(test_operations, setup), UTEST(test_schema_mount, setup), UTEST(test_opaque, setup), + UTEST(test_opaque_list, setup), UTEST(test_attributes, setup), };