# HG changeset patch
# User alanb
# Date 1297019854 0
# Node ID d00080320e439c339594d380f0322c865553a046
# Parent  f7afe7a5e086a6af1f23dd6304bcbe7fb2b6226a
4421494: infinite loop while parsing double literal
Reviewed-by: darcy, alanb
Contributed-by: dmitry.nadezhin@oracle.com

diff --git a/src/share/classes/sun/misc/FloatingDecimal.java b/src/share/classes/sun/misc/FloatingDecimal.java
--- openjdk/jdk/src/share/classes/sun/misc/FloatingDecimal.java
+++ openjdk/jdk/src/share/classes/sun/misc/FloatingDecimal.java
@@ -1547,7 +1547,7 @@ public class FloatingDecimal{
                 if ( (cmpResult = bigB.cmp( bigD ) ) > 0 ){
                     overvalue = true; // our candidate is too big.
                     diff = bigB.sub( bigD );
-                    if ( (bigIntNBits == 1) && (bigIntExp > -expBias) ){
+                    if ( (bigIntNBits == 1) && (bigIntExp > -expBias+1) ){
                         // candidate is a normalized exact power of 2 and
                         // is too big. We will be subtracting.
                         // For our purposes, ulp is the ulp of the
diff --git a/test/java/lang/Double/ParseDouble.java b/test/java/lang/Double/ParseDouble.java
--- openjdk/jdk/test/java/lang/Double/ParseDouble.java
+++ openjdk/jdk/test/java/lang/Double/ParseDouble.java
@@ -23,11 +23,12 @@
 
 /*
  * @test
- * @bug 4160406 4705734 4707389 4826774 4895911
+ * @bug 4160406 4705734 4707389 4826774 4895911 4421494
  * @summary Test for Double.parseDouble method and acceptance regex
  */
 
 import java.util.regex.*;
+import java.math.BigDecimal;
 
 public class ParseDouble {
 
@@ -416,7 +417,15 @@ public class ParseDouble {
 
         "0x00100p1",
         "0x00.100p1",
-        "0x001.100p1"
+        "0x001.100p1",
+
+        // Limits
+
+        "1.7976931348623157E308",     // Double.MAX_VALUE
+        "4.9e-324",                   // Double.MIN_VALUE
+        "2.2250738585072014e-308",    // Double.MIN_NORMAL
+
+        "2.2250738585072012e-308",    // near Double.MIN_NORMAL
     };
 
     static String paddedBadStrings[];
@@ -546,6 +555,42 @@ public class ParseDouble {
 
     }
 
+    /**
+     * For each subnormal power of two, test at boundaries of
+     * region that should convert to that value.
+     */
+    private static void testSubnormalPowers() {
+        BigDecimal TWO = BigDecimal.valueOf(2);
+        // An ulp is the same for all subnormal values
+        BigDecimal ulp_BD = new BigDecimal(Double.MIN_VALUE);
+
+        System.out.println("Testing subnormal powers of two.");
+        for(int i = -1074; i <= -1022; i++) {
+            double d = Math.scalb(1.0, i);
+
+            /*
+             * The region [d - ulp/2, d + ulp/2] should round to d.
+             */
+            BigDecimal d_BD = new BigDecimal(d);
+
+            BigDecimal lowerBound = d_BD.subtract(ulp_BD.divide(TWO));
+            BigDecimal upperBound = d_BD.add(ulp_BD.divide(TWO));
+
+            double convertedLowerBound = Double.parseDouble(lowerBound.toString());
+            double convertedUpperBound = Double.parseDouble(upperBound.toString());
+
+            if (convertedLowerBound != d) {
+                System.out.printf("Exponent %d, unexpected lower bound converted to %a, not %a.%n",
+                                  i, convertedLowerBound, d);
+            }
+
+            if (convertedUpperBound != d) {
+                System.out.printf("Exponent %d, unexpected upper bound converted to %a, not %a.%n",
+                                  i, convertedUpperBound, d);
+            }
+        }
+    }
+
     public static void main(String[] args) throws Exception {
         rudimentaryTest();
 
@@ -558,5 +603,7 @@ public class ParseDouble {
         testRegex(paddedGoodStrings, false);
         testRegex(badStrings, true);
         testRegex(paddedBadStrings, true);
+
+        testSubnormalPowers();
     }
 }
