aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc R. Hoffmann <hoffmann@mountainminds.com>2015-01-19 22:57:25 +0100
committerMarc R. Hoffmann <hoffmann@mountainminds.com>2015-01-19 22:57:25 +0100
commitbc47c020906fde9ce162597cf499fb66e73920fb (patch)
treec7a6b8674f8e3525e499d8a7a00da231b4a33f57
parent0bac737c1bca289341243bfb15e7399170383a21 (diff)
downloadjacoco-bc47c020906fde9ce162597cf499fb66e73920fb.tar.gz
GitHub #272: Exclude dynamically generated classes
Exclude dynamically generated classes from instrumentation for better interoperability with JMockit.
-rw-r--r--org.jacoco.agent.rt.test/src/org/jacoco/agent/rt/internal/CoverageTransformerTest.java75
-rw-r--r--org.jacoco.agent.rt/src/org/jacoco/agent/rt/internal/CoverageTransformer.java34
-rw-r--r--org.jacoco.doc/docroot/doc/changes.html3
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>