murkaje / npe-blame-agent

JVMTI Agent to display detailed cause message in otherwise empty NullPointerException
9 stars 0 forks source link

Build Status

What is this?

A simple agent for the JVM that will provide hopefully helpful messages to otherwise empty NullPointerExceptions

For example the following java snippet

String myVar = null;
myVar.toLowerCase();

The default java exception will not have a message, but with the help of this agent the following exception message is produced

java.lang.NullPointerException: Invoking java.lang.String#toLowerCase on null local variable myVar:java.lang.String
    at ee.murkaje.GeneratedBase.generateNpeDebug(GeneratedBase.java:30)
    at ee.murkaje.TestNullPtr.lambda$testLocalVariableWithDebug$1(TestNullPtr.java:63)
    at org.junit.jupiter.api.AssertThrows.assertThrows(AssertThrows.java:30)
    at org.junit.jupiter.api.Assertions.assertThrows(Assertions.java:1089)
    at ee.murkaje.TestNullPtr.testLocalVariableWithDebug(TestNullPtr.java:63)

Running

Add agent to JVM options and run your application, it's that simple!
Linux: -agentpath:/path/to/npe-blame-agent/target/libnpeblame.so
Windows: -agentpath:/path/to/npe-blame-agent/target/npeblame.dll
MacOS: -agentpath:/path/to/npe-blame-agent/target/libnpeblame.dylib

Building

Make sure you have a c++17 compliant compiler installed
Ensure JAVA_HOME environment variable points to a valid JDK installation

mkdir build
cd build
CXX=clang++ cmake ..
make

-> target/libnpeblame.so | target/libnpeblame.dylib | target/npeblame.dll

⚠ On linux/MacOS avoid GCC(,8.3] due to a compiler bug, use GCC 9.x or Clang. See example: https://godbolt.org/z/McehAm

Testing

Integration tests available in https://github.com/murkaje/npe-blame-test

☞ Checking the test assertion messages gives a nice overview of code examples and resulting exception messages.

Why is it useful?

While the line number will usually be more than enough to track down where the null originated, method chaining on a single line will already be confusing and needs extra debugging.

The situation is far worse for classes generated or instrumented using bytecode manipulation tools like ASM and Javassist. In such cases there will be no line number information and developers are left guessing.

Some scenarios such as reporting exceptions via BugSnag or similar tools will especially benefit from this agent as the runtime generated bytecode or other details on where the NPE originated is not included in a report, but is vital to debug the error cause. The detailed exception message will hopefully provide a good enough alternative, without having to scour logs for library versions or other magic to match the class names and lines to specific code using only minimal information from the target system.