diff options
author | Nada Amin <namin@alum.mit.edu> | 2012-09-28 01:32:44 +0200 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2013-01-24 10:50:18 -0800 |
commit | f2e45fccfe53ff79ae34f9ca6cae1afa0d153e53 (patch) | |
tree | baa0ccd3754434ce5943b3474a2fda7974f9dcef /src/partest | |
parent | 6fd92774fe1cbee4ec68af359fa57cbd4ad8fc01 (diff) | |
download | scala-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/partest')
-rw-r--r-- | src/partest/scala/tools/partest/javaagent/ASMTransformer.java | 30 |
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); |