Impossible IndexOutOfBound happening on ArrayList.get(). Any clue? - java

I've got a very strange error, that would like to share with you.
I've the following code (simplified):
public ArrayList<String> al = new ArrayList<String>();
public void doSomething() {
int size = al.size();
for(int i=0; i<size; i++) {
if (al.get(i) != null) {
System.out.println(al.get(i));
String sPath = al.get(i);
File fFile = new File(sPath);
fFile.delete(); // Simplified. It has some error checking
}
}
}
I have one error, saw in the production environment:
java.lang.IndexOutOfBoundsException: Index: 1, Size: 0
at java.util.ArrayList.RangeCheck(Unknown Source)
at java.util.ArrayList.get(Unknown Source)
at MYCLASS.soSomething(MICLASS.java:1944)
[...]
Line 1944 is if (al.get(i) != null) {.
What! How can it raise IndexOutOfBound?!
The problem is that the error does not reproduce. I've been able to raise it only once in the dev environment, but trying to reproduce it was not possible (it dit not raise again)... so no way to look for a pattern in the error.
So my only option is simple: read the code and use the brain.
So I browse the code of java.util.ArrayList.get():
public class ArrayList<E> [...]{
public E get(int index) {
RangeCheck(index);
return (E) elementData[index];
}
private void RangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException("Index: "+index+", Size: "+size);
}
}
So it throws the exception because index >= size... How is it possible? The for() sweeps from 0 to size-1... It is impossible! It cannot raise the error!
Wait a second! This code is not thread-safe. Maybe another thread is calling clear() or remove*() on the ArrayList... Studying the code, it is not possible. So I run it, set a breakpoint on line 1944 and watch the threads in that moment, and effectively, the other running threads have nothing to do with this issue.
Any other clue?
Kernnigan & Pike: "Debugging [...]Something impossible occurred, and the only solid information is that it really did occur."

I see the following candidates how this happens:
something in your loop changes the value of i.
something in your loop changes the size of al, possibly something removing elements.
something is replacing your collection with a different collection.
I have seen cases where the loop was constructed in a way so the body gets even executed once in the case of an empty collection. Although that seems unlikely with a for loop as described.
An idea for debugging this: replace the list with your own implementation which logs every access to it, and delegating all the real functionality to a standard implementation.
If needed it can print the stack trace of an freshly created exception in order to identify the place it is called from. It can even throw an exception when it gets accessed from a different thread.

Everyone is suggesting that you're removing elements from the Array. The solution to your problem is to use an Iterator, which allows you to iterate through an entire Collection, but still allow you to modify that Collection.

You probably remove elements from your ArrayList in your for loop, therefore decrementing its original size which is used to exit this loop!

How sure are you that your simplified code exactly replicates the production code? To my mind it's impossible for your simplified code to raise IndexOutOfBoundsException because the list is empty so the for loop should never be processed. Are you modifying the contents of the array list in the loop?

Another possibility is that another thread is modifying the list while your code above is scanning it.
If you want something better than guesses, you need to show us either the relevant production code, or create a simplified version that actually exhibits the same problem when you run it.
Studying the code, it is not possible.
Clearly is is possible, otherwise you wouldn't have observed it.

Thanks everybody for the answers. Most of the suggestions are based on:
A) The loop is modifying al or i.
B) Another thread is modifying al.
c) Another thread is replacing al.
Since I know A is not the case, I'll bet that in some cases another thread is modifying/replacing al. Since I cannot make it fail in a pattern, such thread may be running only in certain situations, such as error conditions. While the code in the loop is pretty simple, the application is not at all small, with abuse of singletons and getter/setters, and it hardens the debugging, so I wouldn't be surprised of it.
That's the same that I suspected (except C, that I had not though of), but you confirmed that this is the only possible cause. Thanks for your help.

Related

Can this code cause an infinite loop while searching for the lowest level cause of an exception?

