summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Wellnhofer <wellnhofer@aevum.de>2017-09-21 00:11:26 +0200
committerNick Wellnhofer <wellnhofer@aevum.de>2017-11-14 15:58:40 +0100
commit8813f397f8925f85ffbe9e9fb62bfaa3c1accf11 (patch)
tree0c91b70a669d128e8b880cc361d045f3872574dd
parent861823902b780a36d2583c0b742a19b3da3ddd1e (diff)
downloadlibxml2-8813f397f8925f85ffbe9e9fb62bfaa3c1accf11.tar.gz
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.
-rw-r--r--.travis.yml2
-rw-r--r--xpath.c146
2 files changed, 49 insertions, 99 deletions
diff --git a/.travis.yml b/.travis.yml
index 67202897..9562d6e7 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -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:
diff --git a/xpath.c b/xpath.c
index 0dc5e34a..413b246a 100644
--- a/xpath.c
+++ b/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);