Monday, 22 May 2017

Configuring BMUnit for the latest JDK9 EA releases

The latest JDK9 EA access releases (jdk-ea+169 and subsequent) now incorporates a restriction that affects use of the BMUnit package (BMUnit integrates Byteman with JUnit and TestNG -- see the 2nd Byteman tutorial for full details).

BMUnit makes it easy to use Byteman in unit and integration tests. It provides @BMRule and @BMScript annotations used to annotate test methods or test classes. These annotations specify the Byteman rules you want injected into your application, test or JDK runtime classes prior to running a test. In order for that to work, BMUnit needs to ensure the Byteman agent is loaded into the current test JVM before running the annotated tests.

As of the Early Access 169 release, JDK9 now includes a check which, by default, stops code using the Agent Load library to hoist an agent into the same JVM. This is provided for users who want to guarantee that code they have deployed in their classpath cannot load an agent in order to escalate its own privilege level (agents like Byteman have very special powers, most notably the ability to rewrite method bytecode).

Of course, that kind of hostage scenario should never be an issue. Users ought to be in full control of what code gets placed in their classpath. So, they should not have to be concerned that a deployment might attempt to use this capability unless it is intended Anyway, irrespective of the rationale for its inclusion, this restriction has been added to JDK9 as a belt and braces security feature for the  super-paranoid^H^H^H^H^H^H -safety conscious user.

Of course, this restriction affects BMUnit because it has to use the Agent Load library to hoist the Byteman agent into the running JVM in order then to be able to inject code changes required for unit tests. Having BMUnit load the agent automatically is much more convenient than configuring the relevant agent options on the Java command line. In particular, BMUNit provides the BMUnitConfig annotation, allowing you to easily configure/reset all the extra arguments that you would otherwise have to squeeze into one long command line string. So, it is much better to be able to remove this restriction and rely on self-hoisting when running your BMUnit tests.

Luckily, it is very simple to disable the restriction. The JVM will allow an agent self-hoist to proceed if a specific system property, jdk.attach.allowAttachSelf, is set to the String value "true". This is a read-only property so it has to be set when the test JVM is started.

If you are using maven then this means that you need to modify the configuration for your maven surefire or failsafe tests to specify the required system property at JVM start setting using the argLine configuration element

<argLine>-Djdk.attach.allowAttachSelf=true</argLine>

n.b. specifying this value as a property element in the properties configuration element will not work.

If you are running from the command line or using some other tool then ensure you pass the property setting on the java command line using the -D command flag

  java -Djdk.attach.allowAttachSelf=true ...

It is probably worth adding this to all your BMUnit test configurations even if you are not yet using jdk9-ea+169 or later releases. You will be prepared for when you do eventually upgrade and setting the property will be harmless since it will ignored by any earlier JDK releases (including on JDK8).