Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

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.
  • Loading branch information...
commit f2e45fccfe53ff79ae34f9ca6cae1afa0d153e53 1 parent 6fd9277
@namin namin authored Paul Phillips committed
Showing with 28 additions and 2 deletions.
  1. +28 −2 src/partest/scala/tools/partest/javaagent/ASMTransformer.java
View
30 src/partest/scala/tools/partest/javaagent/ASMTransformer.java
@@ -26,9 +26,35 @@ private boolean shouldTransform(String className) {
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);
Please sign in to comment.
Something went wrong with that request. Please try again.