public static Throwable getCause(#Nonnull Throwable t) {
while ((t instanceof ExecutionException || t instanceof CompletionException) && t.getCause() != null) {
t = t.getCause();
}
return t;
}
Is this code dangerous in a sense that the while loop may never end? Just wondering if someone can cause this to go on forever.
If so, what might be a better way to handle this? I'm thinking maybe adding an upper bound limit.
Is this code dangerous in a sense that the while loop may never end? Just wondering if someone can cause this to go on forever.
In short: Theoretically? Yes. But practically? No. Your code is fine as is.
In long:
Theoretically, yes
Sure, one can create a loop in the causal chain just fine. GetCause() is just a method, and not a final one at that; exceptions are just classes, so one can make their own exception and write public Throwable getCause() { return this; }.
Practically, no
... but just because someone could do that, doesn't mean you should deal with it. Because why do you want to deal with that? Perhaps you're thinking: Well, if some programmer is intentionally trying to blow up the system, I'd want to be robust and not blow up even when they try.
But therein lies a problem: If someone wants to blow up a system, they can. It's nearly trivial to do so. Imagine this:
public class HahaHackingIsSoEasy extends RuntimeException {
#Override public Throwable getCause() {
while (true) ;
}
}
And I throw that. Your code will hang just the same, and if you attempt to detect loops, that's not going to solve the problem. And if you try to stop me from doing this, too, by firing up a separate thread with a timeout and then using Thread.stop() (deprecated, and dangerous) to stop me, I'll just write a loop without a savepoint in which case neither stop() nor using JVMTI to hook in as a debugger and stop that way is going to work.
The conclusion is: There are only 2 reliable ways to stop intentionally malicious code:
The best, by far: Don't run the malicious code in the first place.
The distant second best option: Run it in a highly controlled sandbox environment.
The JVM is un-sandboxable from inside itself (no, the SecurityManager isn't good enough. It has absolutely no way to stop (savepoint-less) infinite loops, for example), so this at the very least involves firing up an entirely separate JVM just to do the job you want to do, so that you can set timeouts and memory limits on it, and possibly an entire new virtual machine. It'll take thousands of times the resources, and is extremely complicated; I rather doubt that's what you intended to do here.
But what about unintentional loops?
The one question that remains is, given that we already wrote off malicious code (not 'we can deal with it', but rather 'if its intentionally malicious you cannot stop them with a loop detector'), what if it's an accident?
Generally, the best way to deal with accidents is to not deal with them at all, not in code: Let them happen; that's why you have operations teams and server maintainers and the like (you're going to have to have those, no matter what happens. Might as well use them). Once it happens, you figure it out, and you fix it.
That leaves just one final corner case which is: What if loops in causal chains have a plausible, desired usecase?
And that's a fair question. Fortunately, the answer is a simple: No, there is no plausible/desired usecase. Loops in causal chains do not happen unless there is a bug (in which case, the answer is: Find it, fix it), or there is malicious case (in which case, the answer is: Do not run it and call your security team).
The loop is following the exception hierarchy down to the root cause.
If that one points back to one of the already visited exceptions there is a bigger fail in the causality. Therefore I'd say it will never go into an infinite loop.
Of course it is possible, you can't prevent someone write something like:
public class ExceptionWithCauseAsItself extends ExecutionException {
#Override
public Throwable getCause() {
return this;
}
}
Following the principle of Defensive Programming, the method should not fall into infinite loop even when someone throw something like ExceptionWithCauseAsItself.
Since your case is not only getting the root cause, probably there is no library to fit what you use. I suggest refer to Apache Common Langs ExceptionUtils.getRootCause to get some idea on how to tackle recursive cause structures.
But as suggested by rzwitserloot, it is just impossible to defence when someone just want to messy you up.
So why does ExceptionUtils.getRootCause mention below?
this method handles recursive cause structures
that might otherwise cause infinite loops
Browsing the history, getThrowableList implementation is using ExceptionUtils.getCause, which tried to get cause by introspect different method, and hence it may cause cyclic cause chain.
This behaviour is already rectified in this commit by calling Throwable#getCause instead. So cyclic cause chain should not happen in general.
More reference related to this topic:
Why is exception.getCause() == exception?.
How can I loop through Exception getCause() to find root cause with detail message
Cycles in chained exceptions

Why does Kotlin use forloop to cause the index to be null? (indices)

This is my code to run in android. Sometime throw ArrayIndexOutOfBoundsException(length=0; index=0)
val list = mutableListOf<String>()
for (i in list.indices){
val item = list[i]
}
But when I use forEachIndexed , The code works well.
Does anyone know the reason?
And Which method is usually preferred?
Thanks for help!
Does anyone know the reason?
Both for (i in list.indices) and forEachIndexed should behave the same way.
Your problem might come from places in the code that you haven't shared. Do you manipulate indices? Do you mutate the list in another thread at the same time?
Which method is usually preferred?
If there is a functional shortcut, it's usually preferred over a loop, because it has less boilerplate. This makes it easier to read (we see the intent more clearly) and also there are less opportunities to make mistakes.
So I would definitely prefer:
list.forEachIndexed { i, item ->
// use item and i in the loop body
}
Over:
for (i in list.indices) {
val item = list[i]
// use item and i in the loop body
}
The only exception is when the loops are in very performance sensitive spots (those are quite rare), because using a for can save an Iterator usage.

