summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNada Amin <namin@alum.mit.edu>2012-09-28 01:32:44 +0200
committerPaul Phillips <paulp@improving.org>2013-01-24 10:50:18 -0800
commitf2e45fccfe53ff79ae34f9ca6cae1afa0d153e53 (patch)
treebaa0ccd3754434ce5943b3474a2fda7974f9dcef /src
parent6fd92774fe1cbee4ec68af359fa57cbd4ad8fc01 (diff)
downloadscala-f2e45fccfe53ff79ae34f9ca6cae1afa0d153e53.tar.gz
scala-f2e45fccfe53ff79ae34f9ca6cae1afa0d153e53.tar.bz2
scala-f2e45fccfe53ff79ae34f9ca6cae1afa0d153e53.zip
Fix class loader issues in instrumentation tests.
The ASM ClassWriter uses a wimpy class loader when computing common superclasses. This could cause a ClassNotFoundException in the transform method (at reader.accept). This exception gets swallowed, resulting in a class that should be instrumented to silently not be. The fix is to override getCommonSuperClass to use the correct class loader. Trivia: This bug was discovered while 'stress-testing' this instrumentation scheme on the Coursera students, to check that they implement one method in terms of another in the assignment.
Diffstat (limited to 'src')
-rw-r--r--src/partest/scala/tools/partest/javaagent/ASMTransformer.java30
1 files changed, 28 insertions, 2 deletions
diff --git a/src/partest/scala/tools/partest/javaagent/ASMTransformer.java b/src/partest/scala/tools/partest/javaagent/ASMTransformer.java
index 494a5a99be..b6bec2f598 100644
--- a/src/partest/scala/tools/partest/javaagent/ASMTransformer.java
+++ b/src/partest/scala/tools/partest/javaagent/ASMTransformer.java
@@ -26,9 +26,35 @@ public class ASMTransformer implements ClassFileTransformer {
className.startsWith("instrumented/"));
}
- public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) {
+ public byte[] transform(final ClassLoader classLoader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) {
if (shouldTransform(className)) {
- ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
+ ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS) {
+ // this is copied verbatim from the superclass,
+ // except that we use the outer class loader
+ @Override protected String getCommonSuperClass(final String type1, final String type2) {
+ Class<?> c, d;
+ try {
+ c = Class.forName(type1.replace('/', '.'), false, classLoader);
+ d = Class.forName(type2.replace('/', '.'), false, classLoader);
+ } catch (Exception e) {
+ throw new RuntimeException(e.toString());
+ }
+ if (c.isAssignableFrom(d)) {
+ return type1;
+ }
+ if (d.isAssignableFrom(c)) {
+ return type2;
+ }
+ if (c.isInterface() || d.isInterface()) {
+ return "java/lang/Object";
+ } else {
+ do {
+ c = c.getSuperclass();
+ } while (!c.isAssignableFrom(d));
+ return c.getName().replace('.', '/');
+ }
+ }
+ };
ProfilerVisitor visitor = new ProfilerVisitor(writer);
ClassReader reader = new ClassReader(classfileBuffer);
reader.accept(visitor, 0);