Skip to content

Commit 080c707

Browse files
Ian GravesStuart Marks
authored andcommitted
8253459: Formatter treats index, width and precision > Integer.MAX_VALUE incorrectly
Reviewed-by: rriggs, smarks
1 parent b9db002 commit 080c707

File tree

5 files changed

+175
-8
lines changed

5 files changed

+175
-8
lines changed

src/java.base/share/classes/java/util/Formatter.java

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -692,12 +692,28 @@
692692
* <p> If the format specifier contains a width or precision with an invalid
693693
* value or which is otherwise unsupported, then a {@link
694694
* IllegalFormatWidthException} or {@link IllegalFormatPrecisionException}
695-
* respectively will be thrown.
695+
* respectively will be thrown. Similarly, values of zero for an argument
696+
* index will result in an {@link IllegalFormatException}.
696697
*
697698
* <p> If a format specifier contains a conversion character that is not
698699
* applicable to the corresponding argument, then an {@link
699700
* IllegalFormatConversionException} will be thrown.
700701
*
702+
* <p> Values of <i>precision</i> must be in the range zero to
703+
* {@link Integer#MAX_VALUE}, inclusive, otherwise
704+
* {@link IllegalFormatPrecisionException} is thrown.</p>
705+
*
706+
* <p> Values of <i>width</i> must be in the range one to
707+
* {@link Integer#MAX_VALUE}, inclusive, otherwise
708+
* {@link IllegalFormatWidthException} will be thrown
709+
* Note that widths can appear to have a negative value, but the negative sign
710+
* is a <i>flag</i>. For example in the format string {@code "%-20s"} the
711+
* <i>width</i> is <i>20</i> and the <i>flag</i> is "-".</p>
712+
*
713+
* <p> Values of <i>index</i> must be in the range one to
714+
* {@link Integer#MAX_VALUE}, inclusive, otherwise
715+
* {@link IllegalFormatException} will be thrown.</p>
716+
*
701717
* <p> All specified exceptions may be thrown by any of the {@code format}
702718
* methods of {@code Formatter} as well as by any {@code format} convenience
703719
* methods such as {@link String#format(String,Object...) String.format} and
@@ -2783,8 +2799,11 @@ private int index(String s, int start, int end) {
27832799
try {
27842800
// skip the trailing '$'
27852801
index = Integer.parseInt(s, start, end - 1, 10);
2802+
if (index <= 0) {
2803+
throw new IllegalFormatArgumentIndexException(index);
2804+
}
27862805
} catch (NumberFormatException x) {
2787-
assert(false);
2806+
throw new IllegalFormatArgumentIndexException(Integer.MIN_VALUE);
27882807
}
27892808
} else {
27902809
index = 0;
@@ -2811,7 +2830,7 @@ private int width(String s, int start, int end) {
28112830
if (width < 0)
28122831
throw new IllegalFormatWidthException(width);
28132832
} catch (NumberFormatException x) {
2814-
assert(false);
2833+
throw new IllegalFormatWidthException(Integer.MIN_VALUE);
28152834
}
28162835
}
28172836
return width;
@@ -2826,7 +2845,7 @@ private int precision(String s, int start, int end) {
28262845
if (precision < 0)
28272846
throw new IllegalFormatPrecisionException(precision);
28282847
} catch (NumberFormatException x) {
2829-
assert(false);
2848+
throw new IllegalFormatPrecisionException(Integer.MIN_VALUE);
28302849
}
28312850
}
28322851
return precision;
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation. Oracle designates this
8+
* particular file as subject to the "Classpath" exception as provided
9+
* by Oracle in the LICENSE file that accompanied this code.
10+
*
11+
* This code is distributed in the hope that it will be useful, but WITHOUT
12+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+
* version 2 for more details (a copy is included in the LICENSE file that
15+
* accompanied this code).
16+
*
17+
* You should have received a copy of the GNU General Public License version
18+
* 2 along with this work; if not, write to the Free Software Foundation,
19+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+
*
21+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+
* or visit www.oracle.com if you need additional information or have any
23+
* questions.
24+
*/
25+
26+
package java.util;
27+
28+
/**
29+
* Unchecked exception thrown when the argument index is not within the valid
30+
* range of supported argument index values. If an index value isn't
31+
* representable by an {@code int} type, then the value
32+
* {@code Integer.MIN_VALUE} will be used in the exception.
33+
*
34+
* @since 16
35+
*/
36+
class IllegalFormatArgumentIndexException extends IllegalFormatException {
37+
38+
@java.io.Serial
39+
private static final long serialVersionUID = 4191767811181838112L;
40+
41+
private final int illegalIndex;
42+
43+
/**
44+
* Constructs an instance of this class with the specified argument index
45+
* @param index The value of a corresponding illegal argument index.
46+
*/
47+
IllegalFormatArgumentIndexException(int index) {
48+
illegalIndex = index;
49+
}
50+
51+
/**
52+
* Gets the value of the illegal index.
53+
* Returns {@code Integer.MIN_VALUE} if the illegal index is not
54+
* representable by an {@code int}.
55+
* @return the illegal index value
56+
*/
57+
int getIndex() {
58+
return illegalIndex;
59+
}
60+
61+
@Override
62+
public String getMessage() {
63+
int index = getIndex();
64+
65+
if (index == Integer.MIN_VALUE) {
66+
return "Format argument index: (not representable as int)";
67+
}
68+
69+
return String.format("Illegal format argument index = %d", getIndex());
70+
}
71+
72+
}

src/java.base/share/classes/java/util/IllegalFormatPrecisionException.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@
2828
/**
2929
* Unchecked exception thrown when the precision is a negative value other than
3030
* {@code -1}, the conversion does not support a precision, or the value is
31-
* otherwise unsupported.
31+
* otherwise unsupported. If the precision is not representable by an
32+
* {@code int} type, then the value {@code Integer.MIN_VALUE} will be used
33+
* in the exception.
3234
*
3335
* @since 1.5
3436
*/
@@ -50,7 +52,8 @@ public IllegalFormatPrecisionException(int p) {
5052
}
5153

5254
/**
53-
* Returns the precision
55+
* Returns the precision. If the precision isn't representable by an
56+
* {@code int}, then will return {@code Integer.MIN_VALUE}.
5457
*
5558
* @return The precision
5659
*/

src/java.base/share/classes/java/util/IllegalFormatWidthException.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@
2727

2828
/**
2929
* Unchecked exception thrown when the format width is a negative value other
30-
* than {@code -1} or is otherwise unsupported.
30+
* than {@code -1} or is otherwise unsupported. If a given format width is not
31+
* representable by an {@code int} type, then the value
32+
* {@code Integer.MIN_VALUE} will be used in the exception.
3133
*
3234
* @since 1.5
3335
*/
@@ -49,7 +51,8 @@ public IllegalFormatWidthException(int w) {
4951
}
5052

5153
/**
52-
* Returns the width
54+
* Returns the width. If the width is not representable by an {@code int},
55+
* then returns {@code Integer.MIN_VALUE}.
5356
*
5457
* @return The width
5558
*/
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
/*
25+
* @test
26+
* @bug 8253459
27+
* @run testng TestFormatSpecifierBounds
28+
*/
29+
30+
import java.util.*;
31+
import org.testng.annotations.Test;
32+
import static org.testng.Assert.*;
33+
34+
@Test
35+
public class TestFormatSpecifierBounds {
36+
37+
public void testZeroIndex() {
38+
IllegalFormatException e = expectThrows(IllegalFormatException.class, () -> {
39+
String r = String.format("%0$s", "A", "B");
40+
});
41+
assertEquals(e.getMessage(), "Illegal format argument index = 0");
42+
}
43+
44+
public void testNonRepresentableIntIndex() {
45+
IllegalFormatException e = expectThrows(IllegalFormatException.class, () -> {
46+
String r = String.format("%2147483648$s", "A", "B");
47+
});
48+
assertEquals(e.getMessage(), "Format argument index: (not representable as int)");
49+
}
50+
51+
public void testZeroWidth() {
52+
assertThrows(IllegalFormatException.class, () -> {
53+
String r = String.format("%0s", "A", "B");
54+
});
55+
}
56+
57+
public void testNonRepresentableWidth() {
58+
IllegalFormatException e = expectThrows(IllegalFormatException.class, () -> {
59+
String r = String.format("%2147483648s", "A", "B");
60+
});
61+
assertEquals(e.getMessage(), Integer.toString(Integer.MIN_VALUE));
62+
}
63+
64+
public void testNonRepresentablePrecision() {
65+
IllegalFormatException e = expectThrows(IllegalFormatException.class, () -> {
66+
String r = String.format("%.2147483648s", "A", "B");
67+
});
68+
assertEquals(e.getMessage(), Integer.toString(Integer.MIN_VALUE));
69+
}
70+
}

0 commit comments

Comments
 (0)