Commit 4abce5a3 authored by ebruneton's avatar ebruneton
Browse files

added tests for compute frames with dead code

fixed bug in Handler.remove found with these tests
added class version check in ClassReader
parent 0e4dc092
......@@ -162,6 +162,10 @@ public class ClassReader {
*/
public ClassReader(final byte[] b, final int off, final int len) {
this.b = b;
// checks the class version
if (readShort(6) > Opcodes.V1_7) {
throw new IllegalArgumentException();
}
// parses the constant pool
items = new int[readUnsignedShort(off + 8)];
int n = items.length;
......
......@@ -94,12 +94,12 @@ class Handler {
// [hstart,hend[ fully included in [s,e[, h removed
h = h.next;
} else {
// [hstart,hend[ minus [s,e[ = [hstart,e[
h.end = end;
// [hstart,hend[ minus [s,e[ = [e,hend[
h.start = end;
}
} else if (e >= hend) {
// [hstart,hend[ minus [s,e[ = [s,hend[
h.start = start;
// [hstart,hend[ minus [s,e[ = [hstart,s[
h.end = start;
} else {
// [hstart,hend[ minus [s,e[ = [hstart,s[ + [e,hend[
Handler g = new Handler();
......
......@@ -168,6 +168,7 @@
<ant antfile="${test.conform}/classreader.xml" inheritRefs="true"/>
<ant antfile="${test.conform}/classwriter.xml" inheritRefs="true"/>
<ant antfile="${test.conform}/classwritercomputeframes.xml" inheritRefs="true"/>
<ant antfile="${test.conform}/classwritercomputeframesdeadcode.xml" inheritRefs="true"/>
<ant antfile="${test.conform}/classwritercomputemaxs.xml" inheritRefs="true"/>
<ant antfile="${test.conform}/classwritercopypool.xml" inheritRefs="true"/>
<ant antfile="${test.conform}/classwriterresizeinsns.xml" inheritRefs="true"/>
......
<!--
! ASM: a very small and fast Java bytecode manipulation framework
! Copyright (c) 2000-2005 INRIA, France Telecom
! All rights reserved.
!
! Redistribution and use in source and binary forms, with or without
! modification, are permitted provided that the following conditions
! are met:
! 1. Redistributions of source code must retain the above copyright
! notice, this list of conditions and the following disclaimer.
! 2. Redistributions in binary form must reproduce the above copyright
! notice, this list of conditions and the following disclaimer in the
! documentation and/or other materials provided with the distribution.
! 3. Neither the name of the copyright holders nor the names of its
! contributors may be used to endorse or promote products derived from
! this software without specific prior written permission.
!
! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
! LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
! CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
! SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
! INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
! CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
! ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
! THE POSSIBILITY OF SUCH DAMAGE.
-->
<project name="conform" default="test">
<target name="test.normal" unless="coverage">
<condition property="testclasses" value="${asm.test.class}">
<not><equals arg1="${asm.test.class}" arg2=""/></not>
</condition>
<condition property="testclasses" value="javax">
<equals arg1="${asm.test.class}" arg2=""/>
</condition>
<jar jarfile="${out.test}/agent3.jar">
<fileset dir="${out}/build">
<include name="org/objectweb/asm/**/*.class"/>
</fileset>
<fileset dir="${out}/test">
<include name="org/objectweb/asm/*.class"/>
</fileset>
<manifest>
<attribute name="Premain-Class" value="org.objectweb.asm.ClassWriterComputeFramesDeadCodeTest"/>
</manifest>
</jar>
<junit fork="yes"
printsummary="yes"
errorproperty="test.failed"
failureproperty="test.failed">
<test name="org.objectweb.asm.ClassWriterComputeFramesDeadCodeTest"
fork="yes"
todir="${out.test}/reports"
outfile="TEST-org.objectweb.asm.ClassWriterComputeFramesDeadCodeTest">
</test>
<formatter type="xml"/>
<classpath>
<pathelement location="${out.test}/cases"/>
</classpath>
<jvmarg value="-javaagent:${out.test}/agent3.jar=${asm.test.class}"/>
<jvmarg value="-Dasm.test=${asm.test}"/>
<jvmarg value="-Dasm.test.class=${testclasses}"/>
<jvmarg value="-XX:-FailOverToOldVerifier"/>
<jvmarg value="-Xverify:all"/>
</junit>
</target>
<target name="test.coverage" if="coverage">
<jar jarfile="${out.test}/agent3.jar">
<fileset dir="${out}/instr">
<include name="org/objectweb/asm/**/*.class"/>
</fileset>
<fileset dir="${out}/test">
<include name="org/objectweb/asm/*.class"/>
</fileset>
<manifest>
<attribute name="Premain-Class" value="org.objectweb.asm.ClassWriterComputeFramesDeadCodeTest"/>
</manifest>
</jar>
<junit fork="yes"
printsummary="yes"
errorproperty="test.failed"
failureproperty="test.failed">
<batchtest fork="yes" todir="${out.test}/reports">
<fileset dir="${test}/conform">
<include name="**/ClassWriterComputeFramesDeadCodeTest.java"/>
</fileset>
</batchtest>
<formatter type="xml"/>
<classpath>
<pathelement location="${out.test}/cases"/>
</classpath>
<jvmarg value="-javaagent:${out.test}/agent3.jar=${asm.test.class}"/>
<jvmarg value="-Dasm.test=${asm.test}"/>
<jvmarg value="-Dasm.test.class=${asm.test.class}"/>
<jvmarg value="-Xbootclasspath/p:${cobertura.runtime.path}"/>
<jvmarg value="-XX:-FailOverToOldVerifier"/>
<jvmarg value="-Xverify:all"/>
</junit>
</target>
<target name="test" depends="test.normal,test.coverage"/>
</project>
/***
* ASM tests
* Copyright (c) 2002-2005 France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.objectweb.asm;
import java.io.PrintWriter;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;
import java.util.Random;
import org.objectweb.asm.util.TraceClassVisitor;
import junit.framework.TestSuite;
/**
* ClassWriter tests.
*
* @author Eric Bruneton
*/
public class ClassWriterComputeFramesDeadCodeTest extends AbstractTest {
public static void premain(
final String agentArgs,
final Instrumentation inst)
{
inst.addTransformer(new ClassFileTransformer() {
public byte[] transform(
final ClassLoader loader,
final String className,
final Class<?> classBeingRedefined,
final ProtectionDomain domain,
final byte[] classFileBuffer)
throws IllegalClassFormatException
{
String n = className.replace('/', '.');
if (n.indexOf("javax") == -1) {
return null;
}
if (agentArgs.length() == 0 || n.indexOf(agentArgs) != -1) {
return transformClass(n, classFileBuffer);
} else {
return null;
}
}
});
}
static byte[] transformClass(final String n, final byte[] clazz) {
ClassReader cr = new ClassReader(clazz);
ClassWriter cw = new ComputeClassWriter(ClassWriter.COMPUTE_FRAMES);
cr.accept(new ClassVisitor(Opcodes.ASM4, cw) {
private String className;
@Override
public void visit(
final int version,
final int access,
final String name,
final String signature,
final String superName,
final String[] interfaces)
{
className = name;
super.visit((version & 0xFFFF) < Opcodes.V1_6 ? Opcodes.V1_6 : version,
access,
name,
signature,
superName,
interfaces);
}
@Override
public MethodVisitor visitMethod(
int access,
String name,
String desc,
String signature,
String[] exceptions)
{
int seed = (className + "." + name + desc).hashCode();
return new MethodDeadCodeInserter(seed, super.visitMethod(access,
name,
desc,
signature,
exceptions));
}
}, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG);
byte[] b = cw.toByteArray();
if (n.equals("javax.imageio.ImageIO")) new ClassReader(b).accept(new TraceClassVisitor(new PrintWriter(System.err)), 0);
return b;
}
public static TestSuite suite() throws Exception {
return new ClassWriterComputeFramesDeadCodeTest().getSuite();
}
@Override
public void test() throws Exception {
try {
Class.forName(n, true, getClass().getClassLoader());
} catch (NoClassDefFoundError ncdfe) {
// ignored
} catch (UnsatisfiedLinkError ule) {
// ignored
} catch (ClassFormatError cfe) {
fail(cfe.getMessage());
} catch (VerifyError ve) {
/*String s = n.replace('.', '/') + ".class";
InputStream is = getClass().getClassLoader().getResourceAsStream(s);
ClassReader cr = new ClassReader(is);
byte[] b = transformClass("", cr.b);
StringWriter sw1 = new StringWriter();
StringWriter sw2 = new StringWriter();
sw2.write(ve.toString() + "\n");
ClassVisitor cv1 = new TraceClassVisitor(new PrintWriter(sw1));
ClassVisitor cv2 = new TraceClassVisitor(new PrintWriter(sw2));
cr.accept(cv1, 0);
new ClassReader(b).accept(cv2, 0);
String s1 = sw1.toString();
String s2 = sw2.toString();
assertEquals("different data", s1, s2);*/
fail(ve.getMessage());
}
}
}
class MethodDeadCodeInserter extends MethodVisitor implements Opcodes {
private Random r;
public MethodDeadCodeInserter(int seed, final MethodVisitor mv) {
super(ASM4, mv);
r = new Random(seed);
}
@Override
public void visitInsn(int opcode) {
super.visitInsn(opcode);
insertDeadcode();
}
@Override
public void visitIntInsn(int opcode, int operand) {
super.visitIntInsn(opcode, operand);
insertDeadcode();
}
@Override
public void visitVarInsn(int opcode, int var) {
super.visitVarInsn(opcode, var);
insertDeadcode();
}
@Override
public void visitTypeInsn(int opcode, String type) {
super.visitTypeInsn(opcode, type);
insertDeadcode();
}
@Override
public void visitFieldInsn(
int opcode,
String owner,
String name,
String desc)
{
super.visitFieldInsn(opcode, owner, name, desc);
insertDeadcode();
}
@Override
public void visitMethodInsn(
int opcode,
String owner,
String name,
String desc)
{
super.visitMethodInsn(opcode, owner, name, desc);
insertDeadcode();
}
@Override
public void visitInvokeDynamicInsn(
String name,
String desc,
Handle bsm,
Object... bsmArgs)
{
super.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
insertDeadcode();
}
@Override
public void visitJumpInsn(int opcode, Label label) {
super.visitJumpInsn(opcode, label);
insertDeadcode();
}
@Override
public void visitLdcInsn(Object cst) {
super.visitLdcInsn(cst);
insertDeadcode();
}
@Override
public void visitIincInsn(int var, int increment) {
super.visitIincInsn(var, increment);
insertDeadcode();
}
@Override
public void visitTableSwitchInsn(
int min,
int max,
Label dflt,
Label... labels)
{
super.visitTableSwitchInsn(min, max, dflt, labels);
insertDeadcode();
}
@Override
public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
super.visitLookupSwitchInsn(dflt, keys, labels);
insertDeadcode();
}
@Override
public void visitMultiANewArrayInsn(String desc, int dims) {
super.visitMultiANewArrayInsn(desc, dims);
insertDeadcode();
}
private void insertDeadcode() {
// inserts dead code once every 50 instructions in average
if (r.nextFloat() < 1.0 / 50.0) {
Label end = new Label();
mv.visitJumpInsn(Opcodes.GOTO, end);
mv.visitLdcInsn("DEAD CODE");
mv.visitLabel(end);
}
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment