Commit 8783234d authored by Remi Forax's avatar Remi Forax
Browse files

Merge branch 'master' of git@gitlab.ow2.org:asm/asm.git into

ASM7_NESTMATES

Conflicts:
	build.gradle
parents 3c46b64f 84c9bb83
......@@ -27,8 +27,10 @@
// THE POSSIBILITY OF SUCH DAMAGE.
package org.objectweb.asm.tree.analysis;
import static java.time.Duration.ofSeconds;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively;
import java.io.FileInputStream;
import java.io.IOException;
......@@ -37,6 +39,7 @@ import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.test.AsmTest;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.MethodNode;
......@@ -72,6 +75,30 @@ public class BasicInterpreterTest extends AsmTest {
assertEquals("RIR..... ", analyzer.getFrames()[104].toString());
}
/**
* Tests that the analyzer does not loop infinitely, even if the {@link Interpreter#merge} method
* does not follow its required contract (namely that if the merge result is equal to the first
* argument, the first argument should be returned - see #316326).
*
* @throws AnalyzerException
*/
@Test
public void testAnalyzeWithBadInterpreter() throws AnalyzerException {
ClassNode classNode = new ClassNode();
new ClassReader(PrecompiledClass.JDK8_ALL_FRAMES.getBytes()).accept(classNode, 0);
for (MethodNode methodNode : classNode.methods) {
Analyzer<BasicValue> analyzer =
new Analyzer<BasicValue>(
new BasicInterpreter(Opcodes.ASM6) {
@Override
public BasicValue merge(final BasicValue value1, final BasicValue value2) {
return new BasicValue(super.merge(value1, value2).getType());
}
});
assertTimeoutPreemptively(ofSeconds(1), () -> analyzer.analyze("Test", methodNode));
}
}
/**
* Tests that the precompiled classes can be successfully analyzed with a BasicInterpreter.
*
......
......@@ -97,7 +97,7 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes
@Override
public void visitCode() {
mv.visitCode();
super.visitCode();
if (constructor) {
stackFrame = new ArrayList<Object>();
branches = new HashMap<Label, List<Object>>();
......@@ -109,7 +109,7 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes
@Override
public void visitLabel(final Label label) {
mv.visitLabel(label);
super.visitLabel(label);
if (constructor && branches != null) {
List<Object> frame = branches.get(label);
if (frame != null) {
......@@ -298,7 +298,7 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes
break;
}
}
mv.visitInsn(opcode);
super.visitInsn(opcode);
}
@Override
......@@ -335,7 +335,7 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes
@Override
public void visitFieldInsn(
final int opcode, final String owner, final String name, final String desc) {
mv.visitFieldInsn(opcode, owner, name, desc);
super.visitFieldInsn(opcode, owner, name, desc);
if (constructor) {
char c = desc.charAt(0);
boolean longOrDouble = c == 'J' || c == 'D';
......@@ -370,7 +370,7 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes
@Override
public void visitIntInsn(final int opcode, final int operand) {
mv.visitIntInsn(opcode, operand);
super.visitIntInsn(opcode, operand);
if (constructor && opcode != NEWARRAY) {
pushValue(OTHER);
}
......@@ -378,7 +378,7 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes
@Override
public void visitLdcInsn(final Object cst) {
mv.visitLdcInsn(cst);
super.visitLdcInsn(cst);
if (constructor) {
pushValue(OTHER);
if (cst instanceof Double || cst instanceof Long) {
......@@ -389,7 +389,7 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes
@Override
public void visitMultiANewArrayInsn(final String desc, final int dims) {
mv.visitMultiANewArrayInsn(desc, dims);
super.visitMultiANewArrayInsn(desc, dims);
if (constructor) {
for (int i = 0; i < dims; i++) {
popValue();
......@@ -400,7 +400,7 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes
@Override
public void visitTypeInsn(final int opcode, final String type) {
mv.visitTypeInsn(opcode, type);
super.visitTypeInsn(opcode, type);
// ANEWARRAY, CHECKCAST or INSTANCEOF don't change stack
if (constructor && opcode == NEW) {
pushValue(OTHER);
......@@ -474,7 +474,7 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes
@Override
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) {
mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
super.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
if (constructor) {
Type[] types = Type.getArgumentTypes(desc);
for (int i = 0; i < types.length; i++) {
......@@ -496,7 +496,7 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes
@Override
public void visitJumpInsn(final int opcode, final Label label) {
mv.visitJumpInsn(opcode, label);
super.visitJumpInsn(opcode, label);
if (constructor) {
switch (opcode) {
case IFEQ:
......@@ -530,7 +530,7 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes
@Override
public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) {
mv.visitLookupSwitchInsn(dflt, keys, labels);
super.visitLookupSwitchInsn(dflt, keys, labels);
if (constructor) {
popValue();
addBranches(dflt, labels);
......@@ -540,7 +540,7 @@ public abstract class AdviceAdapter extends GeneratorAdapter implements Opcodes
@Override
public void visitTableSwitchInsn(
final int min, final int max, final Label dflt, final Label... labels) {
mv.visitTableSwitchInsn(min, max, dflt, labels);
super.visitTableSwitchInsn(min, max, dflt, labels);
if (constructor) {
popValue();
addBranches(dflt, labels);
......
......@@ -197,9 +197,7 @@ public class AnalyzerAdapter extends MethodVisitor {
"ClassReader.accept() should be called with EXPAND_FRAMES flag");
}
if (mv != null) {
mv.visitFrame(type, nLocal, local, nStack, stack);
}
super.visitFrame(type, nLocal, local, nStack, stack);
if (this.locals != null) {
this.locals.clear();
......@@ -210,6 +208,7 @@ public class AnalyzerAdapter extends MethodVisitor {
}
visitFrameTypes(nLocal, local, this.locals);
visitFrameTypes(nStack, stack, this.stack);
maxLocals = Math.max(maxLocals, this.locals.size());
maxStack = Math.max(maxStack, this.stack.size());
}
......@@ -226,9 +225,7 @@ public class AnalyzerAdapter extends MethodVisitor {
@Override
public void visitInsn(final int opcode) {
if (mv != null) {
mv.visitInsn(opcode);
}
super.visitInsn(opcode);
execute(opcode, 0, null);
if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) || opcode == Opcodes.ATHROW) {
this.locals = null;
......@@ -238,17 +235,19 @@ public class AnalyzerAdapter extends MethodVisitor {
@Override
public void visitIntInsn(final int opcode, final int operand) {
if (mv != null) {
mv.visitIntInsn(opcode, operand);
}
super.visitIntInsn(opcode, operand);
execute(opcode, operand, null);
}
@Override
public void visitVarInsn(final int opcode, final int var) {
if (mv != null) {
mv.visitVarInsn(opcode, var);
}
super.visitVarInsn(opcode, var);
boolean isLongOrDouble =
opcode == Opcodes.LLOAD
|| opcode == Opcodes.DLOAD
|| opcode == Opcodes.LSTORE
|| opcode == Opcodes.DSTORE;
maxLocals = Math.max(maxLocals, var + (isLongOrDouble ? 2 : 1));
execute(opcode, var, null);
}
......@@ -267,18 +266,14 @@ public class AnalyzerAdapter extends MethodVisitor {
uninitializedTypes.put(labels.get(i), type);
}
}
if (mv != null) {
mv.visitTypeInsn(opcode, type);
}
super.visitTypeInsn(opcode, type);
execute(opcode, 0, type);
}
@Override
public void visitFieldInsn(
final int opcode, final String owner, final String name, final String desc) {
if (mv != null) {
mv.visitFieldInsn(opcode, owner, name, desc);
}
super.visitFieldInsn(opcode, owner, name, desc);
execute(opcode, 0, desc);
}
......@@ -344,9 +339,7 @@ public class AnalyzerAdapter extends MethodVisitor {
@Override
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) {
if (mv != null) {
mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
}
super.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
if (this.locals == null) {
labels = null;
return;
......@@ -358,9 +351,7 @@ public class AnalyzerAdapter extends MethodVisitor {
@Override
public void visitJumpInsn(final int opcode, final Label label) {
if (mv != null) {
mv.visitJumpInsn(opcode, label);
}
super.visitJumpInsn(opcode, label);
execute(opcode, 0, null);
if (opcode == Opcodes.GOTO) {
this.locals = null;
......@@ -370,9 +361,7 @@ public class AnalyzerAdapter extends MethodVisitor {
@Override
public void visitLabel(final Label label) {
if (mv != null) {
mv.visitLabel(label);
}
super.visitLabel(label);
if (labels == null) {
labels = new ArrayList<Label>(3);
}
......@@ -381,9 +370,7 @@ public class AnalyzerAdapter extends MethodVisitor {
@Override
public void visitLdcInsn(final Object cst) {
if (mv != null) {
mv.visitLdcInsn(cst);
}
super.visitLdcInsn(cst);
if (this.locals == null) {
labels = null;
return;
......@@ -419,18 +406,15 @@ public class AnalyzerAdapter extends MethodVisitor {
@Override
public void visitIincInsn(final int var, final int increment) {
if (mv != null) {
mv.visitIincInsn(var, increment);
}
super.visitIincInsn(var, increment);
maxLocals = Math.max(maxLocals, var + 1);
execute(Opcodes.IINC, var, null);
}
@Override
public void visitTableSwitchInsn(
final int min, final int max, final Label dflt, final Label... labels) {
if (mv != null) {
mv.visitTableSwitchInsn(min, max, dflt, labels);
}
super.visitTableSwitchInsn(min, max, dflt, labels);
execute(Opcodes.TABLESWITCH, 0, null);
this.locals = null;
this.stack = null;
......@@ -438,9 +422,7 @@ public class AnalyzerAdapter extends MethodVisitor {
@Override
public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) {
if (mv != null) {
mv.visitLookupSwitchInsn(dflt, keys, labels);
}
super.visitLookupSwitchInsn(dflt, keys, labels);
execute(Opcodes.LOOKUPSWITCH, 0, null);
this.locals = null;
this.stack = null;
......@@ -448,12 +430,18 @@ public class AnalyzerAdapter extends MethodVisitor {
@Override
public void visitMultiANewArrayInsn(final String desc, final int dims) {
if (mv != null) {
mv.visitMultiANewArrayInsn(desc, dims);
}
super.visitMultiANewArrayInsn(desc, dims);
execute(Opcodes.MULTIANEWARRAY, dims, desc);
}
@Override
public void visitLocalVariable(
String name, String descriptor, String signature, Label start, Label end, int index) {
char firstDescChar = descriptor.charAt(0);
maxLocals = Math.max(maxLocals, index + (firstDescChar == 'J' || firstDescChar == 'D' ? 2 : 1));
super.visitLocalVariable(name, descriptor, signature, start, end, index);
}
@Override
public void visitMaxs(final int maxStack, final int maxLocals) {
if (mv != null) {
......
......@@ -63,9 +63,7 @@ public class CodeSizeEvaluator extends MethodVisitor implements Opcodes {
public void visitInsn(final int opcode) {
minSize += 1;
maxSize += 1;
if (mv != null) {
mv.visitInsn(opcode);
}
super.visitInsn(opcode);
}
@Override
......@@ -77,9 +75,7 @@ public class CodeSizeEvaluator extends MethodVisitor implements Opcodes {
minSize += 2;
maxSize += 2;
}
if (mv != null) {
mv.visitIntInsn(opcode, operand);
}
super.visitIntInsn(opcode, operand);
}
@Override
......@@ -94,18 +90,14 @@ public class CodeSizeEvaluator extends MethodVisitor implements Opcodes {
minSize += 2;
maxSize += 2;
}
if (mv != null) {
mv.visitVarInsn(opcode, var);
}
super.visitVarInsn(opcode, var);
}
@Override
public void visitTypeInsn(final int opcode, final String type) {
minSize += 3;
maxSize += 3;
if (mv != null) {
mv.visitTypeInsn(opcode, type);
}
super.visitTypeInsn(opcode, type);
}
@Override
......@@ -113,9 +105,7 @@ public class CodeSizeEvaluator extends MethodVisitor implements Opcodes {
final int opcode, final String owner, final String name, final String desc) {
minSize += 3;
maxSize += 3;
if (mv != null) {
mv.visitFieldInsn(opcode, owner, name, desc);
}
super.visitFieldInsn(opcode, owner, name, desc);
}
@Deprecated
......@@ -161,9 +151,7 @@ public class CodeSizeEvaluator extends MethodVisitor implements Opcodes {
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) {
minSize += 5;
maxSize += 5;
if (mv != null) {
mv.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
}
super.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
}
@Override
......@@ -174,9 +162,7 @@ public class CodeSizeEvaluator extends MethodVisitor implements Opcodes {
} else {
maxSize += 8;
}
if (mv != null) {
mv.visitJumpInsn(opcode, label);
}
super.visitJumpInsn(opcode, label);
}
@Override
......@@ -188,9 +174,7 @@ public class CodeSizeEvaluator extends MethodVisitor implements Opcodes {
minSize += 2;
maxSize += 3;
}
if (mv != null) {
mv.visitLdcInsn(cst);
}
super.visitLdcInsn(cst);
}
@Override
......@@ -202,9 +186,7 @@ public class CodeSizeEvaluator extends MethodVisitor implements Opcodes {
minSize += 3;
maxSize += 3;
}
if (mv != null) {
mv.visitIincInsn(var, increment);
}
super.visitIincInsn(var, increment);
}
@Override
......@@ -212,26 +194,20 @@ public class CodeSizeEvaluator extends MethodVisitor implements Opcodes {
final int min, final int max, final Label dflt, final Label... labels) {
minSize += 13 + labels.length * 4;
maxSize += 16 + labels.length * 4;
if (mv != null) {
mv.visitTableSwitchInsn(min, max, dflt, labels);
}
super.visitTableSwitchInsn(min, max, dflt, labels);
}
@Override
public void visitLookupSwitchInsn(final Label dflt, final int[] keys, final Label[] labels) {
minSize += 9 + keys.length * 8;
maxSize += 12 + keys.length * 8;
if (mv != null) {
mv.visitLookupSwitchInsn(dflt, keys, labels);
}
super.visitLookupSwitchInsn(dflt, keys, labels);
}
@Override
public void visitMultiANewArrayInsn(final String desc, final int dims) {
minSize += 4;
maxSize += 4;
if (mv != null) {
mv.visitMultiANewArrayInsn(desc, dims);
}
super.visitMultiANewArrayInsn(desc, dims);
}
}
......@@ -53,7 +53,7 @@ import org.objectweb.asm.Type;
* can be generated as follows:
*
* <pre>
* ClassWriter cw = new ClassWriter(true);
* ClassWriter cw = new ClassWriter(0);
* cw.visit(V1_1, ACC_PUBLIC, &quot;Example&quot;, null, &quot;java/lang/Object&quot;, null);
*
* Method m = Method.getMethod(&quot;void &lt;init&gt; ()&quot;);
......@@ -173,6 +173,9 @@ public class GeneratorAdapter extends LocalVariablesSorter {
/** Access flags of the method visited by this adapter. */
private final int access;
/** The name of the method visited by this adapter. */
private final String name;
/** Return type of the method visited by this adapter. */
private final Type returnType;
......@@ -219,6 +222,7 @@ public class GeneratorAdapter extends LocalVariablesSorter {
final String desc) {
super(api, access, desc, mv);
this.access = access;
this.name = name;
this.returnType = Type.getReturnType(desc);
this.argumentTypes = Type.getArgumentTypes(desc);
}
......@@ -233,7 +237,7 @@ public class GeneratorAdapter extends LocalVariablesSorter {
* @param mv the method visitor to which this adapter delegates calls.
*/
public GeneratorAdapter(final int access, final Method method, final MethodVisitor mv) {
this(mv, access, null, method.getDescriptor());
this(mv, access, method.getName(), method.getDescriptor());
}
/**
......@@ -281,6 +285,22 @@ public class GeneratorAdapter extends LocalVariablesSorter {
return names;
}
public int getAccess() {
return access;
}
public String getName() {
return name;
}
public Type getReturnType() {
return returnType;
}
public Type[] getArgumentTypes() {
return argumentTypes.clone();
}
// ------------------------------------------------------------------------
// Instructions to push constants on the stack
// ------------------------------------------------------------------------
......@@ -411,7 +431,11 @@ public class GeneratorAdapter extends LocalVariablesSorter {
* @param handle the handle to be pushed on the stack.
*/
public void push(final Handle handle) {
mv.visitLdcInsn(handle);
if (handle == null) {
mv.visitInsn(Opcodes.ACONST_NULL);
} else {
mv.visitLdcInsn(handle);
}
}
// ------------------------------------------------------------------------
......@@ -753,7 +777,9 @@ public class GeneratorAdapter extends LocalVariablesSorter {
mv.visitInsn(Opcodes.I2L);
} else if (to == Type.SHORT_TYPE) {
mv.visitInsn(Opcodes.I2S);
}
} else {
throw new IllegalArgumentException();
}
}
}
}
......@@ -957,6 +983,8 @@ public class GeneratorAdapter extends LocalVariablesSorter {
case GT:
intOp = Opcodes.IF_ICMPGT;
break;
default:
throw new IllegalArgumentException("Bad comparison mode " + mode);
}
mv.visitJumpInsn(intOp, label);
return;
......
......@@ -622,37 +622,42 @@ public class InstructionAdapter extends MethodVisitor {
}
@Override
public void visitLdcInsn(final Object cst) {
if (cst instanceof Integer) {
int val = ((Integer) cst).intValue();
public void visitLdcInsn(final Object value) {
if (api < Opcodes.ASM5
&& (value instanceof Handle
|| (value instanceof Type && ((Type) value).getSort() == Type.METHOD))) {
throw new UnsupportedOperationException();
}
if (value instanceof Integer) {
int val = ((Integer) value).intValue();
iconst(val);
} else if (cst instanceof Byte) {
int val = ((Byte) cst).intValue();
} else if (value instanceof Byte) {
int val = ((Byte) value).intValue();
iconst(val);
} else if (cst instanceof Character) {
int val = ((Character) cst).charValue();
} else if (value instanceof Character) {
int val = ((Character) value).charValue();
iconst(val);
} else if (cst instanceof Short) {
int val = ((Short) cst).intValue();
} else if (value instanceof Short) {
int val = ((Short) value).intValue();
iconst(val);
} else if (cst instanceof Boolean) {
int val = ((Boolean) cst).booleanValue() ? 1 : 0;
} else if (value instanceof Boolean) {
int val = ((Boolean) value).booleanValue() ? 1 : 0;
iconst(val);
} else if (cst instanceof Float) {
float val = ((Float) cst).floatValue();
} else if (value instanceof Float) {
float val = ((Float) value).floatValue();
fconst(val);