Skip to content

Commit 508cef7

Browse files
Istvan NeuwirthGoogle Java Core Libraries
authored andcommitted
Changed *.concat() to throw IllegalArgumentException if the input arrays contain too many elements.
Fixes #7376 Fixes #3303 This change comes from @perceptron8, who generalized the earlier PR by @ineuwirth. RELNOTES=n/a PiperOrigin-RevId: 668024782
1 parent 137798d commit 508cef7

File tree

30 files changed

+608
-34
lines changed

30 files changed

+608
-34
lines changed

android/guava-tests/test/com/google/common/primitives/BooleansTest.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,37 @@ public void testConcat() {
130130
.isEqualTo(new boolean[] {false, false, true});
131131
}
132132

133+
@GwtIncompatible // different overflow behavior; could probably be made to work by using ~~
134+
public void testConcat_overflow_negative() {
135+
int dim1 = 1 << 16;
136+
int dim2 = 1 << 15;
137+
assertThat(dim1 * dim2).isLessThan(0);
138+
testConcatOverflow(dim1, dim2);
139+
}
140+
141+
@GwtIncompatible // different overflow behavior; could probably be made to work by using ~~
142+
public void testConcat_overflow_nonNegative() {
143+
int dim1 = 1 << 16;
144+
int dim2 = 1 << 16;
145+
assertThat(dim1 * dim2).isAtLeast(0);
146+
testConcatOverflow(dim1, dim2);
147+
}
148+
149+
private static void testConcatOverflow(int arraysDim1, int arraysDim2) {
150+
assertThat((long) arraysDim1 * arraysDim2).isNotEqualTo((long) (arraysDim1 * arraysDim2));
151+
152+
boolean[][] arrays = new boolean[arraysDim1][];
153+
// it's shared to avoid using too much memory in tests
154+
boolean[] sharedArray = new boolean[arraysDim2];
155+
Arrays.fill(arrays, sharedArray);
156+
157+
try {
158+
Booleans.concat(arrays);
159+
fail();
160+
} catch (IllegalArgumentException expected) {
161+
}
162+
}
163+
133164
public void testEnsureCapacity() {
134165
assertThat(Booleans.ensureCapacity(EMPTY, 0, 1)).isSameInstanceAs(EMPTY);
135166
assertThat(Booleans.ensureCapacity(ARRAY_FALSE, 0, 1)).isSameInstanceAs(ARRAY_FALSE);

android/guava-tests/test/com/google/common/primitives/BytesTest.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,37 @@ public void testConcat() {
131131
.isEqualTo(new byte[] {(byte) 1, (byte) 2, (byte) 3, (byte) 4});
132132
}
133133

134+
@GwtIncompatible // different overflow behavior; could probably be made to work by using ~~
135+
public void testConcat_overflow_negative() {
136+
int dim1 = 1 << 16;
137+
int dim2 = 1 << 15;
138+
assertThat(dim1 * dim2).isLessThan(0);
139+
testConcatOverflow(dim1, dim2);
140+
}
141+
142+
@GwtIncompatible // different overflow behavior; could probably be made to work by using ~~
143+
public void testConcat_overflow_nonNegative() {
144+
int dim1 = 1 << 16;
145+
int dim2 = 1 << 16;
146+
assertThat(dim1 * dim2).isAtLeast(0);
147+
testConcatOverflow(dim1, dim2);
148+
}
149+
150+
private static void testConcatOverflow(int arraysDim1, int arraysDim2) {
151+
assertThat((long) arraysDim1 * arraysDim2).isNotEqualTo((long) (arraysDim1 * arraysDim2));
152+
153+
byte[][] arrays = new byte[arraysDim1][];
154+
// it's shared to avoid using too much memory in tests
155+
byte[] sharedArray = new byte[arraysDim2];
156+
Arrays.fill(arrays, sharedArray);
157+
158+
try {
159+
Bytes.concat(arrays);
160+
fail();
161+
} catch (IllegalArgumentException expected) {
162+
}
163+
}
164+
134165
public void testEnsureCapacity() {
135166
assertThat(Bytes.ensureCapacity(EMPTY, 0, 1)).isSameInstanceAs(EMPTY);
136167
assertThat(Bytes.ensureCapacity(ARRAY1, 0, 1)).isSameInstanceAs(ARRAY1);

android/guava-tests/test/com/google/common/primitives/CharsTest.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,37 @@ public void testConcat() {
222222
.isEqualTo(new char[] {(char) 1, (char) 2, (char) 3, (char) 4});
223223
}
224224

225+
@GwtIncompatible // different overflow behavior; could probably be made to work by using ~~
226+
public void testConcat_overflow_negative() {
227+
int dim1 = 1 << 16;
228+
int dim2 = 1 << 15;
229+
assertThat(dim1 * dim2).isLessThan(0);
230+
testConcatOverflow(dim1, dim2);
231+
}
232+
233+
@GwtIncompatible // different overflow behavior; could probably be made to work by using ~~
234+
public void testConcat_overflow_nonNegative() {
235+
int dim1 = 1 << 16;
236+
int dim2 = 1 << 16;
237+
assertThat(dim1 * dim2).isAtLeast(0);
238+
testConcatOverflow(dim1, dim2);
239+
}
240+
241+
private static void testConcatOverflow(int arraysDim1, int arraysDim2) {
242+
assertThat((long) arraysDim1 * arraysDim2).isNotEqualTo((long) (arraysDim1 * arraysDim2));
243+
244+
char[][] arrays = new char[arraysDim1][];
245+
// it's shared to avoid using too much memory in tests
246+
char[] sharedArray = new char[arraysDim2];
247+
Arrays.fill(arrays, sharedArray);
248+
249+
try {
250+
Chars.concat(arrays);
251+
fail();
252+
} catch (IllegalArgumentException expected) {
253+
}
254+
}
255+
225256
@GwtIncompatible // Chars.fromByteArray
226257
public void testFromByteArray() {
227258
assertThat(Chars.fromByteArray(new byte[] {0x23, 0x45, (byte) 0xDC})).isEqualTo('\u2345');

android/guava-tests/test/com/google/common/primitives/DoublesTest.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,37 @@ public void testConcat() {
280280
.isEqualTo(new double[] {(double) 1, (double) 2, (double) 3, (double) 4});
281281
}
282282

283+
@GwtIncompatible // different overflow behavior; could probably be made to work by using ~~
284+
public void testConcat_overflow_negative() {
285+
int dim1 = 1 << 16;
286+
int dim2 = 1 << 15;
287+
assertThat(dim1 * dim2).isLessThan(0);
288+
testConcatOverflow(dim1, dim2);
289+
}
290+
291+
@GwtIncompatible // different overflow behavior; could probably be made to work by using ~~
292+
public void testConcat_overflow_nonNegative() {
293+
int dim1 = 1 << 16;
294+
int dim2 = 1 << 16;
295+
assertThat(dim1 * dim2).isAtLeast(0);
296+
testConcatOverflow(dim1, dim2);
297+
}
298+
299+
private static void testConcatOverflow(int arraysDim1, int arraysDim2) {
300+
assertThat((long) arraysDim1 * arraysDim2).isNotEqualTo((long) (arraysDim1 * arraysDim2));
301+
302+
double[][] arrays = new double[arraysDim1][];
303+
// it's shared to avoid using too much memory in tests
304+
double[] sharedArray = new double[arraysDim2];
305+
Arrays.fill(arrays, sharedArray);
306+
307+
try {
308+
Doubles.concat(arrays);
309+
fail();
310+
} catch (IllegalArgumentException expected) {
311+
}
312+
}
313+
283314
public void testEnsureCapacity() {
284315
assertThat(Doubles.ensureCapacity(EMPTY, 0, 1)).isSameInstanceAs(EMPTY);
285316
assertThat(Doubles.ensureCapacity(ARRAY1, 0, 1)).isSameInstanceAs(ARRAY1);

android/guava-tests/test/com/google/common/primitives/FloatsTest.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,37 @@ public void testConcat() {
267267
.isEqualTo(new float[] {(float) 1, (float) 2, (float) 3, (float) 4});
268268
}
269269

270+
@GwtIncompatible // different overflow behavior; could probably be made to work by using ~~
271+
public void testConcat_overflow_negative() {
272+
int dim1 = 1 << 16;
273+
int dim2 = 1 << 15;
274+
assertThat(dim1 * dim2).isLessThan(0);
275+
testConcatOverflow(dim1, dim2);
276+
}
277+
278+
@GwtIncompatible // different overflow behavior; could probably be made to work by using ~~
279+
public void testConcat_overflow_nonNegative() {
280+
int dim1 = 1 << 16;
281+
int dim2 = 1 << 16;
282+
assertThat(dim1 * dim2).isAtLeast(0);
283+
testConcatOverflow(dim1, dim2);
284+
}
285+
286+
private static void testConcatOverflow(int arraysDim1, int arraysDim2) {
287+
assertThat((long) arraysDim1 * arraysDim2).isNotEqualTo((long) (arraysDim1 * arraysDim2));
288+
289+
float[][] arrays = new float[arraysDim1][];
290+
// it's shared to avoid using too much memory in tests
291+
float[] sharedArray = new float[arraysDim2];
292+
Arrays.fill(arrays, sharedArray);
293+
294+
try {
295+
Floats.concat(arrays);
296+
fail();
297+
} catch (IllegalArgumentException expected) {
298+
}
299+
}
300+
270301
public void testEnsureCapacity() {
271302
assertThat(Floats.ensureCapacity(EMPTY, 0, 1)).isSameInstanceAs(EMPTY);
272303
assertThat(Floats.ensureCapacity(ARRAY1, 0, 1)).isSameInstanceAs(ARRAY1);

android/guava-tests/test/com/google/common/primitives/IntsTest.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,37 @@ public void testConcat() {
224224
.isEqualTo(new int[] {(int) 1, (int) 2, (int) 3, (int) 4});
225225
}
226226

227+
@GwtIncompatible // different overflow behavior; could probably be made to work by using ~~
228+
public void testConcat_overflow_negative() {
229+
int dim1 = 1 << 16;
230+
int dim2 = 1 << 15;
231+
assertThat(dim1 * dim2).isLessThan(0);
232+
testConcatOverflow(dim1, dim2);
233+
}
234+
235+
@GwtIncompatible // different overflow behavior; could probably be made to work by using ~~
236+
public void testConcat_overflow_nonNegative() {
237+
int dim1 = 1 << 16;
238+
int dim2 = 1 << 16;
239+
assertThat(dim1 * dim2).isAtLeast(0);
240+
testConcatOverflow(dim1, dim2);
241+
}
242+
243+
private static void testConcatOverflow(int arraysDim1, int arraysDim2) {
244+
assertThat((long) arraysDim1 * arraysDim2).isNotEqualTo((long) (arraysDim1 * arraysDim2));
245+
246+
int[][] arrays = new int[arraysDim1][];
247+
// it's shared to avoid using too much memory in tests
248+
int[] sharedArray = new int[arraysDim2];
249+
Arrays.fill(arrays, sharedArray);
250+
251+
try {
252+
Ints.concat(arrays);
253+
fail();
254+
} catch (IllegalArgumentException expected) {
255+
}
256+
}
257+
227258
public void testToByteArray() {
228259
assertThat(Ints.toByteArray(0x12131415)).isEqualTo(new byte[] {0x12, 0x13, 0x14, 0x15});
229260
assertThat(Ints.toByteArray(0xFFEEDDCC))

android/guava-tests/test/com/google/common/primitives/LongsTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -201,18 +201,18 @@ public void testConcat_overflow_negative() {
201201
int dim1 = 1 << 16;
202202
int dim2 = 1 << 15;
203203
assertThat(dim1 * dim2).isLessThan(0);
204-
testConcat_overflow(dim1, dim2);
204+
testConcatOverflow(dim1, dim2);
205205
}
206206

207207
@GwtIncompatible // different overflow behavior; could probably be made to work by using ~~
208208
public void testConcat_overflow_nonNegative() {
209209
int dim1 = 1 << 16;
210210
int dim2 = 1 << 16;
211211
assertThat(dim1 * dim2).isAtLeast(0);
212-
testConcat_overflow(dim1, dim2);
212+
testConcatOverflow(dim1, dim2);
213213
}
214214

215-
private static void testConcat_overflow(int arraysDim1, int arraysDim2) {
215+
private static void testConcatOverflow(int arraysDim1, int arraysDim2) {
216216
assertThat((long) arraysDim1 * arraysDim2).isNotEqualTo((long) (arraysDim1 * arraysDim2));
217217

218218
long[][] arrays = new long[arraysDim1][];

android/guava-tests/test/com/google/common/primitives/ShortsTest.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,37 @@ public void testConcat() {
243243
.isEqualTo(new short[] {(short) 1, (short) 2, (short) 3, (short) 4});
244244
}
245245

246+
@GwtIncompatible // different overflow behavior; could probably be made to work by using ~~
247+
public void testConcat_overflow_negative() {
248+
int dim1 = 1 << 16;
249+
int dim2 = 1 << 15;
250+
assertThat(dim1 * dim2).isLessThan(0);
251+
testConcatOverflow(dim1, dim2);
252+
}
253+
254+
@GwtIncompatible // different overflow behavior; could probably be made to work by using ~~
255+
public void testConcat_overflow_nonNegative() {
256+
int dim1 = 1 << 16;
257+
int dim2 = 1 << 16;
258+
assertThat(dim1 * dim2).isAtLeast(0);
259+
testConcatOverflow(dim1, dim2);
260+
}
261+
262+
private static void testConcatOverflow(int arraysDim1, int arraysDim2) {
263+
assertThat((long) arraysDim1 * arraysDim2).isNotEqualTo((long) (arraysDim1 * arraysDim2));
264+
265+
short[][] arrays = new short[arraysDim1][];
266+
// it's shared to avoid using too much memory in tests
267+
short[] sharedArray = new short[arraysDim2];
268+
Arrays.fill(arrays, sharedArray);
269+
270+
try {
271+
Shorts.concat(arrays);
272+
fail();
273+
} catch (IllegalArgumentException expected) {
274+
}
275+
}
276+
246277
@GwtIncompatible // Shorts.toByteArray
247278
public void testToByteArray() {
248279
assertThat(Shorts.toByteArray((short) 0x2345)).isEqualTo(new byte[] {0x23, 0x45});

android/guava/src/com/google/common/primitives/Booleans.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -230,13 +230,15 @@ private static int lastIndexOf(boolean[] array, boolean target, int start, int e
230230
*
231231
* @param arrays zero or more {@code boolean} arrays
232232
* @return a single array containing all the values from the source arrays, in order
233+
* @throws IllegalArgumentException if the total number of elements in {@code arrays} does not fit
234+
* in an {@code int}
233235
*/
234236
public static boolean[] concat(boolean[]... arrays) {
235-
int length = 0;
237+
long length = 0;
236238
for (boolean[] array : arrays) {
237239
length += array.length;
238240
}
239-
boolean[] result = new boolean[length];
241+
boolean[] result = new boolean[checkNoOverflow(length)];
240242
int pos = 0;
241243
for (boolean[] array : arrays) {
242244
System.arraycopy(array, 0, result, pos, array.length);
@@ -245,6 +247,14 @@ public static boolean[] concat(boolean[]... arrays) {
245247
return result;
246248
}
247249

250+
private static int checkNoOverflow(long result) {
251+
checkArgument(
252+
result == (int) result,
253+
"the total number of elements (%s) in the arrays must fit in an int",
254+
result);
255+
return (int) result;
256+
}
257+
248258
/**
249259
* Returns an array containing the same values as {@code array}, but guaranteed to be of a
250260
* specified minimum length. If {@code array} already has a length of at least {@code minLength},

android/guava/src/com/google/common/primitives/Bytes.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -156,13 +156,15 @@ private static int lastIndexOf(byte[] array, byte target, int start, int end) {
156156
*
157157
* @param arrays zero or more {@code byte} arrays
158158
* @return a single array containing all the values from the source arrays, in order
159+
* @throws IllegalArgumentException if the total number of elements in {@code arrays} does not fit
160+
* in an {@code int}
159161
*/
160162
public static byte[] concat(byte[]... arrays) {
161-
int length = 0;
163+
long length = 0;
162164
for (byte[] array : arrays) {
163165
length += array.length;
164166
}
165-
byte[] result = new byte[length];
167+
byte[] result = new byte[checkNoOverflow(length)];
166168
int pos = 0;
167169
for (byte[] array : arrays) {
168170
System.arraycopy(array, 0, result, pos, array.length);
@@ -171,6 +173,14 @@ public static byte[] concat(byte[]... arrays) {
171173
return result;
172174
}
173175

176+
private static int checkNoOverflow(long result) {
177+
checkArgument(
178+
result == (int) result,
179+
"the total number of elements (%s) in the arrays must fit in an int",
180+
result);
181+
return (int) result;
182+
}
183+
174184
/**
175185
* Returns an array containing the same values as {@code array}, but guaranteed to be of a
176186
* specified minimum length. If {@code array} already has a length of at least {@code minLength},

0 commit comments

Comments
 (0)