I’m occasionally getting a very strange exception:
04-18 18:08:08.121: E/AndroidRuntime(3031): Uncaught handler: thread main exiting due to uncaught exception
04-18 18:08:08.141: E/AndroidRuntime(3031): java.lang.ArrayIndexOutOfBoundsException
04-18 18:08:08.141: E/AndroidRuntime(3031): at java.util.ArrayList.addAll(ArrayList.java:257)
04-18 18:08:08.141: E/AndroidRuntime(3031): at com.zigzagworld.text.formatter.FormatManager.formatIfNeeded(FormatManager.java:185)
etc.
This is happening on a 1.6 emulator. The line in my code that calls addAll is:
mTasksAbove.addAll(schedule.above);
The only thing I can imagine is some sort of concurrent access to mTasksAbove. However, I’ve been very careful to ensure that all accesses are synchronized on the same object. The only other thing I thought of was if schedule.above were modified during execution of addAll, but I believe that would generate a ConcurrentModificationException (plus, I don’t think my code does that). Does anyone know of anything else I should be looking for?
EDIT
Based on Raykud’s answer, I did a little digging and found the exact bug. In the Android 1.6 sources, the addAll method calls an internal method, growAtEnd that is buggy. Here’s the source itself:
private void growAtEnd(int required) {
int size = size();
if (firstIndex >= required - (array.length - lastIndex)) {
int newLast = lastIndex - firstIndex;
if (size > 0) {
System.arraycopy(array, firstIndex, array, 0, size);
int start = newLast < firstIndex ? firstIndex : newLast;
Arrays.fill(array, start, array.length, null);
}
firstIndex = 0;
lastIndex = newLast;
} else {
int increment = size / 2;
if (required > increment) {
increment = required;
}
if (increment < 12) {
increment = 12;
}
E[] newArray = newElementArray(size + increment);
if (size > 0) {
System.arraycopy(array, firstIndex, newArray, 0, size);
/********************************************************\
* BUG! The next 2 lines of code should be outside the if *
\********************************************************/
firstIndex = 0;
lastIndex = size;
}
array = newArray;
}
}
The bug rears its ugly head when the list had been previously populated and then emptied, leaving size == 0 and firstIndex == lastIndex > 0 and you try to add a collection large enough that it doesn’t fit between lastIndex and the current array size.
The bug is gone as of 2.2, when the addAll method was rewritten and growAtEnd disappeared from the class.
Thanks, Raykud, for the pointer!
as of 1.5 the method addAll in arraylist was buggy, it was supposed to get fixed in a future realease, however I’m not sure in wich one.
To work around this you could create an Iterator for your collection and adding the elements one by one.
Here is a little code to help:
and the IndexOutOfBounds exception is caused because you are trying to retrieve an item from a position where there is nothing.