Skip to content

Do not instrument classes loaded by platform class loader by default #2152

Description

@Godin

For the following src/Example.java

class Example {
    public static void main(String[] args) {
        new java.sql.SQLException();
        System.our.println("OK");
    }
}

compiled by JDK 8

mkdir classes
javac src/Example.java -d classes

using JDK 8 execution of

rm jacoco.exec
java -javaagent:jacoco-0.8.14/lib/jacocoagent.jar -cp classes Example
java -jar jacoco-0.8.14/lib/jacococli.jar execinfo jacoco.exec | grep SQLException | wc -l

produces

OK
0

whereas execution using JDK 9 and above up to JDK 26 produces

OK
1

To instrument java.sql.SQLException prior to JDK 9 was required to use inclbootstrapclasses=true,
ie using JDK 8 execution of

rm jacoco.exec
java -javaagent:jacoco-0.8.14/lib/jacocoagent.jar=inclbootstrapclasses=true -cp classes Example
java -jar jacoco-0.8.14/lib/jacococli.jar execinfo jacoco.exec | grep SQLException | wc -l

produces

OK
1

This difference comes from introduction of platform class loader by https://openjdk.org/jeps/261 in JDK 9.

By not instrumenting such classes by default
(eg by requiring for their instrumentation as it was before
inclbootstrapclasses to be true instead of default false)
we can get rid of exceptions when agent does not support bytecode version of classes in JDK EA
while supports bytecode version of classes whose coverage should be measured,
in which case such exceptions can already be safely ignored
(see #2151, #1742 (comment) and #1631 (comment)) - ie execution using JDK 27 EA produces

java.lang.instrument.IllegalClassFormatException: Error while instrumenting java/sql/SQLException with JaCoCo 0.8.14.202510111229/2eb2483.
	at org.jacoco.agent.rt.internal_29a6edd.CoverageTransformer.transform(CoverageTransformer.java:94)
	at java.instrument/java.lang.instrument.ClassFileTransformer.transform(ClassFileTransformer.java:257)
	at java.instrument/sun.instrument.TransformerManager.transform(TransformerManager.java:188)
	at java.instrument/sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:594)
	at java.base/java.lang.ClassLoader.defineClass2(Native Method)
	at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1080)
	at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1064)
	at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:177)
	at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:735)
	at java.base/jdk.internal.loader.BuiltinClassLoader.findClassInModuleOrNull(BuiltinClassLoader.java:678)
	at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:604)
	at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:639)
	at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:608)
	at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:578)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:502)
	at Example.main(Example.java:3)
Caused by: java.io.IOException: Error while instrumenting java/sql/SQLException with JaCoCo 0.8.14.202510111229/2eb2483.
	at org.jacoco.agent.rt.internal_29a6edd.core.instr.Instrumenter.instrumentError(Instrumenter.java:161)
	at org.jacoco.agent.rt.internal_29a6edd.core.instr.Instrumenter.instrument(Instrumenter.java:111)
	at org.jacoco.agent.rt.internal_29a6edd.CoverageTransformer.transform(CoverageTransformer.java:92)
	... 15 more
Caused by: java.lang.IllegalArgumentException: Unsupported class file major version 71
	at org.jacoco.agent.rt.internal_29a6edd.asm.ClassReader.<init>(ClassReader.java:200)
	at org.jacoco.agent.rt.internal_29a6edd.asm.ClassReader.<init>(ClassReader.java:180)
	at org.jacoco.agent.rt.internal_29a6edd.asm.ClassReader.<init>(ClassReader.java:166)
	at org.jacoco.agent.rt.internal_29a6edd.core.internal.instr.InstrSupport.classReaderFor(InstrSupport.java:280)
	at org.jacoco.agent.rt.internal_29a6edd.core.instr.Instrumenter.instrument(Instrumenter.java:77)
	at org.jacoco.agent.rt.internal_29a6edd.core.instr.Instrumenter.instrument(Instrumenter.java:109)
	... 16 more
...
OK
0

while execution of

java -jar jacoco-0.8.14/lib/jacococli.jar report jacoco.exec \
    --classfiles classes \
    --sourcefiles src \
    --html report

still produces correct code coverage report for Example.java

And similarly for JaCoCo 0.8.15 and JDK 28 EA.


Should also be noted that such classes can already be excluded from instrumentation using

'excludes=java/sql/*'

or

'exclclassloader=jdk.internal.loader.ClassLoaders$PlatformClassLoader'

Metadata

Metadata

Assignees

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions