-
Bug
-
Resolution: Unresolved
-
P3
-
None
-
16
-
b20
-
generic
-
generic
A DESCRIPTION OF THE PROBLEM :
JavadocTokenizer.ensure has this code:
private void ensure(int need) {
need += size;
int grow = map.length;
while (need > grow) {
grow <<= 1;
}
// Handle overflow.
if (grow < map.length) {
throw new IndexOutOfBoundsException();
} else if (grow != map.length) {
map = Arrays.copyOf(map, grow);
}
}
The purpose of the method is to copy the array `map` into one with a new length that is greater than `size+need`.
For small (<= MAX_INTEGER/2) values of `size+need` this works fine, by doubling the size of `map` until it is large enough.
But consider the case when Integer.MAX_VALUE/2 < map.length < size+need <= Integer.MAX_VALUE. Now when the target size of the map (`grow`) is doubled using `<<=`, it becomes a negative number; the while loop continues to loop. `grow` now takes on various positive or negative numbers depending on the pattern of lower-order bits in the original `map.length`. It is possible one such value will be larger than `size+need`, halting the loop.
But it is also possible that the value of grow will end up being `0` after a sufficient number of shifts. In this case the loop will never exit. In any case, the IndexOutOfBoundsException will never be thrown, despite the comment.
The simple solution for this potential unending loop is to change the while condition and subsequent logic:
private void ensure(int need) {
need += size;
int grow = map.length;
while (need > grow && grow <= Integer.MAX_VALUE/2) {
grow <<= 1;
}
if (grow < need) {
throw new IllegalArgumentException();
} else if (grow > map.length) {
map = Arrays.copyOf(map, grow);
}
}
An alternate change -- with smaller footprint but less clear logic -- is to just write the while condition as
`while (need > grow && grow > 0) `
Admittedly, this situation will arise only when the actual and desired sizes are very large, perhaps prohibitively so. However, since the method purports to handle integer overflow, it ought to do so correctly.
FREQUENCY : rarely
JavadocTokenizer.ensure has this code:
private void ensure(int need) {
need += size;
int grow = map.length;
while (need > grow) {
grow <<= 1;
}
// Handle overflow.
if (grow < map.length) {
throw new IndexOutOfBoundsException();
} else if (grow != map.length) {
map = Arrays.copyOf(map, grow);
}
}
The purpose of the method is to copy the array `map` into one with a new length that is greater than `size+need`.
For small (<= MAX_INTEGER/2) values of `size+need` this works fine, by doubling the size of `map` until it is large enough.
But consider the case when Integer.MAX_VALUE/2 < map.length < size+need <= Integer.MAX_VALUE. Now when the target size of the map (`grow`) is doubled using `<<=`, it becomes a negative number; the while loop continues to loop. `grow` now takes on various positive or negative numbers depending on the pattern of lower-order bits in the original `map.length`. It is possible one such value will be larger than `size+need`, halting the loop.
But it is also possible that the value of grow will end up being `0` after a sufficient number of shifts. In this case the loop will never exit. In any case, the IndexOutOfBoundsException will never be thrown, despite the comment.
The simple solution for this potential unending loop is to change the while condition and subsequent logic:
private void ensure(int need) {
need += size;
int grow = map.length;
while (need > grow && grow <= Integer.MAX_VALUE/2) {
grow <<= 1;
}
if (grow < need) {
throw new IllegalArgumentException();
} else if (grow > map.length) {
map = Arrays.copyOf(map, grow);
}
}
An alternate change -- with smaller footprint but less clear logic -- is to just write the while condition as
`while (need > grow && grow > 0) `
Admittedly, this situation will arise only when the actual and desired sizes are very large, perhaps prohibitively so. However, since the method purports to handle integer overflow, it ought to do so correctly.
FREQUENCY : rarely
- relates to
-
JDK-8254073 Tokenizer improvements (revised)
- Resolved