Skip to content

Commit

Permalink
8253459: Formatter treats index, width and precision > Integer.MAX_VA…
Browse files Browse the repository at this point in the history
…LUE incorrectly

Reviewed-by: rriggs, smarks
  • Loading branch information
Ian Graves authored and Stuart Marks committed Nov 19, 2020
1 parent b9db002 commit 080c707
Show file tree
Hide file tree
Showing 5 changed files with 175 additions and 8 deletions.
27 changes: 23 additions & 4 deletions src/java.base/share/classes/java/util/Formatter.java
Original file line number Diff line number Diff line change
Expand Up @@ -692,12 +692,28 @@
* <p> If the format specifier contains a width or precision with an invalid
* value or which is otherwise unsupported, then a {@link
* IllegalFormatWidthException} or {@link IllegalFormatPrecisionException}
* respectively will be thrown.
* respectively will be thrown. Similarly, values of zero for an argument
* index will result in an {@link IllegalFormatException}.
*
* <p> If a format specifier contains a conversion character that is not
* applicable to the corresponding argument, then an {@link
* IllegalFormatConversionException} will be thrown.
*
* <p> Values of <i>precision</i> must be in the range zero to
* {@link Integer#MAX_VALUE}, inclusive, otherwise
* {@link IllegalFormatPrecisionException} is thrown.</p>
*
* <p> Values of <i>width</i> must be in the range one to
* {@link Integer#MAX_VALUE}, inclusive, otherwise
* {@link IllegalFormatWidthException} will be thrown
* Note that widths can appear to have a negative value, but the negative sign
* is a <i>flag</i>. For example in the format string {@code "%-20s"} the
* <i>width</i> is <i>20</i> and the <i>flag</i> is "-".</p>
*
* <p> Values of <i>index</i> must be in the range one to
* {@link Integer#MAX_VALUE}, inclusive, otherwise
* {@link IllegalFormatException} will be thrown.</p>
*
* <p> All specified exceptions may be thrown by any of the {@code format}
* methods of {@code Formatter} as well as by any {@code format} convenience
* methods such as {@link String#format(String,Object...) String.format} and
Expand Down Expand Up @@ -2783,8 +2799,11 @@ private int index(String s, int start, int end) {
try {
// skip the trailing '$'
index = Integer.parseInt(s, start, end - 1, 10);
if (index <= 0) {
throw new IllegalFormatArgumentIndexException(index);
}
} catch (NumberFormatException x) {
assert(false);
throw new IllegalFormatArgumentIndexException(Integer.MIN_VALUE);
}
} else {
index = 0;
Expand All @@ -2811,7 +2830,7 @@ private int width(String s, int start, int end) {
if (width < 0)
throw new IllegalFormatWidthException(width);
} catch (NumberFormatException x) {
assert(false);
throw new IllegalFormatWidthException(Integer.MIN_VALUE);
}
}
return width;
Expand All @@ -2826,7 +2845,7 @@ private int precision(String s, int start, int end) {
if (precision < 0)
throw new IllegalFormatPrecisionException(precision);
} catch (NumberFormatException x) {
assert(false);
throw new IllegalFormatPrecisionException(Integer.MIN_VALUE);
}
}
return precision;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/

package java.util;

/**
* Unchecked exception thrown when the argument index is not within the valid
* range of supported argument index values. If an index value isn't
* representable by an {@code int} type, then the value
* {@code Integer.MIN_VALUE} will be used in the exception.
*
* @since 16
*/
class IllegalFormatArgumentIndexException extends IllegalFormatException {

@java.io.Serial
private static final long serialVersionUID = 4191767811181838112L;

private final int illegalIndex;

/**
* Constructs an instance of this class with the specified argument index
* @param index The value of a corresponding illegal argument index.
*/
IllegalFormatArgumentIndexException(int index) {
illegalIndex = index;
}

/**
* Gets the value of the illegal index.
* Returns {@code Integer.MIN_VALUE} if the illegal index is not
* representable by an {@code int}.
* @return the illegal index value
*/
int getIndex() {
return illegalIndex;
}

@Override
public String getMessage() {
int index = getIndex();

if (index == Integer.MIN_VALUE) {
return "Format argument index: (not representable as int)";
}

return String.format("Illegal format argument index = %d", getIndex());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@
/**
* Unchecked exception thrown when the precision is a negative value other than
* {@code -1}, the conversion does not support a precision, or the value is
* otherwise unsupported.
* otherwise unsupported. If the precision is not representable by an
* {@code int} type, then the value {@code Integer.MIN_VALUE} will be used
* in the exception.
*
* @since 1.5
*/
Expand All @@ -50,7 +52,8 @@ public IllegalFormatPrecisionException(int p) {
}

/**
* Returns the precision
* Returns the precision. If the precision isn't representable by an
* {@code int}, then will return {@code Integer.MIN_VALUE}.
*
* @return The precision
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@

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

/**
* Returns the width
* Returns the width. If the width is not representable by an {@code int},
* then returns {@code Integer.MIN_VALUE}.
*
* @return The width
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/

/*
* @test
* @bug 8253459
* @run testng TestFormatSpecifierBounds
*/

import java.util.*;
import org.testng.annotations.Test;
import static org.testng.Assert.*;

@Test
public class TestFormatSpecifierBounds {

public void testZeroIndex() {
IllegalFormatException e = expectThrows(IllegalFormatException.class, () -> {
String r = String.format("%0$s", "A", "B");
});
assertEquals(e.getMessage(), "Illegal format argument index = 0");
}

public void testNonRepresentableIntIndex() {
IllegalFormatException e = expectThrows(IllegalFormatException.class, () -> {
String r = String.format("%2147483648$s", "A", "B");
});
assertEquals(e.getMessage(), "Format argument index: (not representable as int)");
}

public void testZeroWidth() {
assertThrows(IllegalFormatException.class, () -> {
String r = String.format("%0s", "A", "B");
});
}

public void testNonRepresentableWidth() {
IllegalFormatException e = expectThrows(IllegalFormatException.class, () -> {
String r = String.format("%2147483648s", "A", "B");
});
assertEquals(e.getMessage(), Integer.toString(Integer.MIN_VALUE));
}

public void testNonRepresentablePrecision() {
IllegalFormatException e = expectThrows(IllegalFormatException.class, () -> {
String r = String.format("%.2147483648s", "A", "B");
});
assertEquals(e.getMessage(), Integer.toString(Integer.MIN_VALUE));
}
}

1 comment on commit 080c707

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.