From 1d19562c49dca6474bcc335467bcad7aa00c951e Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Mon, 12 Aug 2019 16:38:52 +0300 Subject: [PATCH] Fix Double.parseDouble and Float.parseFloat for some cases of illegal input --- .../org/teavm/classlib/java/lang/TDouble.java | 40 ++++++++++----- .../org/teavm/classlib/java/lang/TFloat.java | 40 ++++++++++----- .../teavm/classlib/java/lang/DoubleTest.java | 49 +++++++++++-------- .../teavm/classlib/java/lang/FloatTest.java | 49 +++++++++++-------- .../teavm/classlib/java/lang/SystemTest.java | 4 +- 5 files changed, 118 insertions(+), 64 deletions(-) diff --git a/classlib/src/main/java/org/teavm/classlib/java/lang/TDouble.java b/classlib/src/main/java/org/teavm/classlib/java/lang/TDouble.java index e8aefe584..bc9464aea 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/lang/TDouble.java +++ b/classlib/src/main/java/org/teavm/classlib/java/lang/TDouble.java @@ -77,15 +77,32 @@ public class TDouble extends TNumber implements TComparable { public static double parseDouble(TString string) throws TNumberFormatException { // TODO: parse infinite and different radix - string = string.trim(); + + if (string.isEmpty()) { + throw new TNumberFormatException(); + } + int start = 0; + int end = string.length(); + while (string.charAt(start) <= ' ') { + if (++start == end) { + throw new TNumberFormatException(); + } + } + while (string.charAt(end - 1) <= ' ') { + --end; + } + boolean negative = false; - int index = 0; + int index = start; if (string.charAt(index) == '-') { ++index; negative = true; } else if (string.charAt(index) == '+') { ++index; } + if (index == end) { + throw new TNumberFormatException(); + } char c = string.charAt(index); long mantissa = 0; @@ -96,12 +113,10 @@ public class TDouble extends TNumber implements TComparable { if (c < '0' || c > '9') { throw new TNumberFormatException(); } - while (string.charAt(index) == '0') { - if (++index == string.length()) { - return 0; - } + while (index < end && string.charAt(index) == '0') { + ++index; } - while (index < string.length()) { + while (index < end) { c = string.charAt(index); if (c < '0' || c > '9') { break; @@ -114,9 +129,9 @@ public class TDouble extends TNumber implements TComparable { ++index; } } - if (index < string.length() && string.charAt(index) == '.') { + if (index < end && string.charAt(index) == '.') { ++index; - while (index < string.length()) { + while (index < end) { c = string.charAt(index); if (c < '0' || c > '9') { break; @@ -132,13 +147,16 @@ public class TDouble extends TNumber implements TComparable { throw new TNumberFormatException(); } } - if (index < string.length()) { + if (index < end) { c = string.charAt(index); if (c != 'e' && c != 'E') { throw new TNumberFormatException(); } ++index; boolean negativeExp = false; + if (index == end) { + throw new TNumberFormatException(); + } if (string.charAt(index) == '-') { ++index; negativeExp = true; @@ -147,7 +165,7 @@ public class TDouble extends TNumber implements TComparable { } int numExp = 0; hasOneDigit = false; - while (index < string.length()) { + while (index < end) { c = string.charAt(index); if (c < '0' || c > '9') { break; diff --git a/classlib/src/main/java/org/teavm/classlib/java/lang/TFloat.java b/classlib/src/main/java/org/teavm/classlib/java/lang/TFloat.java index 0fca67859..8961b9f83 100644 --- a/classlib/src/main/java/org/teavm/classlib/java/lang/TFloat.java +++ b/classlib/src/main/java/org/teavm/classlib/java/lang/TFloat.java @@ -121,15 +121,32 @@ public class TFloat extends TNumber implements TComparable { public static float parseFloat(TString string) throws TNumberFormatException { // TODO: parse infinite and different radix - string = string.trim(); + + if (string.isEmpty()) { + throw new TNumberFormatException(); + } + int start = 0; + int end = string.length(); + while (string.charAt(start) <= ' ') { + if (++start == end) { + throw new TNumberFormatException(); + } + } + while (string.charAt(end - 1) <= ' ') { + --end; + } + boolean negative = false; - int index = 0; + int index = start; if (string.charAt(index) == '-') { ++index; negative = true; } else if (string.charAt(index) == '+') { ++index; } + if (index == end) { + throw new TNumberFormatException(); + } char c = string.charAt(index); int mantissa = 0; @@ -142,12 +159,10 @@ public class TFloat extends TNumber implements TComparable { throw new TNumberFormatException(); } - while (string.charAt(index) == '0') { - if (++index == string.length()) { - return 0; - } + while (index < end && string.charAt(index) == '0') { + ++index; } - while (index < string.length()) { + while (index < end) { c = string.charAt(index); if (c < '0' || c > '9') { break; @@ -161,9 +176,9 @@ public class TFloat extends TNumber implements TComparable { } } - if (index < string.length() && string.charAt(index) == '.') { + if (index < end && string.charAt(index) == '.') { ++index; - while (index < string.length()) { + while (index < end) { c = string.charAt(index); if (c < '0' || c > '9') { break; @@ -179,13 +194,16 @@ public class TFloat extends TNumber implements TComparable { throw new TNumberFormatException(); } } - if (index < string.length()) { + if (index < end) { c = string.charAt(index); if (c != 'e' && c != 'E') { throw new TNumberFormatException(); } ++index; boolean negativeExp = false; + if (index == end) { + throw new TNumberFormatException(); + } if (string.charAt(index) == '-') { ++index; negativeExp = true; @@ -194,7 +212,7 @@ public class TFloat extends TNumber implements TComparable { } int numExp = 0; hasOneDigit = false; - while (index < string.length()) { + while (index < end) { c = string.charAt(index); if (c < '0' || c > '9') { break; diff --git a/tests/src/test/java/org/teavm/classlib/java/lang/DoubleTest.java b/tests/src/test/java/org/teavm/classlib/java/lang/DoubleTest.java index 24b858258..348768869 100644 --- a/tests/src/test/java/org/teavm/classlib/java/lang/DoubleTest.java +++ b/tests/src/test/java/org/teavm/classlib/java/lang/DoubleTest.java @@ -17,6 +17,7 @@ package org.teavm.classlib.java.lang; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import org.junit.Test; import org.junit.runner.RunWith; import org.teavm.junit.TeaVMTestRunner; @@ -37,43 +38,51 @@ public class DoubleTest { assertEquals(23, Double.parseDouble("23."), 1E-12); assertEquals(0.1, Double.parseDouble("0.1"), 0.001); assertEquals(0.1, Double.parseDouble(".1"), 0.001); - } - - @Test - public void negativeParsed() { + assertEquals(0.1, Double.parseDouble(" .1"), 0.001); + assertEquals(0.1, Double.parseDouble(".1 "), 0.001); assertEquals(-23, Double.parseDouble("-23"), 1E-12); - } - - @Test - public void zeroParsed() { assertEquals(0, Double.parseDouble("0.0"), 1E-12); + assertEquals(0, Double.parseDouble("0"), 1E-12); + assertEquals(0, Double.parseDouble("00"), 1E-12); + assertEquals(0, Double.parseDouble("0."), 1E-12); + assertEquals(0, Double.parseDouble(".0"), 1E-12); assertEquals(0, Double.parseDouble("23E-8000"), 1E-12); assertEquals(0, Double.parseDouble("00000"), 1E-12); assertEquals(0, Double.parseDouble("00000.0000"), 1E-12); } + @Test + public void parsedWithError() { + checkIllegalFormat(""); + checkIllegalFormat(" "); + checkIllegalFormat("a"); + checkIllegalFormat(" a "); + checkIllegalFormat("-"); + checkIllegalFormat("-."); + checkIllegalFormat("."); + checkIllegalFormat("1e-"); + checkIllegalFormat("1e"); + } + + private void checkIllegalFormat(String string) { + try { + Double.parseDouble(string); + fail("Exception expected parsing string: " + string); + } catch (NumberFormatException e) { + // It's expected + } + } + @Test public void longBitsExtracted() { assertEquals(0x41E23456789ABCDEL, Double.doubleToLongBits(0x1.23456789ABCDEP+31)); - } - - @Test - public void longBitsExtracted2() { assertEquals(0x3FE1C28F5C28F5C3L >>> 3, Double.doubleToLongBits(0.555) >>> 3); - } - - @Test - public void subNormalLongBitsExtracted() { assertEquals(0x00000056789ABCDEL, Double.doubleToLongBits(0x0.00056789ABCDEP-1022)); } @Test public void longBitsPacked() { assertEquals(0x1.23456789ABCDEP+31, Double.longBitsToDouble(0x41E23456789ABCDEL), 0x1.0P-19); - } - - @Test - public void subNormalLongBitsPacked() { assertEquals(0x0.00056789ABCDEP-1022, Double.longBitsToDouble(0x00000056789ABCDEL), 0x1.0P-19); } diff --git a/tests/src/test/java/org/teavm/classlib/java/lang/FloatTest.java b/tests/src/test/java/org/teavm/classlib/java/lang/FloatTest.java index 37377f12e..1824984bb 100644 --- a/tests/src/test/java/org/teavm/classlib/java/lang/FloatTest.java +++ b/tests/src/test/java/org/teavm/classlib/java/lang/FloatTest.java @@ -17,6 +17,7 @@ package org.teavm.classlib.java.lang; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import org.junit.Test; import org.junit.runner.RunWith; import org.teavm.junit.TeaVMTestRunner; @@ -38,43 +39,51 @@ public class FloatTest { assertEquals(23, Float.parseFloat("23."), 1E-12F); assertEquals(0.1F, Float.parseFloat("0.1"), 0.001F); assertEquals(0.1F, Float.parseFloat(".1"), 0.001F); - } - - @Test - public void negativeParsed() { + assertEquals(0.1F, Float.parseFloat(" .1"), 0.001F); + assertEquals(0.1F, Float.parseFloat(".1 "), 0.001F); assertEquals(-23, Float.parseFloat("-23"), 1E-12F); - } - - @Test - public void zeroParsed() { assertEquals(0, Float.parseFloat("0.0"), 1E-12F); + assertEquals(0, Float.parseFloat("0"), 1E-12F); + assertEquals(0, Float.parseFloat("00"), 1E-12F); + assertEquals(0, Float.parseFloat(".0"), 1E-12F); + assertEquals(0, Float.parseFloat("0."), 1E-12F); assertEquals(0, Float.parseFloat("23E-8000"), 1E-12F); assertEquals(0, Float.parseFloat("00000"), 1E-12F); assertEquals(0, Float.parseFloat("00000.0000"), 1E-12F); } + @Test + public void parsedWithError() { + checkIllegalFormat(""); + checkIllegalFormat(" "); + checkIllegalFormat("a"); + checkIllegalFormat(" a "); + checkIllegalFormat("-"); + checkIllegalFormat("-."); + checkIllegalFormat("."); + checkIllegalFormat("1e-"); + checkIllegalFormat("1e"); + } + + private void checkIllegalFormat(String string) { + try { + Float.parseFloat(string); + fail("Exception expected parsing string: " + string); + } catch (NumberFormatException e) { + // It's expected + } + } + @Test public void floatBitsExtracted() { assertEquals(0x4591A2B4, Float.floatToIntBits(0x1.234567p+12f)); - } - - @Test - public void floatBitsExtracted2() { assertEquals(0x800000, Float.floatToIntBits((float) Math.pow(2, -126))); - } - - @Test - public void subNormalFloatBitsExtracted() { assertEquals(0x000092, Float.floatToIntBits(0x0.000123p-126f)); } @Test public void floatBitsPacked() { assertEquals(0x1.234567p+12f, Float.intBitsToFloat(0x4591A2B4), 1e7); - } - - @Test - public void subNormalFloatBitsPacked() { assertEquals(0x0.000123p-126f, Float.intBitsToFloat(0x000092), 0x000008p-126); } diff --git a/tests/src/test/java/org/teavm/classlib/java/lang/SystemTest.java b/tests/src/test/java/org/teavm/classlib/java/lang/SystemTest.java index 339fe8aa4..40a735d00 100644 --- a/tests/src/test/java/org/teavm/classlib/java/lang/SystemTest.java +++ b/tests/src/test/java/org/teavm/classlib/java/lang/SystemTest.java @@ -125,8 +125,8 @@ public class SystemTest { System.err.println("err overridden"); System.err.flush(); - assertEquals("err overridden\n", new String(err.toByteArray())); - assertEquals("out overridden\n", new String(out.toByteArray())); + assertEquals("err overridden" + System.lineSeparator(), new String(err.toByteArray())); + assertEquals("out overridden" + System.lineSeparator(), new String(out.toByteArray())); } @Test