From 1eefadfc7469ca0007e30e62c5aa1409a4fec9a5 Mon Sep 17 00:00:00 2001 From: Olof hagsand Date: Thu, 22 Dec 2022 17:32:40 +0100 Subject: [PATCH] Fixed memory leak in xmld database put code C: refactored choice validate code --- lib/src/clixon_datastore_write.c | 15 +++- lib/src/clixon_validate.c | 143 +++++++++++++++++++++++-------- 2 files changed, 123 insertions(+), 35 deletions(-) diff --git a/lib/src/clixon_datastore_write.c b/lib/src/clixon_datastore_write.c index b54e2cb1..24f57255 100644 --- a/lib/src/clixon_datastore_write.c +++ b/lib/src/clixon_datastore_write.c @@ -130,8 +130,11 @@ attr_ns_value(cxobj *x, } } *valp = val; + val = NULL; retval = 1; done: + if (val) + free(val); return retval; fail: retval = 0; @@ -945,8 +948,16 @@ text_modify(clicon_handle h, } /* else Y_CONTAINER */ retval = 1; done: + if (valstr) + free(valstr); + if (keystr) + free(keystr); + if (instr) + free(instr); if (opstr) free(opstr); + if (createstr) + free(createstr); if (nscx1) xml_nsctx_free(nscx1); /* Remove dangling added objects */ @@ -996,7 +1007,7 @@ text_modify_top(clicon_handle h, cxobj *x1c; /* mod child */ yang_stmt *yc; /* yang child */ yang_stmt *ymod;/* yang module */ - char *opstr; + char *opstr = NULL; int ret; char *createstr = NULL; @@ -1121,6 +1132,8 @@ text_modify_top(clicon_handle h, done: if (opstr) free(opstr); + if (createstr) + free(createstr); return retval; fail: /* cbret set */ retval = 0; diff --git a/lib/src/clixon_validate.c b/lib/src/clixon_validate.c index e1a942aa..e56d21c3 100644 --- a/lib/src/clixon_validate.c +++ b/lib/src/clixon_validate.c @@ -75,8 +75,8 @@ #include "clixon_xpath.h" #include "clixon_yang_module.h" #include "clixon_yang_type.h" -#include "clixon_xml_map.h" #include "clixon_xml_default.h" +#include "clixon_xml_map.h" #include "clixon_xml_bind.h" #include "clixon_validate_minmax.h" #include "clixon_validate.h" @@ -479,46 +479,34 @@ xml_yang_validate_rpc_reply(clicon_handle h, goto done; } -/*! Check if an xml node is a part of a choice and have >1 siblings - * @param[in] xt XML node to be validated - * @param[in] yt xt:s yang statement - * @param[out] xret Error XML tree. Free with xml_free after use - * @retval 1 Validation OK - * @retval 0 Validation failed (cbret set) - * @retval -1 Error - * Check if xt is part of valid choice +/*! Check if an xml choice node xp has children in same case + * + * @param[in] xp XML choice node to be validated + * @param[in] ytchoice Yang spec of choice + * @param[in] ytcase Yang spec of case, optional + * @param[in] xt XML child + * @param[out] xret Error XML tree. Free with xml_free after use + * @retval 1 Validation OK + * @retval 0 Validation failed (cbret set) + * @retval -1 Error + * From RFC7950 Sec 7.9.3 + * 1. Default case, the default if no child nodes from any of the choice's cases exist + * 2. Default for child nodes under a case are only used if one of the nodes under that case + * is present */ static int -check_choice(cxobj *xt, +check_choice(cxobj *xp, + yang_stmt *ytchoice, + yang_stmt *ytcase, + cxobj *xt, yang_stmt *yt, cxobj **xret) { int retval = -1; - yang_stmt *y; - yang_stmt *ytp; /* yt:s parent */ - yang_stmt *ytcase = NULL; /* yt:s parent case if any */ - yang_stmt *ytchoice = NULL; - yang_stmt *yp; cxobj *x; - cxobj *xp; + yang_stmt *y; + yang_stmt *yp; - if ((ytp = yang_parent_get(yt)) == NULL) - goto ok; - /* Return OK if xt is not choice */ - switch (yang_keyword_get(ytp)){ - case Y_CASE: - ytcase = ytp; - ytchoice = yang_parent_get(ytp); - break; - case Y_CHOICE: - ytchoice = ytp; - break; - default: - goto ok; /* Not choice */ - break; - } - if ((xp = xml_parent(xt)) == NULL) - goto ok; x = NULL; /* Find a child with same yang spec */ while ((x = xml_child_each(xp, x, CX_ELMNT)) != NULL) { if (x == xt) @@ -546,6 +534,93 @@ check_choice(cxobj *xt, goto done; goto fail; } /* while */ + retval = 1; + done: + return retval; + fail: + retval = 0; + goto done; +} + +/*! Check if an xml node xt is a part of a choice and have >1 siblings + * @param[in] xt XML node to be validated + * @param[in] yt xt:s yang statement + * @param[out] xret Error XML tree. Free with xml_free after use + * @retval 1 Validation OK + * @retval 0 Validation failed (cbret set) + * @retval -1 Error + * Check if xt is part of valid choice + * XXX does not check: xt is choice and has n children, but there exists a default child + */ +static int +check_choice_child(cxobj *xt, + yang_stmt *yt, + cxobj **xret) +{ + int retval = -1; + + yang_stmt *ytp; /* yt:s parent */ + yang_stmt *ytcase = NULL; /* yt:s parent case if any */ + yang_stmt *ytchoice = NULL; + int ret; + cxobj *xp; +#if 0 + cxobj *x; + yang_stmt *yp; + yang_stmt *y; +#endif + + if ((ytp = yang_parent_get(yt)) == NULL) + goto ok; + /* Return OK if xt is not choice */ + switch (yang_keyword_get(ytp)){ + case Y_CASE: + ytcase = ytp; + ytchoice = yang_parent_get(ytp); + break; + case Y_CHOICE: + ytchoice = ytp; + break; + default: + goto ok; /* Not choice */ + break; + } + if ((xp = xml_parent(xt)) == NULL) + goto ok; +#if 1 + if ((ret = check_choice(xp, ytchoice, ytcase, xt, yt, xret)) < 0) + goto done; + if (ret == 0) + goto fail; +#else + x = NULL; /* Find a child with same yang spec */ + while ((x = xml_child_each(xp, x, CX_ELMNT)) != NULL) { + if (x == xt) + continue; + y = xml_spec(x); + if (y == yt) /* eg same list */ + continue; + yp = yang_parent_get(y); + switch (yang_keyword_get(yp)){ + case Y_CASE: + if (yang_parent_get(yp) != ytchoice) /* Not same choice (not relevant) */ + continue; + if (yp == ytcase) /* same choice but different case */ + continue; + break; + case Y_CHOICE: + if (yp != ytchoice) /* Not same choice (not relevant) */ + continue; + break; + default: + continue; /* not choice */ + break; + } + if (xret && netconf_bad_element_xml(xret, "application", xml_name(x), "Element in choice statement already exists") < 0) + goto done; + goto fail; + } /* while */ +#endif ok: retval = 1; done: @@ -919,7 +994,7 @@ xml_yang_validate_add(clicon_handle h, /* if not given by argument (overide) use default link and !Node has a config sub-statement and it is false */ if ((yt = xml_spec(xt)) != NULL && yang_config(yt) != 0){ - if ((ret = check_choice(xt, yt, xret)) < 0) + if ((ret = check_choice_child(xt, yt, xret)) < 0) goto done; if (ret == 0) goto fail;