Fixed memory leak in xmld database put code

C: refactored choice validate code
This commit is contained in:
Olof hagsand 2022-12-22 17:32:40 +01:00
parent b67ef69b7f
commit 1eefadfc74
2 changed files with 123 additions and 35 deletions

View file

@ -130,8 +130,11 @@ attr_ns_value(cxobj *x,
} }
} }
*valp = val; *valp = val;
val = NULL;
retval = 1; retval = 1;
done: done:
if (val)
free(val);
return retval; return retval;
fail: fail:
retval = 0; retval = 0;
@ -945,8 +948,16 @@ text_modify(clicon_handle h,
} /* else Y_CONTAINER */ } /* else Y_CONTAINER */
retval = 1; retval = 1;
done: done:
if (valstr)
free(valstr);
if (keystr)
free(keystr);
if (instr)
free(instr);
if (opstr) if (opstr)
free(opstr); free(opstr);
if (createstr)
free(createstr);
if (nscx1) if (nscx1)
xml_nsctx_free(nscx1); xml_nsctx_free(nscx1);
/* Remove dangling added objects */ /* Remove dangling added objects */
@ -996,7 +1007,7 @@ text_modify_top(clicon_handle h,
cxobj *x1c; /* mod child */ cxobj *x1c; /* mod child */
yang_stmt *yc; /* yang child */ yang_stmt *yc; /* yang child */
yang_stmt *ymod;/* yang module */ yang_stmt *ymod;/* yang module */
char *opstr; char *opstr = NULL;
int ret; int ret;
char *createstr = NULL; char *createstr = NULL;
@ -1121,6 +1132,8 @@ text_modify_top(clicon_handle h,
done: done:
if (opstr) if (opstr)
free(opstr); free(opstr);
if (createstr)
free(createstr);
return retval; return retval;
fail: /* cbret set */ fail: /* cbret set */
retval = 0; retval = 0;

View file

@ -75,8 +75,8 @@
#include "clixon_xpath.h" #include "clixon_xpath.h"
#include "clixon_yang_module.h" #include "clixon_yang_module.h"
#include "clixon_yang_type.h" #include "clixon_yang_type.h"
#include "clixon_xml_map.h"
#include "clixon_xml_default.h" #include "clixon_xml_default.h"
#include "clixon_xml_map.h"
#include "clixon_xml_bind.h" #include "clixon_xml_bind.h"
#include "clixon_validate_minmax.h" #include "clixon_validate_minmax.h"
#include "clixon_validate.h" #include "clixon_validate.h"
@ -479,46 +479,34 @@ xml_yang_validate_rpc_reply(clicon_handle h,
goto done; goto done;
} }
/*! Check if an xml node is a part of a choice and have >1 siblings /*! Check if an xml choice node xp has children in same case
* @param[in] xt XML node to be validated *
* @param[in] yt xt:s yang statement * @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 * @param[out] xret Error XML tree. Free with xml_free after use
* @retval 1 Validation OK * @retval 1 Validation OK
* @retval 0 Validation failed (cbret set) * @retval 0 Validation failed (cbret set)
* @retval -1 Error * @retval -1 Error
* Check if xt is part of valid choice * 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 static int
check_choice(cxobj *xt, check_choice(cxobj *xp,
yang_stmt *ytchoice,
yang_stmt *ytcase,
cxobj *xt,
yang_stmt *yt, yang_stmt *yt,
cxobj **xret) cxobj **xret)
{ {
int retval = -1; 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 *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 */ x = NULL; /* Find a child with same yang spec */
while ((x = xml_child_each(xp, x, CX_ELMNT)) != NULL) { while ((x = xml_child_each(xp, x, CX_ELMNT)) != NULL) {
if (x == xt) if (x == xt)
@ -546,6 +534,93 @@ check_choice(cxobj *xt,
goto done; goto done;
goto fail; goto fail;
} /* while */ } /* 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: ok:
retval = 1; retval = 1;
done: done:
@ -919,7 +994,7 @@ xml_yang_validate_add(clicon_handle h,
/* if not given by argument (overide) use default link /* if not given by argument (overide) use default link
and !Node has a config sub-statement and it is false */ and !Node has a config sub-statement and it is false */
if ((yt = xml_spec(xt)) != NULL && yang_config(yt) != 0){ 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; goto done;
if (ret == 0) if (ret == 0)
goto fail; goto fail;