diff options
3 files changed, 101 insertions, 11 deletions
diff --git a/org.jacoco.agent.rt.test/src/org/jacoco/agent/rt/internal/CoverageTransformerTest.java b/org.jacoco.agent.rt.test/src/org/jacoco/agent/rt/internal/CoverageTransformerTest.java index 0f5ef329..68f25fc7 100644 --- a/org.jacoco.agent.rt.test/src/org/jacoco/agent/rt/internal/CoverageTransformerTest.java +++ b/org.jacoco.agent.rt.test/src/org/jacoco/agent/rt/internal/CoverageTransformerTest.java @@ -21,6 +21,9 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.lang.instrument.IllegalClassFormatException; +import java.security.CodeSource; +import java.security.ProtectionDomain; +import java.security.cert.Certificate; import org.jacoco.core.JaCoCo; import org.jacoco.core.runtime.AbstractRuntime; @@ -41,6 +44,8 @@ public class CoverageTransformerTest { private ClassLoader classLoader; + private ProtectionDomain protectionDomain; + private StubRuntime runtime; @Before @@ -48,6 +53,7 @@ public class CoverageTransformerTest { recorder = new ExceptionRecorder(); options = new AgentOptions(); classLoader = getClass().getClassLoader(); + protectionDomain = getClass().getProtectionDomain(); runtime = new StubRuntime(); } @@ -57,6 +63,33 @@ public class CoverageTransformerTest { } @Test + public void testHasSourceLocationNegative1() { + CoverageTransformer t = createTransformer(); + assertFalse(t.hasSourceLocation(null)); + } + + @Test + public void testHasSourceLocationNegative2() { + CoverageTransformer t = createTransformer(); + ProtectionDomain pd = new ProtectionDomain(null, null); + assertFalse(t.hasSourceLocation(pd)); + } + + @Test + public void testHasSourceLocationNegative3() { + CoverageTransformer t = createTransformer(); + CodeSource cs = new CodeSource(null, new Certificate[0]); + ProtectionDomain pd = new ProtectionDomain(cs, null); + assertFalse(t.hasSourceLocation(pd)); + } + + @Test + public void testHasSourceLocationPositive() { + CoverageTransformer t = createTransformer(); + assertTrue(t.hasSourceLocation(protectionDomain)); + } + + @Test public void testFilterAgentClass() { CoverageTransformer t = createTransformer(); assertFalse(t.filter(classLoader, @@ -78,14 +111,34 @@ public class CoverageTransformerTest { } @Test - public void testFilterClassLoaderPositive() { + public void testFilterClassLoaderPositive1() { + options.setInclBootstrapClasses(false); options.setExclClassloader("org.jacoco.agent.SomeWhere$*"); CoverageTransformer t = createTransformer(); assertTrue(t.filter(classLoader, "org/example/Foo")); } @Test - public void testFilterClassLoaderNegative() { + public void testFilterClassLoaderPositive2() { + options.setInclBootstrapClasses(true); + options.setExclClassloader("org.jacoco.agent.SomeWhere$*"); + CoverageTransformer t = createTransformer(); + assertTrue(t.filter(classLoader, "org/example/Foo")); + } + + @Test + public void testFilterClassLoaderNegative1() { + options.setInclBootstrapClasses(false); + options.setExclClassloader("org.jacoco.agent.rt.internal.CoverageTransformerTest$*"); + CoverageTransformer t = createTransformer(); + ClassLoader myClassLoader = new ClassLoader(null) { + }; + assertFalse(t.filter(myClassLoader, "org/example/Foo")); + } + + @Test + public void testFilterClassLoaderNegative2() { + options.setInclBootstrapClasses(true); options.setExclClassloader("org.jacoco.agent.rt.internal.CoverageTransformerTest$*"); CoverageTransformer t = createTransformer(); ClassLoader myClassLoader = new ClassLoader(null) { @@ -129,17 +182,25 @@ public class CoverageTransformerTest { } @Test - public void testTransformFiltered() throws IllegalClassFormatException { + public void testTransformFiltered1() throws IllegalClassFormatException { CoverageTransformer t = createTransformer(); - assertNull(t.transform(null, "org.jacoco.Sample", null, null, + assertNull(t.transform(classLoader, "org.jacoco.Sample", null, null, new byte[0])); } @Test + public void testTransformFiltered2() throws IllegalClassFormatException { + CoverageTransformer t = createTransformer(); + assertNull(t.transform(null, "org.jacoco.Sample", null, + protectionDomain, new byte[0])); + } + + @Test public void testTransformFailure() { CoverageTransformer t = createTransformer(); try { - t.transform(classLoader, "org.jacoco.Sample", null, null, null); + t.transform(classLoader, "org.jacoco.Sample", null, + protectionDomain, null); fail("IllegalClassFormatException expected."); } catch (IllegalClassFormatException e) { assertEquals("Error while instrumenting class org.jacoco.Sample.", @@ -156,8 +217,8 @@ public class CoverageTransformerTest { CoverageTransformer t = createTransformer(); // Just pick any non-system class outside our namespace final Class<?> target = JaCoCo.class; - assertNull(t.transform(classLoader, target.getName(), target, null, - getClassData(target))); + assertNull(t.transform(classLoader, target.getName(), target, + protectionDomain, getClassData(target))); } private CoverageTransformer createTransformer() { diff --git a/org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/CoverageTransformer.java b/org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/CoverageTransformer.java index 3130ec59..b2688890 100644 --- a/org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/CoverageTransformer.java +++ b/org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/CoverageTransformer.java @@ -13,6 +13,7 @@ package org.jacoco.agent.rt.internal; import java.lang.instrument.ClassFileTransformer; import java.lang.instrument.IllegalClassFormatException; +import java.security.CodeSource; import java.security.ProtectionDomain; import org.jacoco.core.instr.Instrumenter; @@ -73,8 +74,13 @@ public class CoverageTransformer implements ClassFileTransformer { final ProtectionDomain protectionDomain, final byte[] classfileBuffer) throws IllegalClassFormatException { + // We do not support class retransformation: if (classBeingRedefined != null) { - // We do not support class retransformation. + return null; + } + + // We exclude dynamically created non-bootstrap classes. + if (loader != null && !hasSourceLocation(protectionDomain)) { return null; } @@ -96,6 +102,25 @@ public class CoverageTransformer implements ClassFileTransformer { } /** + * Checks whether this protection domain is associated with a source + * location. + * + * @param protectionDomain + * protection domain to check (or <code>null</code>) + * @return <code>true</code> if a source location is defined + */ + boolean hasSourceLocation(final ProtectionDomain protectionDomain) { + if (protectionDomain == null) { + return false; + } + final CodeSource codeSource = protectionDomain.getCodeSource(); + if (codeSource == null) { + return false; + } + return codeSource.getLocation() != null; + } + + /** * Checks whether this class should be instrumented. * * @param loader @@ -104,11 +129,12 @@ public class CoverageTransformer implements ClassFileTransformer { * VM name of the class to check * @return <code>true</code> if the class should be instrumented */ - protected boolean filter(final ClassLoader loader, final String classname) { - if (!includeBootstrapClasses) { - if (loader == null) { + boolean filter(final ClassLoader loader, final String classname) { + if (loader == null) { + if (!includeBootstrapClasses) { return false; } + } else { if (exclClassloader.matches(loader.getClass().getName())) { return false; } diff --git a/org.jacoco.doc/docroot/doc/changes.html b/org.jacoco.doc/docroot/doc/changes.html index 0ebae670..758b30c1 100644 --- a/org.jacoco.doc/docroot/doc/changes.html +++ b/org.jacoco.doc/docroot/doc/changes.html @@ -25,6 +25,9 @@ <li>For offline instrumemtation agent configuration supports system properties replacements. Implementation based on pull request of GitHub user 'debugger' (GitHub <a href="https://github.com/jacoco/jacoco/issues/262">#262</a>).</li> + <li>Exclude dynamically generated classes from instrumentation for better + interoperability with JMockit, analysis contributed by Rogério Liesenfeld + (GitHub <a href="https://github.com/jacoco/jacoco/issues/272">#272</a>).</li> </ul> <h3>Fixed Bugs</h3> |