summaryrefslogtreecommitdiff
path: root/src/partest
diff options
context:
space:
mode:
authorNada Amin <namin@alum.mit.edu>2012-09-28 01:32:44 +0200
committerNada Amin <namin@alum.mit.edu>2012-09-28 01:45:25 +0200
commitddcf5cea60245ee8d41e248feabe901df609bcf4 (patch)
tree786c51850a2953a1694cc90d7aed49f23179ddb1 /src/partest
parentae1871bb1c0480e5b055b83f2db08f49ef3c30cf (diff)
downloadscala-ddcf5cea60245ee8d41e248feabe901df609bcf4.tar.gz
scala-ddcf5cea60245ee8d41e248feabe901df609bcf4.tar.bz2
scala-ddcf5cea60245ee8d41e248feabe901df609bcf4.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.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 09cd485d6b..a9a56d124d 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);