mirror of
https://gitlab.gnome.org/GNOME/libxml2.git
synced 2025-03-10 08:58:16 +03:00
Simplify XPath NaN, inf and -0 handling
Use C99 macros NAN, INFINITY, isnan, isinf. If they're not available: - Assume that (0.0 / 0.0) generates a NaN and !(x == x) tests for NaN. - Use C89's HUGE_VAL for INFINITY. Remove manual handling of NaN, infinity and negative zero in functions xmlXPathValueFlipSign and xmlXPathDivValues. Remove xmlXPathGetSign. All the tests for negative zero can be replaced with a test for negative or positive zero. Simplify xmlXPathRoundFunction. Remove Trio dependency. This should work on IEEE 754 compliant implementations even if the C99 macros aren't available, but will likely break some ancient platforms. If problems arise, my plan is to port the relevant trionan.c solution to xpath.c. Note that non-compliant implementations are impossible to fully support, anyway, since XPath requires IEEE 754.
This commit is contained in:
parent
861823902b
commit
8813f397f8
@ -15,7 +15,7 @@ matrix:
|
||||
- compiler: clang
|
||||
dist: trusty
|
||||
env: CONFIG="--without-python"
|
||||
CFLAGS="-O2 -g -fno-omit-frame-pointer -fsanitize=address,undefined -fno-sanitize-recover=all"
|
||||
CFLAGS="-O2 -g -fno-omit-frame-pointer -fsanitize=address,undefined -fno-sanitize=float-divide-by-zero -fno-sanitize-recover=all"
|
||||
UBSAN_OPTIONS=print_stacktrace=1
|
||||
script: sh autogen.sh $CONFIG && make -j2 V=1 && make check
|
||||
git:
|
||||
|
146
xpath.c
146
xpath.c
@ -477,84 +477,66 @@ int wrap_cmp( xmlNodePtr x, xmlNodePtr y );
|
||||
* *
|
||||
************************************************************************/
|
||||
|
||||
#ifndef TRIO_REPLACE_STDIO
|
||||
#define TRIO_PUBLIC static
|
||||
#ifndef NAN
|
||||
#define NAN (0.0 / 0.0)
|
||||
#endif
|
||||
#include "trionan.c"
|
||||
|
||||
/*
|
||||
* The lack of portability of this section of the libc is annoying !
|
||||
*/
|
||||
double xmlXPathNAN = 0;
|
||||
double xmlXPathPINF = 1;
|
||||
double xmlXPathNINF = -1;
|
||||
static double xmlXPathNZERO = 0; /* not exported from headers */
|
||||
static int xmlXPathInitialized = 0;
|
||||
#ifndef INFINITY
|
||||
#define INFINITY HUGE_VAL
|
||||
#endif
|
||||
|
||||
double xmlXPathNAN = NAN;
|
||||
double xmlXPathPINF = INFINITY;
|
||||
double xmlXPathNINF = -INFINITY;
|
||||
|
||||
/**
|
||||
* xmlXPathInit:
|
||||
*
|
||||
* Initialize the XPath environment
|
||||
*
|
||||
* Does nothing but must be kept as public function.
|
||||
*/
|
||||
void
|
||||
xmlXPathInit(void) {
|
||||
if (xmlXPathInitialized) return;
|
||||
|
||||
xmlXPathPINF = trio_pinf();
|
||||
xmlXPathNINF = trio_ninf();
|
||||
xmlXPathNAN = trio_nan();
|
||||
xmlXPathNZERO = trio_nzero();
|
||||
|
||||
xmlXPathInitialized = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* xmlXPathIsNaN:
|
||||
* @val: a double value
|
||||
*
|
||||
* Provides a portable isnan() function to detect whether a double
|
||||
* is a NotaNumber. Based on trio code
|
||||
* http://sourceforge.net/projects/ctrio/
|
||||
*
|
||||
* Returns 1 if the value is a NaN, 0 otherwise
|
||||
*/
|
||||
int
|
||||
xmlXPathIsNaN(double val) {
|
||||
return(trio_isnan(val));
|
||||
#ifdef isnan
|
||||
return isnan(val);
|
||||
#else
|
||||
return !(val == val);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* xmlXPathIsInf:
|
||||
* @val: a double value
|
||||
*
|
||||
* Provides a portable isinf() function to detect whether a double
|
||||
* is a +Infinite or -Infinite. Based on trio code
|
||||
* http://sourceforge.net/projects/ctrio/
|
||||
*
|
||||
* Returns 1 vi the value is +Infinite, -1 if -Infinite, 0 otherwise
|
||||
* Returns 1 if the value is +Infinite, -1 if -Infinite, 0 otherwise
|
||||
*/
|
||||
int
|
||||
xmlXPathIsInf(double val) {
|
||||
return(trio_isinf(val));
|
||||
#ifdef isinf
|
||||
return isinf(val);
|
||||
#else
|
||||
if (val >= HUGE_VAL)
|
||||
return 1;
|
||||
if (val <= -HUGE_VAL)
|
||||
return -1;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* SCHEMAS or XPATH */
|
||||
#ifdef LIBXML_XPATH_ENABLED
|
||||
/**
|
||||
* xmlXPathGetSign:
|
||||
* @val: a double value
|
||||
*
|
||||
* Provides a portable function to detect the sign of a double
|
||||
* Modified from trio code
|
||||
* http://sourceforge.net/projects/ctrio/
|
||||
*
|
||||
* Returns 1 if the value is Negative, 0 if positive
|
||||
*/
|
||||
static int
|
||||
xmlXPathGetSign(double val) {
|
||||
return(trio_signbit(val));
|
||||
}
|
||||
|
||||
#ifdef LIBXML_XPATH_ENABLED
|
||||
|
||||
/*
|
||||
* TODO: when compatibility allows remove all "fake node libxslt" strings
|
||||
@ -1423,7 +1405,8 @@ xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
|
||||
default:
|
||||
if (xmlXPathIsNaN(cur->floatval)) {
|
||||
fprintf(output, "Object is a number : NaN\n");
|
||||
} else if (cur->floatval == 0 && xmlXPathGetSign(cur->floatval) != 0) {
|
||||
} else if (cur->floatval == 0) {
|
||||
/* Omit sign for negative zero. */
|
||||
fprintf(output, "Object is a number : 0\n");
|
||||
} else {
|
||||
fprintf(output, "Object is a number : %0g\n", cur->floatval);
|
||||
@ -3119,7 +3102,8 @@ xmlXPathFormatNumber(double number, char buffer[], int buffersize)
|
||||
if (xmlXPathIsNaN(number)) {
|
||||
if (buffersize > (int)sizeof("NaN"))
|
||||
snprintf(buffer, buffersize, "NaN");
|
||||
} else if (number == 0 && xmlXPathGetSign(number) != 0) {
|
||||
} else if (number == 0) {
|
||||
/* Omit sign for negative zero. */
|
||||
snprintf(buffer, buffersize, "0");
|
||||
} else if ((number > INT_MIN) && (number < INT_MAX) &&
|
||||
(number == (int) number)) {
|
||||
@ -5728,7 +5712,8 @@ xmlXPathCastNumberToString (double val) {
|
||||
default:
|
||||
if (xmlXPathIsNaN(val)) {
|
||||
ret = xmlStrdup((const xmlChar *) "NaN");
|
||||
} else if (val == 0 && xmlXPathGetSign(val) != 0) {
|
||||
} else if (val == 0) {
|
||||
/* Omit sign for negative zero. */
|
||||
ret = xmlStrdup((const xmlChar *) "0");
|
||||
} else {
|
||||
/* could be improved */
|
||||
@ -5910,10 +5895,10 @@ xmlXPathCastNodeToNumber (xmlNodePtr node) {
|
||||
double ret;
|
||||
|
||||
if (node == NULL)
|
||||
return(xmlXPathNAN);
|
||||
return(NAN);
|
||||
strval = xmlXPathCastNodeToString(node);
|
||||
if (strval == NULL)
|
||||
return(xmlXPathNAN);
|
||||
return(NAN);
|
||||
ret = xmlXPathCastStringToNumber(strval);
|
||||
xmlFree(strval);
|
||||
|
||||
@ -5934,7 +5919,7 @@ xmlXPathCastNodeSetToNumber (xmlNodeSetPtr ns) {
|
||||
double ret;
|
||||
|
||||
if (ns == NULL)
|
||||
return(xmlXPathNAN);
|
||||
return(NAN);
|
||||
str = xmlXPathCastNodeSetToString(ns);
|
||||
ret = xmlXPathCastStringToNumber(str);
|
||||
xmlFree(str);
|
||||
@ -5954,13 +5939,13 @@ xmlXPathCastToNumber(xmlXPathObjectPtr val) {
|
||||
double ret = 0.0;
|
||||
|
||||
if (val == NULL)
|
||||
return(xmlXPathNAN);
|
||||
return(NAN);
|
||||
switch (val->type) {
|
||||
case XPATH_UNDEFINED:
|
||||
#ifdef DEGUB_EXPR
|
||||
xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
|
||||
#endif
|
||||
ret = xmlXPathNAN;
|
||||
ret = NAN;
|
||||
break;
|
||||
case XPATH_NODESET:
|
||||
case XPATH_XSLT_TREE:
|
||||
@ -5980,7 +5965,7 @@ xmlXPathCastToNumber(xmlXPathObjectPtr val) {
|
||||
case XPATH_RANGE:
|
||||
case XPATH_LOCATIONSET:
|
||||
TODO;
|
||||
ret = xmlXPathNAN;
|
||||
ret = NAN;
|
||||
break;
|
||||
}
|
||||
return(ret);
|
||||
@ -7484,20 +7469,7 @@ xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
|
||||
if ((ctxt == NULL) || (ctxt->context == NULL)) return;
|
||||
CAST_TO_NUMBER;
|
||||
CHECK_TYPE(XPATH_NUMBER);
|
||||
if (xmlXPathIsNaN(ctxt->value->floatval))
|
||||
ctxt->value->floatval=xmlXPathNAN;
|
||||
else if (xmlXPathIsInf(ctxt->value->floatval) == 1)
|
||||
ctxt->value->floatval=xmlXPathNINF;
|
||||
else if (xmlXPathIsInf(ctxt->value->floatval) == -1)
|
||||
ctxt->value->floatval=xmlXPathPINF;
|
||||
else if (ctxt->value->floatval == 0) {
|
||||
if (xmlXPathGetSign(ctxt->value->floatval) == 0)
|
||||
ctxt->value->floatval = xmlXPathNZERO;
|
||||
else
|
||||
ctxt->value->floatval = 0;
|
||||
}
|
||||
else
|
||||
ctxt->value->floatval = - ctxt->value->floatval;
|
||||
ctxt->value->floatval = -ctxt->value->floatval;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -7589,25 +7561,7 @@ xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
|
||||
xmlXPathReleaseObject(ctxt->context, arg);
|
||||
CAST_TO_NUMBER;
|
||||
CHECK_TYPE(XPATH_NUMBER);
|
||||
if (xmlXPathIsNaN(val) || xmlXPathIsNaN(ctxt->value->floatval))
|
||||
ctxt->value->floatval = xmlXPathNAN;
|
||||
else if (val == 0 && xmlXPathGetSign(val) != 0) {
|
||||
if (ctxt->value->floatval == 0)
|
||||
ctxt->value->floatval = xmlXPathNAN;
|
||||
else if (ctxt->value->floatval > 0)
|
||||
ctxt->value->floatval = xmlXPathNINF;
|
||||
else if (ctxt->value->floatval < 0)
|
||||
ctxt->value->floatval = xmlXPathPINF;
|
||||
}
|
||||
else if (val == 0) {
|
||||
if (ctxt->value->floatval == 0)
|
||||
ctxt->value->floatval = xmlXPathNAN;
|
||||
else if (ctxt->value->floatval > 0)
|
||||
ctxt->value->floatval = xmlXPathPINF;
|
||||
else if (ctxt->value->floatval < 0)
|
||||
ctxt->value->floatval = xmlXPathNINF;
|
||||
} else
|
||||
ctxt->value->floatval /= val;
|
||||
ctxt->value->floatval /= val;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -7632,7 +7586,7 @@ xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
|
||||
CHECK_TYPE(XPATH_NUMBER);
|
||||
arg1 = ctxt->value->floatval;
|
||||
if (arg2 == 0)
|
||||
ctxt->value->floatval = xmlXPathNAN;
|
||||
ctxt->value->floatval = NAN;
|
||||
else {
|
||||
ctxt->value->floatval = fmod(arg1, arg2);
|
||||
}
|
||||
@ -9751,13 +9705,9 @@ xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
|
||||
|
||||
f = ctxt->value->floatval;
|
||||
|
||||
/* Test for zero to keep negative zero unchanged. */
|
||||
if ((xmlXPathIsNaN(f)) || (f == 0.0))
|
||||
return;
|
||||
|
||||
if ((f >= -0.5) && (f < 0.0)) {
|
||||
/* Negative zero. */
|
||||
ctxt->value->floatval = xmlXPathNZERO;
|
||||
if ((f >= -0.5) && (f < 0.5)) {
|
||||
/* Handles negative zero. */
|
||||
ctxt->value->floatval *= 0.0;
|
||||
}
|
||||
else {
|
||||
double rounded = floor(f);
|
||||
@ -10104,7 +10054,7 @@ xmlXPathStringEvalNumber(const xmlChar *str) {
|
||||
if (cur == NULL) return(0);
|
||||
while (IS_BLANK_CH(*cur)) cur++;
|
||||
if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
|
||||
return(xmlXPathNAN);
|
||||
return(NAN);
|
||||
}
|
||||
if (*cur == '-') {
|
||||
isneg = 1;
|
||||
@ -10140,7 +10090,7 @@ xmlXPathStringEvalNumber(const xmlChar *str) {
|
||||
|
||||
cur++;
|
||||
if (((*cur < '0') || (*cur > '9')) && (!ok)) {
|
||||
return(xmlXPathNAN);
|
||||
return(NAN);
|
||||
}
|
||||
while (*cur == '0') {
|
||||
frac = frac + 1;
|
||||
@ -10173,7 +10123,7 @@ xmlXPathStringEvalNumber(const xmlChar *str) {
|
||||
}
|
||||
}
|
||||
while (IS_BLANK_CH(*cur)) cur++;
|
||||
if (*cur != 0) return(xmlXPathNAN);
|
||||
if (*cur != 0) return(NAN);
|
||||
if (isneg) ret = -ret;
|
||||
if (is_exponent_negative) exponent = -exponent;
|
||||
ret *= pow(10.0, (double)exponent);
|
||||
|
Loading…
x
Reference in New Issue
Block a user