Hidden exceptions

Posted by user12617285 on Oracle Blogs See other posts from Oracle Blogs or by user12617285
Published on Wed, 22 Jun 2011 05:25:29 -0700 Indexed on 2011/06/22 16:26 UTC
Read the original article Hit count: 438

Filed under:

Occasionally you may find yourself in a Java application environment where exceptions in your code are being caught by the application framework and either silently swallowed or converted into a generic exception. Either way, the potentially useful details of your original exception are inaccessible. Wouldn't it be nice if there was a VM option that showed the stack trace for every exception thrown, whether or not it's caught? In fact, HotSpot includes such an option: -XX:+TraceExceptions. However, this option is only available in a debug build of HotSpot (search globals.hpp for TraceExceptions). And based on a quick skim of the HotSpot source code, this option only prints the exception class and message. A more useful capability would be to have the complete stack trace printed as well as the code location catching the exception. This is what the various TraceException* options in in Maxine do (and more). That said, there is a way to achieve a limited version of the same thing with a stock standard JVM. It involves the use of the -Xbootclasspath/p non-standard option. The trick is to modify the source of java.lang.Exception by inserting the following:

    private static final boolean logging = System.getProperty("TraceExceptions") != null;
    private void log() {
        if (logging && sun.misc.VM.isBooted()) {
            printStackTrace();
        }
    }

Then every constructor simply needs to be modified to call log() just before returning:

    public Exception(String message) {
        super(message);
        log();
    }

    public Exception(String message, Throwable cause) {
        super(message, cause);
        log();
    }

    // etc...

You now need to compile the modified Exception.java source and prepend the resulting class to the boot class path as well as add -DTraceExceptions to your java command line. Here's a console session showing these steps:

% mkdir boot
% javac -d boot Exception.java
% java -DTraceExceptions -Xbootclasspath/p:boot -cp com.oracle.max.vm/bin test.output.HelloWorld
java.util.zip.ZipException: error in opening zip file
        at java.util.zip.ZipFile.open(Native Method)
        at java.util.zip.ZipFile.(ZipFile.java:127)
        at java.util.jar.JarFile.(JarFile.java:135)
        at java.util.jar.JarFile.(JarFile.java:72)
        at sun.misc.URLClassPath$JarLoader.getJarFile(URLClassPath.java:646)
        at sun.misc.URLClassPath$JarLoader.access$600(URLClassPath.java:540)
        at sun.misc.URLClassPath$JarLoader$1.run(URLClassPath.java:607)
        at java.security.AccessController.doPrivileged(Native Method)
        at sun.misc.URLClassPath$JarLoader.ensureOpen(URLClassPath.java:599)
        at sun.misc.URLClassPath$JarLoader.(URLClassPath.java:583)
        at sun.misc.URLClassPath$3.run(URLClassPath.java:333)
        at java.security.AccessController.doPrivileged(Native Method)
        at sun.misc.URLClassPath.getLoader(URLClassPath.java:322)
        at sun.misc.URLClassPath.getLoader(URLClassPath.java:299)
        at sun.misc.URLClassPath.getResource(URLClassPath.java:168)
        at java.net.URLClassLoader$1.run(URLClassLoader.java:194)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
        at sun.misc.Launcher$ExtClassLoader.findClass(Launcher.java:229)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:295)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:247)
java.security.PrivilegedActionException
        at java.security.AccessController.doPrivileged(Native Method)
        at sun.misc.URLClassPath$JarLoader.ensureOpen(URLClassPath.java:599)
        at sun.misc.URLClassPath$JarLoader.(URLClassPath.java:583)
        at sun.misc.URLClassPath$3.run(URLClassPath.java:333)
        at java.security.AccessController.doPrivileged(Native Method)
        at sun.misc.URLClassPath.getLoader(URLClassPath.java:322)
        ...

It's worth pointing out that this is not as useful as direct VM support for tracing exceptions. It has (at least) the following limitations:

  • The trace is shown for every exception, whether it is thrown or not.
  • It only applies to subclasses of java.lang.Exception as there appears to be bootstrap issues when the modification is applied to Throwable.java.
  • It does not show you where the exception was caught.
  • It involves overriding a class in rt.jar, something should never be done in a non-development environment.

© Oracle Blogs or respective owner

Related posts about /Sun