Multithreaded library exposing unsafe ArrayList

I am using a shared library in Java that returns ArrayList; as I iterate over it, a ConcurrentModificationException could be thrown and I am looking for 100% (?) guarantee to be safe. I was thinking on something like below and I'd appreciate any input.
The data_list is the ArrayList<> returned from the MT library.
boolean pass = true;
ArrayList<Something> local = new ArrayList<Something>(256);
for (int spin=0; spin<10; ++spin)
{
try {
local.addAll(data_list);
}
catch (java.util.ConcurrentModificationException ce) {
pass = false;
}
finally {
if (pass) break;
pass = true;
}
}
Assuming variable pass is true, how should I operate on local?
There is no safe way to do this. You should not catch ConcurrentModificationException.
The iterators returned by this class's iterator and listIterator methods are fail-fast: if the list is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove or add methods, the iterator will throw a ConcurrentModificationException. Thus, in the face of concurrent modification, the iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic behavior at an undetermined time in the future.
Note that the fail-fast behavior of an iterator cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast iterators throw ConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: the fail-fast behavior of iterators should be used only to detect bugs.
Some collections, like HashMap, even can enter an infinite loop when used this way. Here's an explanation of how it happens.
You should not do this. There is no correct way to do this.
Either you misunderstand how the library works, or you need to switch out your library with one written by a competent developer.
What library are you using?
You don't define exactly what you mean by safe, and don't specify what kind of modifications are being performed to the list, but in many cases it may be acceptable to iterate over it manually by index, i.e.
for (int index = 0; index < data_list.size(); index ++)
local.add(data_list.get(index));
The way I see it, there are four possible kinds of modification, with varying degrees of acceptability:
New items could be appended. This solution should work appropriately for this case, as long as the list does not grow enough to trigger a backing list expansion (and as this should happen with exponentially-reducing frequency, retrying if it occurs should be guaranteed to succeed eventually).
Existing items may be modified. This solution may not present a consistent view of the contents of the list at any given time, but it would be guaranteed to provide a usable list that is representative of items that have been in the list, which may be acceptable depending on your definition of "safe".
Items may be removed. There is a small chance this solution would fail with an IndexOutOfBoundsException, and the same caveat as for items being modified would apply with regards to consistency.
Items may be inserted into the middle of the list. The same caveat as items being modified would apply, and there would also be a danger of getting duplicated values. The problems with backing array expansion from the appending case would also apply.
You've got a bad situation here, but I think your solution is as sound as possible. The new ArrayList should go in the loop so you start fresh after each failure. Actually, the best thing might be to make your "try" line look like:
local = new ArrayList<Something>( data_list );
You don't want your ArrayList to have to expand itself because that will take time when you're trying to grab the data before the list changes. This should set the size, create it, and fill it with the least wasted effort.
You might need to catch things other than ConcurrentModification. You'll probably learn what the hard way. Or just catch Throwable.
If you want to go to extremes, run the code inside the for loop in it's own thread so if it does hang you can kill it and restart it. That's going to take some work.
I think this will work, if you let "spin" get large enough.
I don't have any fundamental changes, but I think that code could be simplified a bit:
ArrayList<Something> local = new ArrayList<Something>(256);
for (int spin=0; spin<10; ++spin)
{
try {
local.addAll(data_list);
break;
}
catch (java.util.ConcurrentModificationException ce) {}
}

ArrayList related debugging question

