Working with code R012

R012 - JNI sandbox policy violation

If you receive the output code R012, this means the method tested performs operations that violate Diffblue Cover’s sandbox policy by using Java Native Interface (JNI). The JNI mechanism allows your Java applications to load native applications and libraries written in C, C++, assembly, etc. Diffblue Cover executes parts of your application in a sandboxed environment, so that its behavior can be analyzed without external effects, and by default this blocks JNI access. If you believe that Diffblue Cover is safe to call your library, then you can add it to the list of JNI libraries that are allowed to be loaded.

Example

For example, consider an application that directly, or indirectly, calls some JNI enabled code that loads some custommagic native library such as this:

public class CustomMagic {
  static {
    // load the OS specific native library file:
    //   libcustommagic.so on Linux
    //   libcustommagic.dylib on macOS
    //   custommagic.dll on Windows
    System.loadLibrary("custommagic");
  }

  public native boolean isMagicEnabled();
}

Using Cover CLI you can use the --allow-jni option to specifically allow JNI libraries with the given name prefix to be loaded. In this case, either --allow-jni=custommagic or --allow-jni=custom would allow the library to be loaded.

Using Cover Plugin, the same is available from Diffblue > Change Settings > Sandboxed Environment > Allowed JNI prefixes:

Cover CLI and Cover Plugin also allow a comma separated list of allowed library name prefixes to be used if multiple JNI libraries are needed.

Java Native Access (JNA)

JNA provides Java programs easy access to native shared libraries without writing any specific JNI wrapper library, making it a popular alternative to using JNI directly. For example, the following loads the standard C library and exposes the cosh() method without a custom JNI wrapper:

import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Platform;

public interface CMath extends Library {
    double cosh(double value);
}

public class JNAExample {
    public static double mut(double param) {
        final CMath instance = Native.load(Platform.isWindows() ? "msvcrt" : "c", CMath.class);
        return instance.cosh(param);
    }
}

In this case, the library name of jna can be used to unblock access to JNA's native library, and the platform specific libraries are then loaded by that so that msvcrt or c don't need to be explicitly allowed.

Bytedeco JavaCPP

Another popular mechanism for easing access to native libraries without maintaining custom JNI wrappers is to use Bytedeco's JavaCPP which provides pre-built binaries of popular open source libraries. For example, the following loads the lz4 library:

import org.bytedeco.lz4.global.lz4;

public class BytedecoLZ4 {
    public static String mut() {
        return lz4.LZ4_VERSION_STRING.getString();
    }
}

In this case each native library used is loaded via System.loadLibrary(String) and so each needs to be explicitly allowed. At a minimum you can expect to allow JNI libraries for JavaCPP, lz4 and its JNI wrapper library jnilz4, but when you create tests again you'll likely see messages referring to e.g. JNI library 'vcruntime140_1' as further dependencies are required. At present the only mechanism to discover the full list of libraries to allow is to start with a minimal list and use the output messages to guide the expansion, likely arriving at something like: jnijavacpp,jnilz4,lz4,api-ms-win-,concrt,msvcp,vcomp,vcruntime

Last updated