diff --git a/src/main/java/org/apache/commons/lang3/Conversion.java b/src/main/java/org/apache/commons/lang3/Conversion.java index b91e52e765f..cf43e36c371 100644 --- a/src/main/java/org/apache/commons/lang3/Conversion.java +++ b/src/main/java/org/apache/commons/lang3/Conversion.java @@ -160,7 +160,7 @@ public static byte binaryToByte(final boolean[] src, final int srcPos, final byt if (src.length == 0 && srcPos == 0 || 0 == nBools) { return dstInit; } - if (nBools - 1 + dstPos >= Byte.SIZE) { + if ((long) nBools - 1 + dstPos >= Byte.SIZE) { throw new IllegalArgumentException("nBools - 1 + dstPos >= 8"); } byte out = dstInit; @@ -307,7 +307,7 @@ public static int binaryToInt(final boolean[] src, final int srcPos, final int d if (src.length == 0 && srcPos == 0 || 0 == nBools) { return dstInit; } - if (nBools - 1 + dstPos >= Integer.SIZE) { + if ((long) nBools - 1 + dstPos >= Integer.SIZE) { throw new IllegalArgumentException("nBools - 1 + dstPos >= 32"); } int out = dstInit; @@ -337,7 +337,7 @@ public static long binaryToLong(final boolean[] src, final int srcPos, final lon if (src.length == 0 && srcPos == 0 || 0 == nBools) { return dstInit; } - if (nBools - 1 + dstPos >= Long.SIZE) { + if ((long) nBools - 1 + dstPos >= Long.SIZE) { throw new IllegalArgumentException("nBools - 1 + dstPos >= 64"); } long out = dstInit; @@ -367,7 +367,7 @@ public static short binaryToShort(final boolean[] src, final int srcPos, final s if (src.length == 0 && srcPos == 0 || 0 == nBools) { return dstInit; } - if (nBools - 1 + dstPos >= Short.SIZE) { + if ((long) nBools - 1 + dstPos >= Short.SIZE) { throw new IllegalArgumentException("nBools - 1 + dstPos >= 16"); } short out = dstInit; @@ -397,7 +397,7 @@ public static int byteArrayToInt(final byte[] src, final int srcPos, final int d if (src.length == 0 && srcPos == 0 || 0 == nBytes) { return dstInit; } - if ((nBytes - 1) * Byte.SIZE + dstPos >= Integer.SIZE) { + if (((long) nBytes - 1) * Byte.SIZE + dstPos >= Integer.SIZE) { throw new IllegalArgumentException("(nBytes - 1) * 8 + dstPos >= 32"); } int out = dstInit; @@ -427,7 +427,7 @@ public static long byteArrayToLong(final byte[] src, final int srcPos, final lon if (src.length == 0 && srcPos == 0 || 0 == nBytes) { return dstInit; } - if ((nBytes - 1) * Byte.SIZE + dstPos >= Long.SIZE) { + if (((long) nBytes - 1) * Byte.SIZE + dstPos >= Long.SIZE) { throw new IllegalArgumentException("(nBytes - 1) * 8 + dstPos >= 64"); } long out = dstInit; @@ -457,7 +457,7 @@ public static short byteArrayToShort(final byte[] src, final int srcPos, final s if (src.length == 0 && srcPos == 0 || 0 == nBytes) { return dstInit; } - if ((nBytes - 1) * Byte.SIZE + dstPos >= Short.SIZE) { + if (((long) nBytes - 1) * Byte.SIZE + dstPos >= Short.SIZE) { throw new IllegalArgumentException("(nBytes - 1) * 8 + dstPos >= 16"); } short out = dstInit; @@ -503,7 +503,7 @@ public static boolean[] byteToBinary(final byte src, final int srcPos, final boo if (0 == nBools) { return dst; } - if (nBools - 1 + srcPos >= Byte.SIZE) { + if ((long) nBools - 1 + srcPos >= Byte.SIZE) { throw new IllegalArgumentException("nBools - 1 + srcPos >= 8"); } for (int i = 0; i < nBools; i++) { @@ -529,7 +529,7 @@ public static String byteToHex(final byte src, final int srcPos, final String ds if (0 == nHexs) { return dstInit; } - if ((nHexs - 1) * 4 + srcPos >= Byte.SIZE) { + if (((long) nHexs - 1) * 4 + srcPos >= Byte.SIZE) { throw new IllegalArgumentException("(nHexs - 1) * 4 + srcPos >= 8"); } final StringBuilder sb = new StringBuilder(dstInit); @@ -748,7 +748,7 @@ public static byte hexToByte(final String src, final int srcPos, final byte dstI if (0 == nHex) { return dstInit; } - if ((nHex - 1) * 4 + dstPos >= Byte.SIZE) { + if (((long) nHex - 1) * 4 + dstPos >= Byte.SIZE) { throw new IllegalArgumentException("(nHex - 1) * 4 + dstPos >= 8"); } byte out = dstInit; @@ -776,7 +776,7 @@ public static int hexToInt(final String src, final int srcPos, final int dstInit if (0 == nHex) { return dstInit; } - if ((nHex - 1) * 4 + dstPos >= Integer.SIZE) { + if (((long) nHex - 1) * 4 + dstPos >= Integer.SIZE) { throw new IllegalArgumentException("(nHexs - 1) * 4 + dstPos >= 32"); } int out = dstInit; @@ -804,7 +804,7 @@ public static long hexToLong(final String src, final int srcPos, final long dstI if (0 == nHex) { return dstInit; } - if ((nHex - 1) * 4 + dstPos >= Long.SIZE) { + if (((long) nHex - 1) * 4 + dstPos >= Long.SIZE) { throw new IllegalArgumentException("(nHexs - 1) * 4 + dstPos >= 64"); } long out = dstInit; @@ -832,7 +832,7 @@ public static short hexToShort(final String src, final int srcPos, final short d if (0 == nHex) { return dstInit; } - if ((nHex - 1) * 4 + dstPos >= Short.SIZE) { + if (((long) nHex - 1) * 4 + dstPos >= Short.SIZE) { throw new IllegalArgumentException("(nHexs - 1) * 4 + dstPos >= 16"); } short out = dstInit; @@ -862,7 +862,7 @@ public static long intArrayToLong(final int[] src, final int srcPos, final long if (src.length == 0 && srcPos == 0 || 0 == nInts) { return dstInit; } - if ((nInts - 1) * Integer.SIZE + dstPos >= Long.SIZE) { + if (((long) nInts - 1) * Integer.SIZE + dstPos >= Long.SIZE) { throw new IllegalArgumentException("(nInts - 1) * 32 + dstPos >= 64"); } long out = dstInit; @@ -892,7 +892,7 @@ public static boolean[] intToBinary(final int src, final int srcPos, final boole if (0 == nBools) { return dst; } - if (nBools - 1 + srcPos >= Integer.SIZE) { + if ((long) nBools - 1 + srcPos >= Integer.SIZE) { throw new IllegalArgumentException("nBools - 1 + srcPos >= 32"); } for (int i = 0; i < nBools; i++) { @@ -919,7 +919,7 @@ public static byte[] intToByteArray(final int src, final int srcPos, final byte[ if (0 == nBytes) { return dst; } - if ((nBytes - 1) * Byte.SIZE + srcPos >= Integer.SIZE) { + if (((long) nBytes - 1) * Byte.SIZE + srcPos >= Integer.SIZE) { throw new IllegalArgumentException("(nBytes - 1) * 8 + srcPos >= 32"); } for (int i = 0; i < nBytes; i++) { @@ -945,7 +945,7 @@ public static String intToHex(final int src, final int srcPos, final String dstI if (0 == nHexs) { return dstInit; } - if ((nHexs - 1) * 4 + srcPos >= Integer.SIZE) { + if (((long) nHexs - 1) * 4 + srcPos >= Integer.SIZE) { throw new IllegalArgumentException("(nHexs - 1) * 4 + srcPos >= 32"); } final StringBuilder sb = new StringBuilder(dstInit); @@ -1061,7 +1061,7 @@ public static short[] intToShortArray(final int src, final int srcPos, final sho if (0 == nShorts) { return dst; } - if ((nShorts - 1) * Short.SIZE + srcPos >= Integer.SIZE) { + if (((long) nShorts - 1) * Short.SIZE + srcPos >= Integer.SIZE) { throw new IllegalArgumentException("(nShorts - 1) * 16 + srcPos >= 32"); } for (int i = 0; i < nShorts; i++) { @@ -1088,7 +1088,7 @@ public static boolean[] longToBinary(final long src, final int srcPos, final boo if (0 == nBools) { return dst; } - if (nBools - 1 + srcPos >= Long.SIZE) { + if ((long) nBools - 1 + srcPos >= Long.SIZE) { throw new IllegalArgumentException("nBools - 1 + srcPos >= 64"); } for (int i = 0; i < nBools; i++) { @@ -1115,7 +1115,7 @@ public static byte[] longToByteArray(final long src, final int srcPos, final byt if (0 == nBytes) { return dst; } - if ((nBytes - 1) * Byte.SIZE + srcPos >= Long.SIZE) { + if (((long) nBytes - 1) * Byte.SIZE + srcPos >= Long.SIZE) { throw new IllegalArgumentException("(nBytes - 1) * 8 + srcPos >= 64"); } for (int i = 0; i < nBytes; i++) { @@ -1141,7 +1141,7 @@ public static String longToHex(final long src, final int srcPos, final String ds if (0 == nHexs) { return dstInit; } - if ((nHexs - 1) * 4 + srcPos >= Long.SIZE) { + if (((long) nHexs - 1) * 4 + srcPos >= Long.SIZE) { throw new IllegalArgumentException("(nHexs - 1) * 4 + srcPos >= 64"); } final StringBuilder sb = new StringBuilder(dstInit); @@ -1176,7 +1176,7 @@ public static int[] longToIntArray(final long src, final int srcPos, final int[] if (0 == nInts) { return dst; } - if ((nInts - 1) * Integer.SIZE + srcPos >= Long.SIZE) { + if (((long) nInts - 1) * Integer.SIZE + srcPos >= Long.SIZE) { throw new IllegalArgumentException("(nInts - 1) * 32 + srcPos >= 64"); } for (int i = 0; i < nInts; i++) { @@ -1203,7 +1203,7 @@ public static short[] longToShortArray(final long src, final int srcPos, final s if (0 == nShorts) { return dst; } - if ((nShorts - 1) * Short.SIZE + srcPos >= Long.SIZE) { + if (((long) nShorts - 1) * Short.SIZE + srcPos >= Long.SIZE) { throw new IllegalArgumentException("(nShorts - 1) * 16 + srcPos >= 64"); } for (int i = 0; i < nShorts; i++) { @@ -1230,7 +1230,7 @@ public static int shortArrayToInt(final short[] src, final int srcPos, final int if (src.length == 0 && srcPos == 0 || 0 == nShorts) { return dstInit; } - if ((nShorts - 1) * Short.SIZE + dstPos >= Integer.SIZE) { + if (((long) nShorts - 1) * Short.SIZE + dstPos >= Integer.SIZE) { throw new IllegalArgumentException("(nShorts - 1) * 16 + dstPos >= 32"); } int out = dstInit; @@ -1260,7 +1260,7 @@ public static long shortArrayToLong(final short[] src, final int srcPos, final l if (src.length == 0 && srcPos == 0 || 0 == nShorts) { return dstInit; } - if ((nShorts - 1) * Short.SIZE + dstPos >= Long.SIZE) { + if (((long) nShorts - 1) * Short.SIZE + dstPos >= Long.SIZE) { throw new IllegalArgumentException("(nShorts - 1) * 16 + dstPos >= 64"); } long out = dstInit; @@ -1290,7 +1290,7 @@ public static boolean[] shortToBinary(final short src, final int srcPos, final b if (0 == nBools) { return dst; } - if (nBools - 1 + srcPos >= Short.SIZE) { + if ((long) nBools - 1 + srcPos >= Short.SIZE) { throw new IllegalArgumentException("nBools - 1 + srcPos >= 16"); } assert nBools - 1 < Short.SIZE - srcPos; @@ -1318,7 +1318,7 @@ public static byte[] shortToByteArray(final short src, final int srcPos, final b if (0 == nBytes) { return dst; } - if ((nBytes - 1) * Byte.SIZE + srcPos >= Short.SIZE) { + if (((long) nBytes - 1) * Byte.SIZE + srcPos >= Short.SIZE) { throw new IllegalArgumentException("(nBytes - 1) * 8 + srcPos >= 16"); } for (int i = 0; i < nBytes; i++) { @@ -1344,7 +1344,7 @@ public static String shortToHex(final short src, final int srcPos, final String if (0 == nHexs) { return dstInit; } - if ((nHexs - 1) * 4 + srcPos >= Short.SIZE) { + if (((long) nHexs - 1) * 4 + srcPos >= Short.SIZE) { throw new IllegalArgumentException("(nHexs - 1) * 4 + srcPos >= 16"); } final StringBuilder sb = new StringBuilder(dstInit); diff --git a/src/test/java/org/apache/commons/lang3/ConversionTest.java b/src/test/java/org/apache/commons/lang3/ConversionTest.java index b0b31630162..9b475a9b339 100644 --- a/src/test/java/org/apache/commons/lang3/ConversionTest.java +++ b/src/test/java/org/apache/commons/lang3/ConversionTest.java @@ -1729,4 +1729,49 @@ void testUuidToByteArray() { assertIllegalArgumentException(() -> Conversion.uuidToByteArray(new UUID( 0xFFEEDDCCBBAA9988L, 0x7766554433221100L), new byte[16], 2, 17)); } + + /** + * Each converter documents an {@link IllegalArgumentException} when the requested count and position exceed the destination width, but the guard was + * evaluated in {@code int} arithmetic and silently overflowed for a large count or position, so the documented exception never fired. + */ + @Test + void testOverflowingCountOrPositionThrowsIllegalArgumentException() { + final int big = Integer.MAX_VALUE; + // nBools - 1 + dstPos + assertIllegalArgumentException(() -> Conversion.binaryToByte(new boolean[]{true}, 0, (byte) 0, big, 2)); + assertIllegalArgumentException(() -> Conversion.binaryToInt(new boolean[]{true}, 0, 0, big, 2)); + assertIllegalArgumentException(() -> Conversion.binaryToLong(new boolean[]{true}, 0, 0L, big, 2)); + assertIllegalArgumentException(() -> Conversion.binaryToShort(new boolean[]{true}, 0, (short) 0, big, 2)); + // nBools - 1 + srcPos + assertIllegalArgumentException(() -> Conversion.byteToBinary((byte) 1, big, new boolean[8], 0, 2)); + assertIllegalArgumentException(() -> Conversion.intToBinary(0, big, new boolean[32], 0, 2)); + assertIllegalArgumentException(() -> Conversion.longToBinary(0L, big, new boolean[64], 0, 2)); + assertIllegalArgumentException(() -> Conversion.shortToBinary((short) 0, big, new boolean[16], 0, 2)); + // (nBytes - 1) * 8 + dstPos + assertIllegalArgumentException(() -> Conversion.byteArrayToInt(new byte[]{1}, 0, 0, 0, big)); + assertIllegalArgumentException(() -> Conversion.byteArrayToLong(new byte[]{1}, 0, 0L, 0, big)); + assertIllegalArgumentException(() -> Conversion.byteArrayToShort(new byte[]{1}, 0, (short) 0, 0, big)); + // (nBytes - 1) * 8 + srcPos + assertIllegalArgumentException(() -> Conversion.intToByteArray(0, 0, new byte[4], 0, big)); + assertIllegalArgumentException(() -> Conversion.longToByteArray(0L, 0, new byte[8], 0, big)); + assertIllegalArgumentException(() -> Conversion.shortToByteArray((short) 0, 0, new byte[2], 0, big)); + // (nHex - 1) * 4 + dstPos + assertIllegalArgumentException(() -> Conversion.hexToByte("f", 0, (byte) 0, 0, big)); + assertIllegalArgumentException(() -> Conversion.hexToInt("f", 0, 0, 0, big)); + assertIllegalArgumentException(() -> Conversion.hexToLong("f", 0, 0L, 0, big)); + assertIllegalArgumentException(() -> Conversion.hexToShort("f", 0, (short) 0, 0, big)); + // (nHexs - 1) * 4 + srcPos + assertIllegalArgumentException(() -> Conversion.byteToHex((byte) 0, 0, "", 0, big)); + assertIllegalArgumentException(() -> Conversion.intToHex(0, 0, "", 0, big)); + assertIllegalArgumentException(() -> Conversion.longToHex(0L, 0, "", 0, big)); + assertIllegalArgumentException(() -> Conversion.shortToHex((short) 0, 0, "", 0, big)); + // (nInts - 1) * 32 + pos + assertIllegalArgumentException(() -> Conversion.intArrayToLong(new int[]{0}, 0, 0L, 0, big)); + assertIllegalArgumentException(() -> Conversion.longToIntArray(0L, 0, new int[2], 0, big)); + // (nShorts - 1) * 16 + pos + assertIllegalArgumentException(() -> Conversion.shortArrayToInt(new short[]{0}, 0, 0, 0, big)); + assertIllegalArgumentException(() -> Conversion.shortArrayToLong(new short[]{0}, 0, 0L, 0, big)); + assertIllegalArgumentException(() -> Conversion.intToShortArray(0, 0, new short[2], 0, big)); + assertIllegalArgumentException(() -> Conversion.longToShortArray(0L, 0, new short[4], 0, big)); + } }