Fix Double.parseDouble and Float.parseFloat for some cases of illegal input

This commit is contained in:
Alexey Andreev 2019-08-12 16:38:52 +03:00
parent c5334e344d
commit 1d19562c49
5 changed files with 118 additions and 64 deletions

View File

@ -77,15 +77,32 @@ public class TDouble extends TNumber implements TComparable<TDouble> {
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<TDouble> {
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<TDouble> {
++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<TDouble> {
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<TDouble> {
}
int numExp = 0;
hasOneDigit = false;
while (index < string.length()) {
while (index < end) {
c = string.charAt(index);
if (c < '0' || c > '9') {
break;

View File

@ -121,15 +121,32 @@ public class TFloat extends TNumber implements TComparable<TFloat> {
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<TFloat> {
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<TFloat> {
}
}
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<TFloat> {
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<TFloat> {
}
int numExp = 0;
hasOneDigit = false;
while (index < string.length()) {
while (index < end) {
c = string.charAt(index);
if (c < '0' || c > '9') {
break;

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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