mirror of
https://gitlab.gnome.org/GNOME/libxml2.git
synced 2025-10-26 00:37:43 +03:00
Rework XPath rounding functions
Use the C library's floor and ceil functions. The old code was overly complicated for no apparent reason and could result in undefined behavior when handling NaNs (found with afl-fuzz and UBSan). Fix wrong comment in xmlXPathRoundFunction. The implementation was already following the spec and rounding half up.
This commit is contained in:
@@ -43,6 +43,26 @@ Object is a number : 5
|
|||||||
Expression: floor(-5.2)
|
Expression: floor(-5.2)
|
||||||
Object is a number : -6
|
Object is a number : -6
|
||||||
|
|
||||||
|
========================
|
||||||
|
Expression: floor(100000000000000000000)
|
||||||
|
Object is a number : 1e+20
|
||||||
|
|
||||||
|
========================
|
||||||
|
Expression: floor(-100000000000000000000)
|
||||||
|
Object is a number : -1e+20
|
||||||
|
|
||||||
|
========================
|
||||||
|
Expression: floor(0 div 0)
|
||||||
|
Object is a number : NaN
|
||||||
|
|
||||||
|
========================
|
||||||
|
Expression: floor(1 div 0)
|
||||||
|
Object is a number : Infinity
|
||||||
|
|
||||||
|
========================
|
||||||
|
Expression: floor(-1 div 0)
|
||||||
|
Object is a number : -Infinity
|
||||||
|
|
||||||
========================
|
========================
|
||||||
Expression: ceiling(0.1)
|
Expression: ceiling(0.1)
|
||||||
Object is a number : 1
|
Object is a number : 1
|
||||||
@@ -67,6 +87,26 @@ Object is a number : 6
|
|||||||
Expression: ceiling(-5.2)
|
Expression: ceiling(-5.2)
|
||||||
Object is a number : -5
|
Object is a number : -5
|
||||||
|
|
||||||
|
========================
|
||||||
|
Expression: ceiling(100000000000000000000)
|
||||||
|
Object is a number : 1e+20
|
||||||
|
|
||||||
|
========================
|
||||||
|
Expression: ceiling(-100000000000000000000)
|
||||||
|
Object is a number : -1e+20
|
||||||
|
|
||||||
|
========================
|
||||||
|
Expression: ceiling(0 div 0)
|
||||||
|
Object is a number : NaN
|
||||||
|
|
||||||
|
========================
|
||||||
|
Expression: ceiling(1 div 0)
|
||||||
|
Object is a number : Infinity
|
||||||
|
|
||||||
|
========================
|
||||||
|
Expression: ceiling(-1 div 0)
|
||||||
|
Object is a number : -Infinity
|
||||||
|
|
||||||
========================
|
========================
|
||||||
Expression: round(0.1)
|
Expression: round(0.1)
|
||||||
Object is a number : 0
|
Object is a number : 0
|
||||||
@@ -98,3 +138,31 @@ Object is a number : -5
|
|||||||
========================
|
========================
|
||||||
Expression: round(-5.6)
|
Expression: round(-5.6)
|
||||||
Object is a number : -6
|
Object is a number : -6
|
||||||
|
|
||||||
|
========================
|
||||||
|
Expression: round(0.5)
|
||||||
|
Object is a number : 1
|
||||||
|
|
||||||
|
========================
|
||||||
|
Expression: round(-0.5)
|
||||||
|
Object is a number : 0
|
||||||
|
|
||||||
|
========================
|
||||||
|
Expression: round(100000000000000000000)
|
||||||
|
Object is a number : 1e+20
|
||||||
|
|
||||||
|
========================
|
||||||
|
Expression: round(-100000000000000000000)
|
||||||
|
Object is a number : -1e+20
|
||||||
|
|
||||||
|
========================
|
||||||
|
Expression: round(0 div 0)
|
||||||
|
Object is a number : NaN
|
||||||
|
|
||||||
|
========================
|
||||||
|
Expression: round(1 div 0)
|
||||||
|
Object is a number : Infinity
|
||||||
|
|
||||||
|
========================
|
||||||
|
Expression: round(-1 div 0)
|
||||||
|
Object is a number : -Infinity
|
||||||
|
|||||||
@@ -9,12 +9,22 @@ floor(-0)
|
|||||||
floor(0)
|
floor(0)
|
||||||
floor(5.2)
|
floor(5.2)
|
||||||
floor(-5.2)
|
floor(-5.2)
|
||||||
|
floor(100000000000000000000)
|
||||||
|
floor(-100000000000000000000)
|
||||||
|
floor(0 div 0)
|
||||||
|
floor(1 div 0)
|
||||||
|
floor(-1 div 0)
|
||||||
ceiling(0.1)
|
ceiling(0.1)
|
||||||
ceiling(-0.1)
|
ceiling(-0.1)
|
||||||
ceiling(-0)
|
ceiling(-0)
|
||||||
ceiling(0)
|
ceiling(0)
|
||||||
ceiling(5.2)
|
ceiling(5.2)
|
||||||
ceiling(-5.2)
|
ceiling(-5.2)
|
||||||
|
ceiling(100000000000000000000)
|
||||||
|
ceiling(-100000000000000000000)
|
||||||
|
ceiling(0 div 0)
|
||||||
|
ceiling(1 div 0)
|
||||||
|
ceiling(-1 div 0)
|
||||||
round(0.1)
|
round(0.1)
|
||||||
round(5.2)
|
round(5.2)
|
||||||
round(5.5)
|
round(5.5)
|
||||||
@@ -23,3 +33,10 @@ round(-0.1)
|
|||||||
round(-5.2)
|
round(-5.2)
|
||||||
round(-5.5)
|
round(-5.5)
|
||||||
round(-5.6)
|
round(-5.6)
|
||||||
|
round(0.5)
|
||||||
|
round(-0.5)
|
||||||
|
round(100000000000000000000)
|
||||||
|
round(-100000000000000000000)
|
||||||
|
round(0 div 0)
|
||||||
|
round(1 div 0)
|
||||||
|
round(-1 div 0)
|
||||||
|
|||||||
69
xpath.c
69
xpath.c
@@ -9675,18 +9675,6 @@ xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
|
|||||||
xmlXPathReleaseObject(ctxt->context, cur);
|
xmlXPathReleaseObject(ctxt->context, cur);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* To assure working code on multiple platforms, we want to only depend
|
|
||||||
* upon the characteristic truncation of converting a floating point value
|
|
||||||
* to an integer. Unfortunately, because of the different storage sizes
|
|
||||||
* of our internal floating point value (double) and integer (int), we
|
|
||||||
* can't directly convert (see bug 301162). This macro is a messy
|
|
||||||
* 'workaround'
|
|
||||||
*/
|
|
||||||
#define XTRUNC(f, v) \
|
|
||||||
f = fmod((v), INT_MAX); \
|
|
||||||
f = (v) - (f) + (double)((int)(f));
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* xmlXPathFloorFunction:
|
* xmlXPathFloorFunction:
|
||||||
* @ctxt: the XPath Parser context
|
* @ctxt: the XPath Parser context
|
||||||
@@ -9699,19 +9687,11 @@ xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
|
|||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
|
xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
|
||||||
double f;
|
|
||||||
|
|
||||||
CHECK_ARITY(1);
|
CHECK_ARITY(1);
|
||||||
CAST_TO_NUMBER;
|
CAST_TO_NUMBER;
|
||||||
CHECK_TYPE(XPATH_NUMBER);
|
CHECK_TYPE(XPATH_NUMBER);
|
||||||
|
|
||||||
XTRUNC(f, ctxt->value->floatval);
|
ctxt->value->floatval = floor(ctxt->value->floatval);
|
||||||
if (f != ctxt->value->floatval) {
|
|
||||||
if (ctxt->value->floatval > 0)
|
|
||||||
ctxt->value->floatval = f;
|
|
||||||
else
|
|
||||||
ctxt->value->floatval = f - 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -9726,28 +9706,11 @@ xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
|
|||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
|
xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
|
||||||
double f;
|
|
||||||
|
|
||||||
CHECK_ARITY(1);
|
CHECK_ARITY(1);
|
||||||
CAST_TO_NUMBER;
|
CAST_TO_NUMBER;
|
||||||
CHECK_TYPE(XPATH_NUMBER);
|
CHECK_TYPE(XPATH_NUMBER);
|
||||||
|
|
||||||
#if 0
|
|
||||||
ctxt->value->floatval = ceil(ctxt->value->floatval);
|
ctxt->value->floatval = ceil(ctxt->value->floatval);
|
||||||
#else
|
|
||||||
XTRUNC(f, ctxt->value->floatval);
|
|
||||||
if (f != ctxt->value->floatval) {
|
|
||||||
if (ctxt->value->floatval > 0)
|
|
||||||
ctxt->value->floatval = f + 1;
|
|
||||||
else {
|
|
||||||
if (ctxt->value->floatval < 0 && f == 0)
|
|
||||||
ctxt->value->floatval = xmlXPathNZERO;
|
|
||||||
else
|
|
||||||
ctxt->value->floatval = f;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -9759,7 +9722,7 @@ xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
|
|||||||
* number round(number)
|
* number round(number)
|
||||||
* The round function returns the number that is closest to the
|
* The round function returns the number that is closest to the
|
||||||
* argument and that is an integer. If there are two such numbers,
|
* argument and that is an integer. If there are two such numbers,
|
||||||
* then the one that is even is returned.
|
* then the one that is closest to positive infinity is returned.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
|
xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
|
||||||
@@ -9769,25 +9732,21 @@ xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
|
|||||||
CAST_TO_NUMBER;
|
CAST_TO_NUMBER;
|
||||||
CHECK_TYPE(XPATH_NUMBER);
|
CHECK_TYPE(XPATH_NUMBER);
|
||||||
|
|
||||||
if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
|
f = ctxt->value->floatval;
|
||||||
(xmlXPathIsInf(ctxt->value->floatval) == 1) ||
|
|
||||||
(xmlXPathIsInf(ctxt->value->floatval) == -1) ||
|
/* Test for zero to keep negative zero unchanged. */
|
||||||
(ctxt->value->floatval == 0.0))
|
if ((xmlXPathIsNaN(f)) || (f == 0.0))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
XTRUNC(f, ctxt->value->floatval);
|
if ((f >= -0.5) && (f < 0.0)) {
|
||||||
if (ctxt->value->floatval < 0) {
|
/* Negative zero. */
|
||||||
if (ctxt->value->floatval < f - 0.5)
|
|
||||||
ctxt->value->floatval = f - 1;
|
|
||||||
else
|
|
||||||
ctxt->value->floatval = f;
|
|
||||||
if (ctxt->value->floatval == 0)
|
|
||||||
ctxt->value->floatval = xmlXPathNZERO;
|
ctxt->value->floatval = xmlXPathNZERO;
|
||||||
} else {
|
}
|
||||||
if (ctxt->value->floatval < f + 0.5)
|
else {
|
||||||
ctxt->value->floatval = f;
|
double rounded = floor(f);
|
||||||
else
|
if (f - rounded >= 0.5)
|
||||||
ctxt->value->floatval = f + 1;
|
rounded += 1.0;
|
||||||
|
ctxt->value->floatval = rounded;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user