]> granicus.if.org Git - icu/commitdiff
ICU-13118 Fixing Out-Of-Memory error in scientific number formatter.
authorShane Carr <shane@unicode.org>
Mon, 10 Apr 2017 22:36:04 +0000 (22:36 +0000)
committerShane Carr <shane@unicode.org>
Mon, 10 Apr 2017 22:36:04 +0000 (22:36 +0000)
X-SVN-Rev: 40026

icu4j/main/classes/core/src/com/ibm/icu/impl/number/formatters/ScientificFormat.java
icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/NumberFormatTest.java

index 767eeaf718a28909378dd7cb892e95089da7770d..feae79634f8b06341e938a45fac9b62858a90ab1 100644 (file)
@@ -142,15 +142,18 @@ public class ScientificFormat extends Format.BeforeFormat implements Rounder.Mul
   private ScientificFormat(DecimalFormatSymbols symbols, IProperties properties, Rounder rounder) {
     exponentShowPlusSign = properties.getExponentSignAlwaysShown();
     exponentDigits = Math.max(1, properties.getMinimumExponentDigits());
+
+    // Calculate minInt/maxInt for the purposes of engineering notation:
+    //   0 <= minInt <= maxInt < 8
+    // The values are validated separately for rounding. This scheme needs to prevent OOM issues
+    // (see #13118). Note that the bound 8 on integer digits is historic.
     int _maxInt = properties.getMaximumIntegerDigits();
     int _minInt = properties.getMinimumIntegerDigits();
-    // Special behavior:
-    if (_maxInt > 8) {
-      _maxInt = _minInt;
-    }
-    maxInt = _maxInt < 0 ? Integer.MAX_VALUE : _maxInt;
-    minInt = _minInt < 0 ? 0 : _minInt < maxInt ? _minInt : maxInt;
-    interval = Math.max(1, maxInt);
+    minInt = _minInt < 0 ? 0 : _minInt >= 8 ? 1 : _minInt;
+    maxInt = _maxInt < _minInt ? _minInt : _maxInt >= 8 ? _minInt : _maxInt;
+    assert 0 <= minInt && minInt <= maxInt && maxInt < 8;
+
+    interval = maxInt < 1 ? 1 : maxInt;
     this.rounder = rounder;
     digitStrings = symbols.getDigitStrings(); // makes a copy
 
index ee13913e2ed2cc56a003b2f23bfd429fce30d2a8..9afc18e1976a9e86d2487df600da3a9ef1370294 100644 (file)
@@ -4992,6 +4992,17 @@ public class NumberFormatTest extends TestFmwk {
         expect2(numfmt, num, "‎٪ ‎−۱٬۲۳۴");
     }
 
+    @Test
+    public void Test13118() {
+        DecimalFormat df = new DecimalFormat("@@@");
+        df.setScientificNotation(true);
+        for (double d=12345.67; d>1e-6; d/=10) {
+            String result = df.format(d);
+            assertEquals("Should produce a string of expected length on " + d,
+                    d > 1 ? 6 : 7, result.length());
+        }
+    }
+
     @Test
     public void testPercentZero() {
         DecimalFormat df = (DecimalFormat) NumberFormat.getPercentInstance();