Running Java with AddressSanitizer

OpenJDK and AddressSanitizer are well-known open source projects. OpenJDK sources contain C/C++ code which may be affected by memory corruption issues and memory leaks. Such issues may be detected at runtime with memory checkers like AddressSanitizer. Now it’s going to be easier to use AddressSanitizer for OpenJDK development to check for memory corruptions and leaks.

What is AddressSanitizer?

AddressSanitizer (aka ASan) is a memory error detector for C/C++ which looks for issues like read/write buffer overruns, use-after-free issues and memory leaks. Basically AddressSanitizer instruments C/C++ code with additional checks which allows to detect memory corruptions when the instrumented code is running. This tools is available in GCC 4.8+ and Clang 3.1+ and is supported on multiple platforms including Linux x64 and MacOS x64. The tools can be enabled by passing -fsanitize=address command line options to GCC or Clang compiler and linker. See more details on the official page:

How AddressSanitizer can be used in OpenJDK development?

Java (or OpenJDK to be precise) contains C/C++ code, for example:

  • Java Core Libraries use JNI to access system functions. See for example I/O and networking components.
  • Java Security Libraries use JNI to perform some cryptography operations faster, and access system crypto API with PKCS11 API.

How to use AddressSanitizer with Java

From now OpenJDK can be built with enabled AddressSanitizer. Support for AddressSanitizer has been recently added to OpenJDK configure/make files:

# clone OpenJDK workspace
hg clone http://hg.openjdk.java.net/jdk10/master jdk10
cd jdk10

# configure
# you can also use 'fastdebug' or just --enable-debug
bash configure --with-boot-jdk=/path/to/jdk9 \
--with-debug-level=slowdebug \
--enable-asan

# build
make images
bash-4.2$ ASAN_OPTIONS="handle_segv=0" ./build/linux-x64/images/jdk/bin/java -version
java version "10-internal"
Java(TM) SE Runtime Environment (slowdebug build 10-internal+0-2017-10-30-1135083.asmotrak.jdk10asan)
Java HotSpot(TM) 64-Bit Server VM (slowdebug build 10-internal+0-2017-10-30-1135083.asmotrak.jdk10asan, mixed mode)
ASAN:SIGSEGV
=================================================================
==115049==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x7f2e1c5eb513 sp 0x7f2e381709d8 bp 0x7f2e3df5a5c0 T1)
#0 0x7f2e1c5eb512 (+0x512)
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV ??:0 ??
Thread T1 created by T0 here:
#0 0x7f2e418f18aa in __interceptor_pthread_create /opt/jprt/jprtadm/erik/jdk9-dev/build/devkit/src/gcc-4.9.2/libsanitizer/asan/asan_interceptors.cc:183
#1 0x7f2e41284416 in ContinueInNewThread0 (/scratch/artem/jdk10_asan/build/linux-x64/images/jdk/bin/../lib/jli/libjli.so+0x1c416)
#2 0x7f2e4128006d in ContinueInNewThread (/scratch/artem/jdk10_asan/build/linux-x64/images/jdk/bin/../lib/jli/libjli.so+0x1806d)
#3 0x7f2e4128467a in JVMInit (/scratch/artem/jdk10_asan/build/linux-x64/images/jdk/bin/../lib/jli/libjli.so+0x1c67a)
#4 0x7f2e41275161 in JLI_Launch (/scratch/artem/jdk10_asan/build/linux-x64/images/jdk/bin/../lib/jli/libjli.so+0xd161)
#5 0x401272 in main (/scratch/artem/jdk10_asan/build/linux-x64/images/jdk/bin/java+0x401272)
#6 0x7f2e40cc4b34 in __libc_start_main (/lib64/libc.so.6+0x21b34)
==115049==ABORTING
bash-4.2$ ASAN_OPTIONS="handle_segv=0 detect_leaks=0" ./build/linux-x64/images/jdk/bin/java -version
java version "10-internal"
Java(TM) SE Runtime Environment (slowdebug build 10-internal+0-2017-10-30-1135083.asmotrak.jdk10asan)
Java HotSpot(TM) 64-Bit Server VM (slowdebug build 10-internal+0-2017-10-30-1135083.asmotrak.jdk10asan, mixed mode)

Running tests with AddressSanitizer

If you contribute to OpenJDK, and your patch touches C/C++ code, you may want to run existing tests in OpenJDK workspace with enabled AddressSanitizer. To do that, just run make test. This command is going to run all automated tests. If you'd like to run only subset of existing tests you can use something like make run-test TEST=jdk_lang. Or, just run tests with Jtreg command. Refer to Testing OpenJDK for details.

Known issues

Code which create new processes with ProcessBuilder class may fail with a message like the following:

Address 0x7fceacab7280 is located in stack of thread T24 (MainThread)==10175==AddressSanitizer CHECK failed: ../../../../src/libsanitizer/asan/asan_thread.cc:231 "((ptr[0] == kCurrentStackFrameMagic)) != (0)" (0x0, 0x0)

Limitations

Even if AddressSanitizer is a well-known good tool, it’s not a silver bullet. First, you still need use your brain to avoid common issues in C/C++ code like buffer overflows, use-after-free and other issues. And then, you may want to be armed with a good set of tools like runtime memory checkers and static code analyzers.

Next steps

Greg Steuck suggested that would be cool if Java runtime compilers inserted AddressSanitizer checks to generated code. I am not an expert in runtime compilation. and talked to Igor Ignatyev from Hotspot Group. He said it might be hard to do that in C1/C2 compilers, but it might be easier to introduce such checks with Graal compiler.

Java and AddressSanitizer
Java and AddressSanitizer

I write about Java, security, electronics and DIY

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store