[libxml2] Rework XPath rounding functions



commit 4bebb030db2100fce5b43fbbae413d372ee70497
Author: Nick Wellnhofer <wellnhofer aevum de>
Date:   Thu Apr 21 13:41:09 2016 +0200

    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.

 result/XPath/expr/functions |   68 +++++++++++++++++++++++++++++++++++++++++
 test/XPath/expr/functions   |   17 ++++++++++
 xpath.c                     |   71 +++++++++----------------------------------
 3 files changed, 100 insertions(+), 56 deletions(-)
---
diff --git a/result/XPath/expr/functions b/result/XPath/expr/functions
index 10cc27e..e09eb4a 100644
--- a/result/XPath/expr/functions
+++ b/result/XPath/expr/functions
@@ -44,6 +44,26 @@ Expression: floor(-5.2)
 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)
 Object is a number : 1
 
@@ -68,6 +88,26 @@ Expression: ceiling(-5.2)
 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)
 Object is a number : 0
 
@@ -98,3 +138,31 @@ Object is a number : -5
 ========================
 Expression: round(-5.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
diff --git a/test/XPath/expr/functions b/test/XPath/expr/functions
index d168b18..00b9461 100644
--- a/test/XPath/expr/functions
+++ b/test/XPath/expr/functions
@@ -9,12 +9,22 @@ floor(-0)
 floor(0)
 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)
 ceiling(0)
 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(5.2)
 round(5.5)
@@ -23,3 +33,10 @@ round(-0.1)
 round(-5.2)
 round(-5.5)
 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)
diff --git a/xpath.c b/xpath.c
index dce1107..0a24be6 100644
--- a/xpath.c
+++ b/xpath.c
@@ -9675,18 +9675,6 @@ xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
     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:
  * @ctxt:  the XPath Parser context
@@ -9699,19 +9687,11 @@ xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  */
 void
 xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
-    double f;
-
     CHECK_ARITY(1);
     CAST_TO_NUMBER;
     CHECK_TYPE(XPATH_NUMBER);
 
-    XTRUNC(f, ctxt->value->floatval);
-    if (f != ctxt->value->floatval) {
-       if (ctxt->value->floatval > 0)
-           ctxt->value->floatval = f;
-       else
-           ctxt->value->floatval = f - 1;
-    }
+    ctxt->value->floatval = floor(ctxt->value->floatval);
 }
 
 /**
@@ -9726,28 +9706,11 @@ xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
  */
 void
 xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
-    double f;
-
     CHECK_ARITY(1);
     CAST_TO_NUMBER;
     CHECK_TYPE(XPATH_NUMBER);
 
-#if 0
     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)
  * The round function returns the number that is closest to the
  * 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
 xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
@@ -9769,25 +9732,21 @@ xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
     CAST_TO_NUMBER;
     CHECK_TYPE(XPATH_NUMBER);
 
-    if ((xmlXPathIsNaN(ctxt->value->floatval)) ||
-       (xmlXPathIsInf(ctxt->value->floatval) == 1) ||
-       (xmlXPathIsInf(ctxt->value->floatval) == -1) ||
-       (ctxt->value->floatval == 0.0))
+    f = ctxt->value->floatval;
+
+    /* Test for zero to keep negative zero unchanged. */
+    if ((xmlXPathIsNaN(f)) || (f == 0.0))
        return;
 
-    XTRUNC(f, ctxt->value->floatval);
-    if (ctxt->value->floatval < 0) {
-       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;
-    } else {
-       if (ctxt->value->floatval < f + 0.5)
-           ctxt->value->floatval = f;
-       else
-           ctxt->value->floatval = f + 1;
+    if ((f >= -0.5) && (f < 0.0)) {
+        /* Negative zero. */
+        ctxt->value->floatval = xmlXPathNZERO;
+    }
+    else {
+        double rounded = floor(f);
+        if (f - rounded >= 0.5)
+            rounded += 1.0;
+        ctxt->value->floatval = rounded;
     }
 }
 


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