FULL PRODUCT VERSION :
java version "1.6.0"
Java (TM) SE Runtime Environment (build 1.6.0-b105)
Java HotSpot(TM) Client VM (build 1.6.0-b105, mixed mode, sharing)
ADDITIONAL OS VERSION INFORMATION :
Windows
A DESCRIPTION OF THE PROBLEM :
Throwable.initCause(Throwable) cannot prevent circular exception-chaining from occuring.
The specification for Throwable.initCause(Throwable) says that a Throwable can't be it's own cause. However the implementation only checks if the direct cause is itself, it does not perform a deep checking.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
See the attached code to reproduce the problem. Just compile and run.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The line "t2.initCause(t1);" should throw IllegalArgumentException.
ACTUAL -
printStackTrace loops forever.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
/* This simple code reproduce the bug. It makes Throwable.printStackTrace() looping forever. */
public class ThrowableTrouble {
public static void main(String[] args) {
Throwable t1 = new Throwable();
Throwable t2 = new Throwable();
t1.initCause(t2);
t2.initCause(t1);
try {
throw t1;
} catch (Throwable t) {
t.printStackTrace();
}
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
The workaround is simple. The programmer should be careful to not do something erroneous like showed in the example code.
However, it is very simple and straight-forward to patch Throwable.initCause(Throwable):
public synchronized Throwable initCause(Throwable cause) {
Throwable deepCause = cause;
if (this.cause != this)
throw new IllegalStateException("Can't overwrite cause");
while (deepCause != null) {
if (deepCause == this)
throw new IllegalArgumentException("Self-causation not permitted");
deepCause = deepCause.getCause();
}
this.cause = cause;
return this;
}