Please help me explaning this. I can't seem to figure out why this produce a null pointer exception
/* Try to find customer in customer list, if not in list add to list with a
new plan; otherwise add additional plan to customer*/
for(int a = 0; a < dataset.length; a++){
if(customer_name_list.contains(dataset[a][CLIENT_NAME])){
int temp_index = 0;
//NULLPOINTEREXCEPTION OCCURRED ON THE FOLLOWING LINE
while(!customer.get(temp_index).name.equals(dataset[a][CLIENT_NAME])){
temp_index++;
}
customer.get(temp_index).add_plan(dataset[a][PLAN], dataset[a][DETAIL]);
}
else{
Customer temp_customer = new Customer(dataset[a][CLIENT_NAME], dataset[a][PLAN], dataset[a][DETAIL]);
customer.add(temp_customer);
customer_name_list.add(dataset[a][CLIENT_NAME]);
}
}
Thank you for your help
Taking this as the line the exception occurs on:
while(!customer.get(temp_index).name.equals(dataset[a][CLIENT_NAME])){
There's a number of things that could be calling the issue. First off, customer could be null. Second, the results of customer.get(temp_index) could be null. Finally, customer.get(temp_index).name could also be null.
Since we're not working with the full code set here, I suggest you step through and print out the values to each of the above things to work out what one's null (or use a debugger.) That way you'll be able to see exactly what's causing the exception. My guess is that a customer's name may well be set to null which would cause the issue, but it could just as easily be any of the other things I mentioned.
If it isn't found you don't exit the loop, instead you keep going. Try adding a counter or clause so you don't go over.
Either your customer collection, or one of its elements, or the name field of one of its elements is null. I can't really say anything more without seeing what goes in the customer collection.
But a good idea is to print out temp_index in the loop in some kind of log file so you can see how many iterations does it complete before falling over.
Another thing you might find useful is to try to avoid multiple dereferencing operators (.) on the same line, especially if you know little about the data that is being accessed.
You could create a helper method for example:
private String getCustomerName( int index ) {
Customer c = customer.get( index );
return c.name;
}
And use it in your while loop.
Although unrelated, but as others have pointed out, your loop will end in an IndexOutOfBoundsException if no matching elements are found, so you'll have to fix that too.
for (dataA : dataset) {
if (customer_name_list.contains(dataA[CLIENT_NAME])) {
for (c : customer) if (dataA[CLIENT_NAME].equals(c.name)) {
c.add_plan(dataA[PLAN], dataA[DETAIL]);
break;
}
} else {
customer.add(new Customer(dataA[CLIENT_NAME], dataA[PLAN], dataA[DETAIL]));
customer_name_list.add(dataA[CLIENT_NAME]);
}
}
That's what you're doing, only cleaner. I suggest you might want to switch to either a hashing data structure (e.g., a HashMap) or a sorted data structure to improve your lookup and search calls. Then the above would look like
for (data : dataset) {
if ((Customer c = customer_map.get(data[CLIENT_NAME]))!=null) {
c.add_plan(data[PLAN], data[DETAIL]);
} else {
customer_map.put(data[CLIENT_NAME], new Customer(data[CLIENT_NAME], data[PLAN], data[DETAIL]));
}
}
which, in addition to be easier on the brain, is nicer performance-wise. If you need other stuff, like insert-order based iteration, you can use the appropriate map flavor.
As to the NPE, that means an item you've fetched isn't properly initialized - either the item at temp_index is null (and getting name throws the NPE), or name is null and trying to call equals on it throws the NPE. If the index weren't there, you'd be getting an out-of-bounds style exception.

Java Array concept

for(int m=0; m< checkBoxValue.length ; m++)
{
System.out.println("check box in model class"+checkBoxValue[m]+"\n");
}
This loop is to print two values in array. It prints the values But after that it shows array out of bound exception
It seems you're on the wrong track. It's best to set a breaking point on your for loop and debug your code, then go through it step wise. This will reveal where the exception is thrown...
Especially since you say "after that", you might want to review your code after that for loop :-)
Are you sure the Exception is raised here ?
Ohh.. Looks like a mess. The information looks very abstract. You need to be specific, may be you can give more code over here. One possible cause I think of, may be, is Multi-threading.
Only multi-threaded application can do this trick. If so, you better provide synchronization on the origin object of checkBoxValue variable.
Hope that helps....
The code should work fine provided you have done the array initialization correctly.
The posted code should not throw ArrayIndexOutOfBoundsException. Most likely, you are doing something after the loop which accesses an incorrect index of an array.
The only way that the code shown in the question could throw an ArrayIndexOutOfBoundsException is if the toString() method of one of the checkBoxValue[m] objects throws the exception.
Maybe you have overridden the toString() method of the checkBoxValue-class (the array initializer would help identifying this class). Following this theory, the toString() implementation might work fine for the first two elements of the array (they are printed) and may throw an exception for the third element in the array.
This could lead to the error description: This loop is to print two values in array. It prints the values But after that it shows array out of bound exception

Categories