[libxml2] Simplify XPath NaN, inf and -0 handling



commit 8813f397f8925f85ffbe9e9fb62bfaa3c1accf11
Author: Nick Wellnhofer <wellnhofer aevum de>
Date:   Thu Sep 21 00:11:26 2017 +0200

    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.

 .travis.yml |    2 +-
 xpath.c     |  146 +++++++++++++++++++---------------------------------------
 2 files changed, 49 insertions(+), 99 deletions(-)
---
diff --git a/.travis.yml b/.travis.yml
index 6720289..9562d6e 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 0dc5e34..413b246 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);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]