From 02e2b1ba19b78407100e6d2cf7c06682c9981f8b Mon Sep 17 00:00:00 2001 From: khromenokroman Date: Thu, 8 Oct 2026 18:13:35 +0200 Subject: [PATCH 1/3] fix: XPath mod crashed with SIGFPE on zero divisor xp_numop() computed mod as ((int)n1)%((int)n2). If the divisor truncates to 0, eg "1 mod 0" or "1 mod 0.5", the process is killed by SIGFPE. Such an expression may come from YANG must/when statements evaluated on user data, or from an XPath filter in a NETCONF get request, so it can crash the backend. XPath 1.0 section 3.5 defines mod on numbers (floating point) as the remainder from a truncating division, ie fmod(). Use fmod(), which also returns correct results for non-integer operands (5.5 mod 2 = 1.5, previously 1) and NaN for a zero divisor, as div does. --- lib/src/clixon_xpath_eval.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/src/clixon_xpath_eval.c b/lib/src/clixon_xpath_eval.c index d181d84cf..c8677412c 100644 --- a/lib/src/clixon_xpath_eval.c +++ b/lib/src/clixon_xpath_eval.c @@ -763,7 +763,9 @@ xp_numop(xp_ctx *xc1, xr->xc_number = n1/n2; break; case XO_MOD: - xr->xc_number = ((int)n1)%((int)n2); + /* XPath 1.0 3.5: remainder from a truncating division, as fmod(). + * Integer % crashes with SIGFPE if n2 truncates to 0 */ + xr->xc_number = fmod(n1, n2); break; case XO_ADD: xr->xc_number = n1+n2; From e6afa3e528a47d8443f31bd6862d4e593fd6b0f7 Mon Sep 17 00:00:00 2001 From: khromenokroman Date: Thu, 8 Oct 2026 18:13:35 +0200 Subject: [PATCH 2/3] fix: xml_diff() returned NULL instead of x1 when x0 is NULL If the first tree is NULL, all of the second tree is new, but x0 (NULL) was appended to the second vector instead of x1 (copy-paste error from the x1 == NULL case above). --- lib/src/clixon_xml_diff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/clixon_xml_diff.c b/lib/src/clixon_xml_diff.c index fddc7c308..e94928204 100644 --- a/lib/src/clixon_xml_diff.c +++ b/lib/src/clixon_xml_diff.c @@ -539,7 +539,7 @@ xml_diff(cxobj *x0, goto ok; } if (x0 == NULL){ - if (cxvec_append(x0, second, secondlen) < 0) + if (cxvec_append(x1, second, secondlen) < 0) goto done; goto ok; } From 663d1b0e7ecf6df4e8f66658513c0f610714a824 Mon Sep 17 00:00:00 2001 From: khromenokroman Date: Thu, 8 Oct 2026 18:13:35 +0200 Subject: [PATCH 3/3] test: XPath mod including zero and non-integer divisor --- test/test_xpath.sh | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/test/test_xpath.sh b/test/test_xpath.sh index 1fa2632ed..039735424 100755 --- a/test/test_xpath.sh +++ b/test/test_xpath.sh @@ -412,6 +412,25 @@ expectpart "$($clixon_util_xpath -D $DBG -f $xml2 -p "string-length(\"12345\")") new "xpath string-length path" expectpart "$($clixon_util_xpath -D $DBG -f $xml2 -p "string-length(aaa/name)")" 0 "number:3" +# mod: XPath 1.0 3.5, remainder from a truncating division +new "xpath 5 mod 2" +expectpart "$($clixon_util_xpath -D $DBG -f $xml2 -p "5 mod 2")" 0 "number:1.0" + +new "xpath 5 mod -2" +expectpart "$($clixon_util_xpath -D $DBG -f $xml2 -p "5 mod -2")" 0 "number:1.0" + +new "xpath -5 mod 2" +expectpart "$($clixon_util_xpath -D $DBG -f $xml2 -p "-5 mod 2")" 0 "number:-1.0" + +new "xpath 5.5 mod 2" +expectpart "$($clixon_util_xpath -D $DBG -f $xml2 -p "5.5 mod 2")" 0 "number:1.5" + +new "xpath 1 mod 0 is NaN, not crash" +expectpart "$($clixon_util_xpath -D $DBG -f $xml2 -p "1 mod 0")" 0 "number:" "nan" + +new "xpath 1 mod 0.5, divisor truncated to int was 0" +expectpart "$($clixon_util_xpath -D $DBG -f $xml2 -p "1 mod 0.5")" 0 "number:0.0" + # translate new "xpath translate" # modified expectpart "$($clixon_util_xpath -D $DBG -f $xml2 -p "translate(\"bar\", \"abc\",\"DEF\")")" 0 "string:EDr$"