Fixed: XPath evaluation of two nodes reverted to strcmp even if both were numbers
This commit is contained in:
parent
ffe918dd0e
commit
b67ef69b7f
2 changed files with 149 additions and 33 deletions
|
|
@ -147,6 +147,7 @@ Developers may need to change their code
|
||||||
|
|
||||||
### Corrected Bugs
|
### Corrected Bugs
|
||||||
|
|
||||||
|
* Fixed: XPath evaluation of two nodes reverted to strcmp even if both were numbers
|
||||||
* Fixed: [Yang identityref XML encoding is not general](https://github.com/clicon/clixon/issues/90)
|
* Fixed: [Yang identityref XML encoding is not general](https://github.com/clicon/clixon/issues/90)
|
||||||
* Revisiting this issue now seems to work, there are no regressions that fail when disabling IDENTITYREF_KLUDGE.
|
* Revisiting this issue now seems to work, there are no regressions that fail when disabling IDENTITYREF_KLUDGE.
|
||||||
* Fixed several xpath crashes discovered by unit xpath fuzzing
|
* Fixed several xpath crashes discovered by unit xpath fuzzing
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,7 @@
|
||||||
#include "clixon_hash.h"
|
#include "clixon_hash.h"
|
||||||
#include "clixon_handle.h"
|
#include "clixon_handle.h"
|
||||||
#include "clixon_yang.h"
|
#include "clixon_yang.h"
|
||||||
|
#include "clixon_yang_type.h"
|
||||||
#include "clixon_xml.h"
|
#include "clixon_xml.h"
|
||||||
#include "clixon_xml_sort.h"
|
#include "clixon_xml_sort.h"
|
||||||
#include "clixon_xml_nsctx.h"
|
#include "clixon_xml_nsctx.h"
|
||||||
|
|
@ -676,6 +677,76 @@ xp_numop(xp_ctx *xc1,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! Get xml body value as cligen variable
|
||||||
|
* @param[in] x XML node (body and leaf/leaf-list)
|
||||||
|
* @param[out] cvp Pointer to cligen variable containing value of x body
|
||||||
|
* @retval 0 OK, cvp contains cv or NULL
|
||||||
|
* @retval -1 Error
|
||||||
|
* @note only applicable if x is body and has yang-spec and is leaf or leaf-list
|
||||||
|
* Move to clixon_xml.c?
|
||||||
|
* As a side-effect sets the cache.
|
||||||
|
* Clear cache with xml_cv_set(x, NULL)
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
xml_cv_cache(cxobj *x,
|
||||||
|
cg_var **cvp)
|
||||||
|
{
|
||||||
|
int retval = -1;
|
||||||
|
cg_var *cv = NULL;
|
||||||
|
yang_stmt *y;
|
||||||
|
yang_stmt *yrestype;
|
||||||
|
enum cv_type cvtype;
|
||||||
|
int ret;
|
||||||
|
char *reason=NULL;
|
||||||
|
int options = 0;
|
||||||
|
uint8_t fraction = 0;
|
||||||
|
char *body;
|
||||||
|
|
||||||
|
if ((body = xml_body(x)) == NULL)
|
||||||
|
body="";
|
||||||
|
if ((cv = xml_cv(x)) != NULL)
|
||||||
|
goto ok;
|
||||||
|
if ((y = xml_spec(x)) == NULL){
|
||||||
|
clicon_err(OE_XML, EFAULT, "Yang binding missing for xml symbol %s, body:%s", xml_name(x), body);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (yang_type_get(y, NULL, &yrestype, &options, NULL, NULL, NULL, &fraction) < 0)
|
||||||
|
goto done;
|
||||||
|
yang2cv_type(yang_argument_get(yrestype), &cvtype);
|
||||||
|
if (cvtype==CGV_ERR){
|
||||||
|
clicon_err(OE_YANG, errno, "yang->cligen type %s mapping failed",
|
||||||
|
yang_argument_get(yrestype));
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if ((cv = cv_new(cvtype)) == NULL){
|
||||||
|
clicon_err(OE_YANG, errno, "cv_new");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (cvtype == CGV_DEC64)
|
||||||
|
cv_dec64_n_set(cv, fraction);
|
||||||
|
|
||||||
|
if ((ret = cv_parse1(body, cv, &reason)) < 0){
|
||||||
|
clicon_err(OE_YANG, errno, "cv_parse1");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (ret == 0){
|
||||||
|
clicon_err(OE_YANG, EINVAL, "cv parse error: %s\n", reason);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (xml_cv_set(x, cv) < 0)
|
||||||
|
goto done;
|
||||||
|
ok:
|
||||||
|
*cvp = cv;
|
||||||
|
cv = NULL;
|
||||||
|
retval = 0;
|
||||||
|
done:
|
||||||
|
if (reason)
|
||||||
|
free(reason);
|
||||||
|
if (cv)
|
||||||
|
cv_free(cv);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
/*! Given two XPATH contexts, eval relational operations: <>=
|
/*! Given two XPATH contexts, eval relational operations: <>=
|
||||||
* A RelationalExpr is evaluated by comparing the objects that result from
|
* A RelationalExpr is evaluated by comparing the objects that result from
|
||||||
* evaluating the two operands.
|
* evaluating the two operands.
|
||||||
|
|
@ -706,7 +777,8 @@ xp_relop(xp_ctx *xc1,
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
xp_ctx *xr = NULL;
|
xp_ctx *xr = NULL;
|
||||||
xp_ctx *xc;
|
xp_ctx *xc;
|
||||||
cxobj *x;
|
cxobj *x1;
|
||||||
|
cxobj *x2;
|
||||||
int i;
|
int i;
|
||||||
int j;
|
int j;
|
||||||
int b;
|
int b;
|
||||||
|
|
@ -715,6 +787,8 @@ xp_relop(xp_ctx *xc1,
|
||||||
int reverse = 0;
|
int reverse = 0;
|
||||||
double n1, n2;
|
double n1, n2;
|
||||||
char *xb;
|
char *xb;
|
||||||
|
cg_var *cv1, *cv2;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (xc1 == NULL || xc2 == NULL){
|
if (xc1 == NULL || xc2 == NULL){
|
||||||
clicon_err(OE_UNIX, EINVAL, "xc1 or xc2 NULL");
|
clicon_err(OE_UNIX, EINVAL, "xc1 or xc2 NULL");
|
||||||
|
|
@ -734,41 +808,82 @@ xp_relop(xp_ctx *xc1,
|
||||||
node in the first node-set and one in the second node-set is true */
|
node in the first node-set and one in the second node-set is true */
|
||||||
for (i=0; i<xc1->xc_size; i++){
|
for (i=0; i<xc1->xc_size; i++){
|
||||||
/* node in nodeset */
|
/* node in nodeset */
|
||||||
if ((x = xc1->xc_nodeset[i]) == NULL ||
|
if ((x1 = xc1->xc_nodeset[i]) == NULL ||
|
||||||
(s1 = xml_body(x)) == NULL){
|
(s1 = xml_body(x1)) == NULL){
|
||||||
xr->xc_bool = 0;
|
xr->xc_bool = 0;
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
for (j=0; j<xc2->xc_size; j++){
|
for (j=0; j<xc2->xc_size; j++){
|
||||||
if ((x = xc2->xc_nodeset[j]) == NULL ||
|
if ((x2 = xc2->xc_nodeset[j]) == NULL ||
|
||||||
(s2 = xml_body(x)) == NULL){
|
(s2 = xml_body(x2)) == NULL){
|
||||||
xr->xc_bool = 0;
|
xr->xc_bool = 0;
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
switch(op){
|
/* YANG bound, use cv evaluation, else strcmp */
|
||||||
case XO_EQ:
|
if (xml_spec(x1) && xml_spec(x2)){
|
||||||
xr->xc_bool = (strcmp(s1, s2)==0);
|
if (xml_cv_cache(x1, &cv1) < 0) /* error case */
|
||||||
break;
|
goto done;
|
||||||
case XO_NE:
|
if (xml_cv_cache(x2, &cv2) < 0) /* error case */
|
||||||
xr->xc_bool = (strcmp(s1, s2)!=0);
|
goto done;
|
||||||
break;
|
if (cv1 != NULL && cv2 != NULL)
|
||||||
case XO_GE:
|
ret = cv_cmp(cv1, cv2);
|
||||||
xr->xc_bool = (strcmp(s1, s2)>=0);
|
else if (cv1 == NULL && cv2 == NULL)
|
||||||
break;
|
ret = 0;
|
||||||
case XO_LE:
|
else if (cv1 == NULL)
|
||||||
xr->xc_bool = (strcmp(s1, s2)<=0);
|
ret = -1;
|
||||||
break;
|
else
|
||||||
case XO_LT:
|
ret = 1;
|
||||||
xr->xc_bool = (strcmp(s1, s2)<0);
|
switch(op){
|
||||||
break;
|
case XO_EQ:
|
||||||
case XO_GT:
|
xr->xc_bool = (ret == 0);
|
||||||
xr->xc_bool = (strcmp(s1, s2)>0);
|
break;
|
||||||
break;
|
case XO_NE:
|
||||||
default:
|
xr->xc_bool = (ret != 0);
|
||||||
clicon_err(OE_XML, 0, "Operator %s not supported for nodeset/nodeset comparison", clicon_int2str(xpopmap,op));
|
break;
|
||||||
goto done;
|
case XO_GE:
|
||||||
break;
|
xr->xc_bool = (ret >= 0);
|
||||||
}
|
break;
|
||||||
|
case XO_LE:
|
||||||
|
xr->xc_bool = (ret <= 0);
|
||||||
|
break;
|
||||||
|
case XO_LT:
|
||||||
|
xr->xc_bool = (ret < 0);
|
||||||
|
break;
|
||||||
|
case XO_GT:
|
||||||
|
xr->xc_bool = (ret > 0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
clicon_err(OE_XML, 0, "Operator %s not supported for nodeset/nodeset comparison", clicon_int2str(xpopmap,op));
|
||||||
|
goto done;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
switch(op){
|
||||||
|
case XO_EQ:
|
||||||
|
xr->xc_bool = (strcmp(s1, s2)==0);
|
||||||
|
break;
|
||||||
|
case XO_NE:
|
||||||
|
xr->xc_bool = (strcmp(s1, s2)!=0);
|
||||||
|
break;
|
||||||
|
case XO_GE:
|
||||||
|
xr->xc_bool = (strcmp(s1, s2)>=0);
|
||||||
|
break;
|
||||||
|
case XO_LE:
|
||||||
|
xr->xc_bool = (strcmp(s1, s2)<=0);
|
||||||
|
break;
|
||||||
|
case XO_LT:
|
||||||
|
xr->xc_bool = (strcmp(s1, s2)<0);
|
||||||
|
break;
|
||||||
|
case XO_GT:
|
||||||
|
xr->xc_bool = (strcmp(s1, s2)>0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
clicon_err(OE_XML, 0, "Operator %s not supported for nodeset/nodeset comparison", clicon_int2str(xpopmap,op));
|
||||||
|
goto done;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (xr->xc_bool) /* enough to find a single node */
|
if (xr->xc_bool) /* enough to find a single node */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -851,10 +966,10 @@ xp_relop(xp_ctx *xc1,
|
||||||
s2 = xc2->xc_string;
|
s2 = xc2->xc_string;
|
||||||
for (i=0; i<xc1->xc_size; i++){
|
for (i=0; i<xc1->xc_size; i++){
|
||||||
/* node in nodeset */
|
/* node in nodeset */
|
||||||
if ((x = xc1->xc_nodeset[i]) == NULL)
|
if ((x1 = xc1->xc_nodeset[i]) == NULL)
|
||||||
s1 = NULL;
|
s1 = NULL;
|
||||||
else
|
else
|
||||||
s1 = xml_body(x);
|
s1 = xml_body(x1);
|
||||||
switch(op){
|
switch(op){
|
||||||
case XO_EQ:
|
case XO_EQ:
|
||||||
if (s1 == NULL && s2 == NULL)
|
if (s1 == NULL && s2 == NULL)
|
||||||
|
|
@ -892,8 +1007,8 @@ xp_relop(xp_ctx *xc1,
|
||||||
case XT_NUMBER:
|
case XT_NUMBER:
|
||||||
for (i=0; i<xc1->xc_size; i++){
|
for (i=0; i<xc1->xc_size; i++){
|
||||||
/* node in nodeset */
|
/* node in nodeset */
|
||||||
if ((x = xc1->xc_nodeset[i]) == NULL ||
|
if ((x1 = xc1->xc_nodeset[i]) == NULL ||
|
||||||
(xb = xml_body(x)) == NULL ||
|
(xb = xml_body(x1)) == NULL ||
|
||||||
sscanf(xb, "%lf", &n1) != 1)
|
sscanf(xb, "%lf", &n1) != 1)
|
||||||
n1 = NAN;
|
n1 = NAN;
|
||||||
n2 = xc2->xc_number;
|
n2 = xc2->xc_number;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue