public TouchMethodVisitor( String owner, MethodNode methodNode, MethodVisitor methodVisitor, Set<Label> jumpLabels, Map<Label, Integer> lineLabels, Map<Label, SwitchHolder> switchLabels) { super(Opcodes.ASM5, methodVisitor); _owner = owner; _jumpLabels = jumpLabels; _lineLabels = lineLabels; _switchLabels = switchLabels; int variableCount = 0; if ((Opcodes.ACC_STATIC & methodNode.access) == 0) { variableCount++; } for (Type type : Type.getArgumentTypes(methodNode.desc)) { variableCount += type.getSize(); } _variableCount = variableCount; }
@Override public void checkCall( @NonNull ClassContext context, @NonNull ClassNode classNode, @NonNull MethodNode method, @NonNull MethodInsnNode call) { String owner = call.owner; String desc = call.desc; if (owner.equals(OWNER_SECURE_RANDOM)) { if (desc.startsWith(LONG_ARG)) { checkValidSetSeed(context, call); } else if (desc.startsWith("([B)")) { // $NON-NLS-1$ // setSeed(byte[]) ... // We could do some flow analysis here to see whether the byte array getting // passed in appears to be fixed. // However, people calling this constructor rather than the simpler one // with a fixed integer are probably less likely to make that mistake... right? } } else if (owner.equals(OWNER_RANDOM) && desc.startsWith(LONG_ARG)) { // Called setSeed(long) on an instanceof a Random object. Flag this if the instance // is likely a SecureRandom. // Track allocations such that we know whether the type of the call // is on a SecureRandom rather than a Random Analyzer analyzer = new Analyzer( new BasicInterpreter() { @Override public BasicValue newValue(Type type) { if (type != null && type.getDescriptor().equals(VM_SECURE_RANDOM)) { return new BasicValue(type); } return super.newValue(type); } }); try { Frame[] frames = analyzer.analyze(classNode.name, method); InsnList instructions = method.instructions; Frame frame = frames[instructions.indexOf(call)]; int stackSlot = frame.getStackSize(); for (Type type : Type.getArgumentTypes(desc)) { stackSlot -= type.getSize(); } BasicValue stackValue = (BasicValue) frame.getStack(stackSlot); Type type = stackValue.getType(); if (type != null && type.getDescriptor().equals(VM_SECURE_RANDOM)) { checkValidSetSeed(context, call); } } catch (AnalyzerException e) { context.log(e, null); } } else if (owner.equals(OWNER_RANDOM) && desc.startsWith(LONG_ARG)) { // Called setSeed(long) on an instanceof a Random object. Flag this if the instance // is likely a SecureRandom. // TODO } }
public void DUP(Type type) { switch (type.getSize()) { case 1: DUP(); break; case 2: DUP2(); break; default: throw new RuntimeException("Bad size"); } }
/** * Fetches return value or thrown exception. If return value is of basic type, it is automatically * boxed. * * @param mv output method visitor * @param type return data type * @return number of JVM stack slots emitted code consumes */ public int emitFetchRetVal(SpyMethodVisitor mv, Type type) { if (Type.VOID == type.getSort()) { mv.visitInsn(ACONST_NULL); return 1; } mv.visitInsn(DUP); emitAutoboxing(mv, type); mv.visitVarInsn(ASTORE, mv.getRetValProbeSlot()); return type.getSize(); }
private int remap(final int var, final Type type) { if (var + type.getSize() <= firstLocal) { return var; } int key = 2 * var + type.getSize() - 1; int size = mapping.length; if (key >= size) { int[] newMapping = new int[Math.max(2 * size, key + 1)]; System.arraycopy(mapping, 0, newMapping, 0, size); mapping = newMapping; } int value = mapping[key]; if (value == 0) { value = newLocalMapping(type); setLocalType(value, type); mapping[key] = value + 1; } else { value--; } if (value != var) { changed = true; } return value; }
protected int newLocalMapping(final Type type) { int local = nextLocal; nextLocal += type.getSize(); return local; }