Reputation: 8358
I got the following stacktrace when trying to print a stacktrace to the console:
java.lang.StackOverflowError
at java.io.FileOutputStream.writeBytes(Native Method)
at java.io.FileOutputStream.write(Unknown Source)
at java.io.BufferedOutputStream.flushBuffer(Unknown Source)
at java.io.BufferedOutputStream.write(Unknown Source)
at java.io.PrintStream.write(Unknown Source)
at sun.nio.cs.StreamEncoder.writeBytes(Unknown Source)
at sun.nio.cs.StreamEncoder.implFlushBuffer(Unknown Source)
at sun.nio.cs.StreamEncoder.flushBuffer(Unknown Source)
at java.io.OutputStreamWriter.flushBuffer(Unknown Source)
at java.io.PrintStream.write(Unknown Source)
at java.io.PrintStream.print(Unknown Source)
at java.io.PrintStream.println(Unknown Source)
at java.lang.Throwable.printStackTrace(Throwable.java:461)
at java.lang.Throwable.printStackTrace(Throwable.java:451)
...
Has anyone seen something like this before? What could have caused this? (Unfortunately I received the stacktrace from a user, so I can't say whether the JVM configuration was changed in any way.)
The method call that caused this was a simple catch-and-print, like this:
try {
...
File canFile = new File(path).getCanonicalFile();
...
} catch (IOException e) {
e.printStackTrace();
}
Although I can't publish any more code, I can guarantee that the IOException was thrown by the getCanonicalFile call, because that's the only call within the try-clause that can throw an IOException.
Upvotes: 4
Views: 2338
Reputation: 64969
If you initialise two Throwable
s to be mutual causes of one another, you'll get a StackOverflowError
if you attempt to print the stacktrace of one of them.
The following class demonstrates this behaviour:
public class StackTraceStackOverflow {
public static void main(String[] args) {
Error e = new Error();
Error f = new Error(e);
e.initCause(f);
e.printStackTrace();
}
}
We need two Throwable
s in this example because it's not possible to set a Throwable
to be its own cause. If you try to do this, you'll get an IllegalArgumentException
.
Alternatively, you can also get a stack-overflow error if you have a ridiculously long chain of cause exceptions. On my machine at least (Kubuntu Natty, x64, OpenJDK 1.6), I found that a chain of 8000 cause exceptions is enough to generate a StackOverflowError
, as the following class demonstrates:
public class StackTraceStackOverflow2 {
public static void main(String[] args) {
Error e = null;
for (int i = 0; i < 8000; ++i) {
e = new Error(null, e);
}
e.printStackTrace(System.out);
}
}
You may have to adjust the number 8000 on other systems.
Note that I used the two-argument Error
constructor in this second example. If I used the constructor that takes a single Throwable
parameter, the exception message is populated using the cause exception. This message gets longer and longer as the chain of exceptions grows, and as a result you are more likely to end up with an OutOfMemoryError
than a StackOverflowError
.
Upvotes: 6