Skip to content

Commit a6785e4

Browse files
committedNov 8, 2023
8318915: Enhance checks in BigDecimal.toPlainString()
Reviewed-by: rriggs, bpb
1 parent 7d25f1c commit a6785e4

File tree

2 files changed

+57
-20
lines changed

2 files changed

+57
-20
lines changed
 

‎src/java.base/share/classes/java/math/BigDecimal.java

+18-18
Original file line numberDiff line numberDiff line change
@@ -3503,21 +3503,19 @@ public String toPlainString() {
35033503
return "0";
35043504
}
35053505
int trailingZeros = checkScaleNonZero((-(long)scale));
3506-
StringBuilder buf;
3507-
if(intCompact!=INFLATED) {
3508-
buf = new StringBuilder(20+trailingZeros);
3509-
buf.append(intCompact);
3510-
} else {
3511-
String str = intVal.toString();
3512-
buf = new StringBuilder(str.length()+trailingZeros);
3513-
buf.append(str);
3514-
}
3515-
for (int i = 0; i < trailingZeros; i++) {
3516-
buf.append('0');
3506+
String str = intCompact != INFLATED
3507+
? Long.toString(intCompact)
3508+
: intVal.toString();
3509+
int len = str.length() + trailingZeros;
3510+
if (len < 0) {
3511+
throw new OutOfMemoryError("too large to fit in a String");
35173512
}
3513+
StringBuilder buf = new StringBuilder(len);
3514+
buf.append(str);
3515+
buf.repeat('0', trailingZeros);
35183516
return buf.toString();
35193517
}
3520-
String str ;
3518+
String str;
35213519
if(intCompact!=INFLATED) {
35223520
str = Long.toString(Math.abs(intCompact));
35233521
} else {
@@ -3527,23 +3525,25 @@ public String toPlainString() {
35273525
}
35283526

35293527
/* Returns a digit.digit string */
3530-
private String getValueString(int signum, String intString, int scale) {
3528+
private static String getValueString(int signum, String intString, int scale) {
35313529
/* Insert decimal point */
35323530
StringBuilder buf;
35333531
int insertionPoint = intString.length() - scale;
3534-
if (insertionPoint == 0) { /* Point goes right before intVal */
3532+
if (insertionPoint == 0) { /* Point goes just before intVal */
35353533
return (signum<0 ? "-0." : "0.") + intString;
35363534
} else if (insertionPoint > 0) { /* Point goes inside intVal */
35373535
buf = new StringBuilder(intString);
35383536
buf.insert(insertionPoint, '.');
35393537
if (signum < 0)
35403538
buf.insert(0, '-');
35413539
} else { /* We must insert zeros between point and intVal */
3542-
buf = new StringBuilder(3-insertionPoint + intString.length());
3543-
buf.append(signum<0 ? "-0." : "0.");
3544-
for (int i=0; i<-insertionPoint; i++) {
3545-
buf.append('0');
3540+
int len = (signum < 0 ? 3 : 2) + scale;
3541+
if (len < 0) {
3542+
throw new OutOfMemoryError("too large to fit in a String");
35463543
}
3544+
buf = new StringBuilder(len);
3545+
buf.append(signum<0 ? "-0." : "0.");
3546+
buf.repeat('0', -insertionPoint); // insertionPoint != MIN_VALUE
35473547
buf.append(intString);
35483548
}
35493549
return buf.toString();

‎test/jdk/java/math/BigDecimal/ToPlainStringTests.java

+39-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2004, 2018, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2004, 2023, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -23,7 +23,7 @@
2323

2424
/*
2525
* @test
26-
* @bug 4984872
26+
* @bug 4984872 8318915
2727
* @summary Basic tests of toPlainString method
2828
* @run main ToPlainStringTests
2929
* @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+EliminateAutoBox -XX:AutoBoxCacheMax=20000 ToPlainStringTests
@@ -67,6 +67,11 @@ public static void main(String argv[]) {
6767
{"12345678901234567890", "12345678901234567890"},
6868
{"12345678901234567890e22", "123456789012345678900000000000000000000000"},
6969
{"12345678901234567890e-22", "0.0012345678901234567890"},
70+
71+
{"12345e-1", "1234.5"},
72+
{"12345e-2", "123.45"},
73+
{"12345e-3", "12.345"},
74+
{"12345e-4", "1.2345"},
7075
};
7176

7277
int errors = 0;
@@ -89,6 +94,38 @@ public static void main(String argv[]) {
8994
}
9095
}
9196

97+
String[] failingCases = {
98+
"1E-" + (Integer.MAX_VALUE - 0), // MAX_VALUE + 2 chars
99+
"1E-" + (Integer.MAX_VALUE - 1), // MAX_VALUE + 1 chars
100+
101+
"-1E-" + (Integer.MAX_VALUE - 0), // MAX_VALUE + 3 chars
102+
"-1E-" + (Integer.MAX_VALUE - 1), // MAX_VALUE + 2 chars
103+
"-1E-" + (Integer.MAX_VALUE - 2), // MAX_VALUE + 1 chars
104+
105+
"123456789E-" + (Integer.MAX_VALUE - 0), // MAX_VALUE + 2 chars
106+
"123456789E-" + (Integer.MAX_VALUE - 1), // MAX_VALUE + 1 chars
107+
108+
"-123456789E-" + (Integer.MAX_VALUE - 0), // MAX_VALUE + 3 chars
109+
"-123456789E-" + (Integer.MAX_VALUE - 1), // MAX_VALUE + 2 chars
110+
"-123456789E-" + (Integer.MAX_VALUE - 2), // MAX_VALUE + 1 chars
111+
112+
"1E" + Integer.MAX_VALUE, // MAX_VALUE + 1 chars
113+
"123456789E" + Integer.MAX_VALUE, // MAX_VALUE + 9 chars
114+
115+
"-1E" + Integer.MAX_VALUE, // MAX_VALUE + 2 chars
116+
"-123456789E" + Integer.MAX_VALUE, // MAX_VALUE + 10 chars
117+
};
118+
/* We expect pre-emptive OutOfMemoryErrors, nothing else */
119+
for (String failingCase : failingCases) {
120+
try {
121+
new BigDecimal(failingCase).toPlainString();
122+
} catch (OutOfMemoryError expected) {
123+
continue;
124+
} catch (Throwable ignored) {
125+
}
126+
++errors;
127+
}
128+
92129
if(errors > 0)
93130
throw new RuntimeException(errors + " errors during run.");
94131
}

0 commit comments

Comments
 (0)
Please sign in to comment.