@Override public BasicValue newOperation(AbstractInsnNode insnNode) throws AnalyzerException { switch (insnNode.getOpcode()) { case ICONST_0: return new IntegerConstantBasicValue(Type.INT_TYPE, 0); case ICONST_1: return new IntegerConstantBasicValue(Type.INT_TYPE, 1); case ICONST_2: return new IntegerConstantBasicValue(Type.INT_TYPE, 2); case ICONST_3: return new IntegerConstantBasicValue(Type.INT_TYPE, 3); case ICONST_4: return new IntegerConstantBasicValue(Type.INT_TYPE, 4); case ICONST_5: return new IntegerConstantBasicValue(Type.INT_TYPE, 5); case BIPUSH: case SIPUSH: return new IntegerConstantBasicValue(Type.INT_TYPE, ((IntInsnNode)insnNode).operand); case Opcodes.LDC: { Object constant = ((LdcInsnNode)insnNode).cst; if (constant instanceof Integer) { return new IntegerConstantBasicValue(Type.INT_TYPE, (Integer)constant); } else { return super.newOperation(insnNode); } } default: return super.newOperation(insnNode); } }
@Override public BasicValue binaryOperation(final AbstractInsnNode insn, final BasicValue value1, final BasicValue value2) throws AnalyzerException { /* * We're looking for the assignment of a local holder objectref to a member variable. * If we spot that, then the local holder can't be replaced, since we don't (yet) * have the mechanics to replace the member variable with the holder's members or * to assign all of them when this happens. */ if (insn.getOpcode() == Opcodes.PUTFIELD) { if (value2.isReference() && (value1 instanceof ReplacingBasicValue)) { final ReplacingBasicValue possibleThis = (ReplacingBasicValue) value1; if (possibleThis.isThis() && (value2 instanceof ReplacingBasicValue)) { // if this is a reference for a holder class, we can't replace it if (HOLDERS.get(value2.getType().getDescriptor()) != null) { final ReplacingBasicValue localRef = (ReplacingBasicValue) value2; localRef.setAssignedToMember(); } } } } return super.binaryOperation(insn, value1, value2); }
@Override public BasicValue naryOperation(final AbstractInsnNode insn, final List<? extends BasicValue> values) throws AnalyzerException { if (insn instanceof MethodInsnNode) { boolean skipOne = insn.getOpcode() != Opcodes.INVOKESTATIC; // Note if the argument is a holder, and is used as a function argument for(BasicValue value : values) { // if non-static method, skip over the receiver if (skipOne) { skipOne = false; continue; } if (value instanceof ReplacingBasicValue) { final ReplacingBasicValue argument = (ReplacingBasicValue) value; argument.setFunctionArgument(); } } } return super.naryOperation(insn, values); }
private void generateCDG(MethodNode mn) { if(BytecodeInstructionPool.getInstance(classLoader).hasMethod(className, mn.name + mn.desc)) return; BytecodeInstructionPool.getInstance(classLoader).registerMethodNode(mn, className, mn.name + mn.desc); // TODO: Adapt for multiple classLoaders BytecodeAnalyzer bytecodeAnalyzer = new BytecodeAnalyzer(); logger.info("Generating initial CFG for method " + mn.name); try { bytecodeAnalyzer.analyze(classLoader, className, mn.name + mn.desc, mn); // TODO } catch (AnalyzerException e) { logger.error("Analyzer exception while analyzing " + className + "." + mn.name + ": " + e); e.printStackTrace(); } // compute Raw and ActualCFG and put both into GraphPool bytecodeAnalyzer.retrieveCFGGenerator().registerCFGs(); }
/** {@inheritDoc} */ @Override public BasicValue newOperation(AbstractInsnNode insn) throws AnalyzerException { if (insn.getOpcode() == ICONST_0) { return BOOLEAN_VALUE; } else if (insn.getOpcode() == ICONST_1) { return BOOLEAN_VALUE; } else if (insn.getOpcode() == Opcodes.GETSTATIC) { FieldInsnNode fieldNode = (FieldInsnNode) insn; if (BooleanTestabilityTransformation.isTransformedField(fieldNode.owner, fieldNode.name, fieldNode.desc)) return BOOLEAN_VALUE; } return super.newOperation(insn); }
/** {@inheritDoc} */ @Override public BasicValue copyOperation(AbstractInsnNode insn, BasicValue value) throws AnalyzerException { if (insn.getOpcode() == Opcodes.ILOAD) { VarInsnNode varNode = (VarInsnNode) insn; if (isStatic) { if (varNode.var < types.length) { if (types[varNode.var] == Type.BOOLEAN_TYPE) { return BOOLEAN_VALUE; } } } else { if (varNode.var > 0 && varNode.var - 1 < types.length) { if (types[varNode.var - 1] == Type.BOOLEAN_TYPE) { return BOOLEAN_VALUE; } } } } return super.copyOperation(insn, value); }
@SuppressWarnings("rawtypes") /** {@inheritDoc} */ @Override public BasicValue naryOperation(AbstractInsnNode insn, List values) throws AnalyzerException { if (insn instanceof MethodInsnNode) { MethodInsnNode mi = (MethodInsnNode) insn; if (Type.getReturnType(BooleanTestabilityTransformation.getOriginalDesc(mi.owner, mi.name, mi.desc)) == Type.BOOLEAN_TYPE) { return BOOLEAN_VALUE; } } return super.naryOperation(insn, values); }
@Override public boolean merge(final Frame<? extends BasicValue> frame, final Interpreter<BasicValue> interpreter) throws AnalyzerException { if (force) { // uses the current frame return true; } if (frame instanceof ExtendedFrame && ((ExtendedFrame) frame).force) { init(frame); return true; } return super.merge(frame, interpreter); }
@Test public void testErrorReporting() throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException, IOException, AnalyzerException { ClassReader cr = new ClassReader(InvalidAwaitCall.class.getResourceAsStream(InvalidAwaitCall.class.getName().replaceAll("^.*[.]", "") + ".class")); assertTrue(mentionsAwait(cr)); AtomicReference<String> reference = new AtomicReference<>(); final Transformer transformer = new Transformer(); transformer.setErrorListener(t -> reference.set(t)); final byte[] bytes = transformer.transform(getClass().getClassLoader(), cr); assertNotNull(reference.get()); assertTrue(reference.get().contains("invalidAwaitCall")); ClassReader cr2 = new ClassReader(bytes); assertFalse(mentionsAwait(cr2)); }
/** * Merges this frame with the given frame. * * @param frame * a frame. * @param interpreter * the interpreter used to merge values. * @return <tt>true</tt> if this frame has been changed as a result of the * merge operation, or <tt>false</tt> otherwise. * @throws AnalyzerException * if the frames have incompatible sizes. */ public boolean merge(final Frame<? extends V> frame, final Interpreter interpreter) throws AnalyzerException { if (top != frame.top) { throw new AnalyzerException(null, "Incompatible stack heights"); } boolean changes = false; for (int i = 0; i < locals + top; ++i) { V v = (V) interpreter.merge(values[i], frame.values[i]); if (!v.equals(values[i])) { values[i] = v; changes = true; } } return changes; }
@SuppressWarnings("unused") private static void printClass(final byte[] classfileBuffer, final String classname) { /* final TraceClassVisitor v = new TraceClassVisitor(new PrintWriter(System.out)); new ClassReader(classfileBuffer).accept(v, ClassReader.SKIP_DEBUG); */ final ClassNode cn = new ClassNode(); final ClassReader cr = new ClassReader(classfileBuffer); //cr.accept(new CheckClassAdapter(cn), ClassReader.SKIP_DEBUG); cr.accept(new CheckClassAdapter(cn), 0); for (final Object methodObj : cn.methods) { final MethodNode method = (MethodNode) methodObj; final Analyzer a = new Analyzer(new BasicVerifier()); //final Analyzer a = new Analyzer(new SimpleVerifier()); try { a.analyze(cn.name, method); } catch (final AnalyzerException e) { System.err.println("// error in method " + classname + "." + method.name + method.desc + ":" + e); } printMethod(a, System.err, method); } }
public byte[] rewrite(final String classToAnalyze, final File[] classPathEntries,IJoinpointFilter filter) throws IOException, AnalyzerException { final IClassReaderProvider provider = new IClassReaderProvider() { @Override public ClassReader getClassReader() throws IOException { return ASMUtil.createClassReader( classToAnalyze , classPathEntries ); } @Override public String getClassName() { return classToAnalyze; } }; return rewrite( provider , filter ); }
private void visitMethod(MethodNode method,String owner) throws AnalyzerException, FileNotFoundException { final ControlFlowGraph graph = analyzer.analyze(owner, method ); final String dot = new DOTRenderer().render( graph ); final File outputFile; if ( outputDir != null ) { outputFile = new File( outputDir , toFilename( method )+".dot" ); } else { outputFile = new File( toFilename( method )+".dot" ); } logVerbose("Writing "+outputFile.getAbsolutePath()); if ( ! outputFile.getParentFile().exists() ) { outputFile.getParentFile().mkdirs(); } final PrintWriter writer = new PrintWriter( outputFile); writer.write( dot ); writer.close(); }
@Override public BasicValue newOperation(AbstractInsnNode insnNode) throws AnalyzerException { if (insnNode.getOpcode() == Opcodes.LDC) { Object constant = ((LdcInsnNode) insnNode).cst; if (constant instanceof String) { return new PlaceHolderStringBasicValue(calculateNumberOfPlaceHolders((String) constant)); } } return super.newOperation(insnNode); }
@Override public BasicValue unaryOperation(AbstractInsnNode insnNode, BasicValue value) throws AnalyzerException { if (insnNode.getOpcode() == Opcodes.ANEWARRAY && value instanceof IntegerConstantBasicValue) { IntegerConstantBasicValue constantBasicValue = (IntegerConstantBasicValue) value; String desc = ((TypeInsnNode) insnNode).desc; return new ArraySizeBasicValue(Type.getType("[" + Type.getObjectType(desc)), constantBasicValue.minValue, constantBasicValue.maxValue); } return super.unaryOperation(insnNode, value); }
@Override public BasicValue ternaryOperation(AbstractInsnNode insnNode, BasicValue value1, BasicValue value2, BasicValue value3) throws AnalyzerException { if (insnNode.getOpcode() == Opcodes.AASTORE && value1 instanceof ArraySizeBasicValue) { return value1; } return super.ternaryOperation(insnNode, value1, value2, value3); }
@Override public BasicValue newOperation(final AbstractInsnNode insn) throws AnalyzerException { if (insn.getOpcode() == Opcodes.NEW) { final TypeInsnNode t = (TypeInsnNode) insn; // if this is for a holder class, we'll replace it final ValueHolderIden iden = HOLDERS.get(t.desc); if (iden != null) { return ReplacingBasicValue.create(Type.getObjectType(t.desc), iden, index++, valueList); } } return super.newOperation(insn); }
@Override public BasicValue unaryOperation(final AbstractInsnNode insn, final BasicValue value) throws AnalyzerException { /* * We're looking for the assignment of an operator member variable that's a holder to a local * objectref. If we spot that, we can't replace the local objectref (at least not * until we do the work to replace member variable holders). * * Note that a GETFIELD does not call newValue(), as would happen for a local variable, so we're * emulating that here. */ if ((insn.getOpcode() == Opcodes.GETFIELD) && (value instanceof ReplacingBasicValue)) { final ReplacingBasicValue possibleThis = (ReplacingBasicValue) value; if (possibleThis.isThis()) { final FieldInsnNode fieldInsn = (FieldInsnNode) insn; if (HOLDERS.get(fieldInsn.desc) != null) { final BasicValue fetchedField = super.unaryOperation(insn, value); final ReplacingBasicValue replacingValue = ReplacingBasicValue.create(fetchedField.getType(), null, -1, valueList); replacingValue.setAssignedToMember(); return replacingValue; } } } return super.unaryOperation(insn, value); }
@Override public BasicValue newOperation(AbstractInsnNode insn) throws AnalyzerException { if(insn.getOpcode() == Opcodes.NEW) { return new NewValue(Type.getObjectType(((TypeInsnNode) insn).desc), false, insn); } return super.newOperation(insn); }
@Override public BasicValue copyOperation(AbstractInsnNode insn, BasicValue value) throws AnalyzerException { if(insn.getOpcode() == Opcodes.DUP) { if(value instanceof NewValue) { NewValue newValue = (NewValue)value; if(!newValue.isDupped) { return new NewValue(newValue.getType(), true, insn); } } } return super.copyOperation(insn, value); }
@Override public BasicValue binaryOperation(AbstractInsnNode insn, BasicValue value1, BasicValue value2) throws AnalyzerException { if(insn.getOpcode() == Opcodes.AALOAD) { Type t1 = value1.getType(); if(t1 == null || t1.getSort() != Type.ARRAY) { throw new AnalyzerException(insn, "AALOAD needs an array as first parameter"); } Type resultType = Type.getType(t1.getDescriptor().substring(1)); return new BasicValue(resultType); } return super.binaryOperation(insn, value1, value2); }
public InstrumentMethod(MethodDatabase db, String className, MethodNode mn) throws AnalyzerException { this.db = db; this.className = className; this.mn = mn; try { Analyzer a = new TypeAnalyzer(db); this.frames = a.analyze(className, mn); this.lvarStack = mn.maxLocals; this.firstLocal = ((mn.access & Opcodes.ACC_STATIC) == Opcodes.ACC_STATIC) ? 0 : 1; } catch (UnsupportedOperationException ex) { throw new AnalyzerException(null, ex.getMessage(), ex); } }
@Override public BasicValue newOperation(AbstractInsnNode insn) throws AnalyzerException { BasicValue superVal = super.newOperation(insn); if (superVal != null) { addEntry(superVal, insn); } return superVal; }
@Override public BasicValue unaryOperation(AbstractInsnNode insn, BasicValue val) throws AnalyzerException { BasicValue superVal = super.unaryOperation(insn, val); if (superVal != null) { addEntry(superVal, insn); } return superVal; }
@Override public BasicValue binaryOperation(AbstractInsnNode insn, BasicValue val1, BasicValue val2) throws AnalyzerException { BasicValue superVal = super.binaryOperation(insn, val1, val2); if (superVal != null) { addEntry(superVal, insn); } return superVal; }
@Override public BasicValue naryOperation(AbstractInsnNode insn, List<? extends BasicValue> vals) throws AnalyzerException { BasicValue superVal = super.naryOperation(insn, vals); if (superVal != null) { addEntry(superVal, insn); } return superVal; }
/** {@inheritDoc} */ @Override public BasicValue naryOperation(AbstractInsnNode insn, @SuppressWarnings("rawtypes") List values) throws AnalyzerException { if (insn.getOpcode() == Opcodes.INVOKESTATIC) { MethodInsnNode mn = (MethodInsnNode) insn; if (mn.owner.equals(Type.getInternalName(StringHelper.class)) && mn.name.startsWith("String")) { return STRING_BOOLEAN; } } return super.naryOperation(insn, values); }
/** {@inheritDoc} */ @Override public BasicValue naryOperation(AbstractInsnNode insn, @SuppressWarnings("rawtypes") List values) throws AnalyzerException { if (insn.getOpcode() == Opcodes.INVOKESTATIC) { MethodInsnNode mn = (MethodInsnNode) insn; if (mn.owner.equals(Type.getInternalName(ContainerHelper.class)) && (mn.name.startsWith("collection") || mn.name.startsWith("map"))) { return CONTAINER_BOOLEAN; } } return super.naryOperation(insn, values); }
/** {@inheritDoc} */ @SuppressWarnings("rawtypes") @Override public BasicValue naryOperation(AbstractInsnNode insn, List values) throws AnalyzerException { if (insn.getOpcode() == INVOKESTATIC || insn.getOpcode() == INVOKEVIRTUAL || insn.getOpcode() == INVOKEINTERFACE) { MethodInsnNode mn = (MethodInsnNode) insn; if (Type.getReturnType(mn.desc).equals(Type.BOOLEAN_TYPE)) { return BOOLEAN; } else if (mn.desc.equals("[Z")) { return BOOLEAN_ARRAY; } else if (mn.desc.equals("[B")) { return BYTE_ARRAY; } else if (mn.desc.equals("[I")) { return INT_ARRAY; } else if (Type.getReturnType(mn.desc).equals(Type.BYTE_TYPE)) { return BYTE; } else { if (mn.name.equals("clone") && mn.owner.equals("[I")) return INT_ARRAY; else if (mn.name.equals("clone") && mn.owner.equals("[Z")) return BOOLEAN_ARRAY; else if (mn.name.equals("clone") && mn.owner.equals("[B")) return BYTE_ARRAY; else { return super.naryOperation(insn, values); } } } else { return super.naryOperation(insn, values); } }
/** {@inheritDoc} */ @Override public BasicValue unaryOperation(AbstractInsnNode insn, BasicValue value) throws AnalyzerException { if (insn.getOpcode() == Opcodes.INSTANCEOF) { return BOOLEAN_VALUE; } else if (insn.getOpcode() == Opcodes.GETFIELD) { FieldInsnNode fieldNode = (FieldInsnNode) insn; if (BooleanTestabilityTransformation.isTransformedField(fieldNode.owner, fieldNode.name, fieldNode.desc)) return BOOLEAN_VALUE; } return super.unaryOperation(insn, value); }
/** {@inheritDoc} */ @Override public BasicValue binaryOperation(AbstractInsnNode insn, BasicValue value1, BasicValue value2) throws AnalyzerException { switch (insn.getOpcode()) { case IALOAD: case BALOAD: case CALOAD: case SALOAD: if (value1 == BOOLEAN_ARRAY) return BOOLEAN_VALUE; } return super.binaryOperation(insn, value1, value2); }
/** {@inheritDoc} */ @Override public BasicValue copyOperation(AbstractInsnNode insn, BasicValue value) throws AnalyzerException { if (insn.getOpcode() == Opcodes.ALOAD) { VarInsnNode varNode = (VarInsnNode) insn; if (varNode.var == 0) { return THIS_VALUE; } } return super.copyOperation(insn, value); }
@Override public BasicValue newOperation(final AbstractInsnNode insn) throws AnalyzerException { if (insn.getOpcode() == Opcodes.NEW) { final Type type = Type.getObjectType(((TypeInsnNode) insn).desc); final ExtendedValue extendedValue = new ExtendedValue(type); extendedValue.uninitialized = true; extendedValue.insnNode = insn; return extendedValue; } return super.newOperation(insn); }
BasicValue convertFrameNodeType(final Object v) throws AnalyzerException { if (v instanceof String) { return interpreter.newValue(Type.getObjectType((String) v)); } else if (v instanceof Integer) { switch ((Integer) v) { case FN_TOP: // TODO: check this return interpreter.newValue(null); case FN_INTEGER: return interpreter.newValue(Type.INT_TYPE); case FN_FLOAT: return interpreter.newValue(Type.FLOAT_TYPE); case FN_DOUBLE: return interpreter.newValue(Type.DOUBLE_TYPE); case FN_LONG: return interpreter.newValue(Type.LONG_TYPE); case FN_NULL: // TODO: check this return interpreter.newValue(BasicValue.REFERENCE_VALUE.getType()); case FN_UNINITIALIZED_THIS: // TODO: check this return interpreter.newValue(null); } } else if (v instanceof LabelNode) { AbstractInsnNode node = (AbstractInsnNode) v; while (node.getOpcode() != NEW) { node = node.getNext(); } return interpreter.newOperation(node); } return interpreter.newValue(null); }
@Test public void branchAnalysisWithFrames() throws AnalyzerException { MethodNode mv = new MethodNode(ACC_PUBLIC, "apply", "(I)Ljava/lang/Object;", null, null); mv.visitCode(); mv.visitInsn(ICONST_1); mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false); mv.visitVarInsn(ASTORE, 2); mv.visitVarInsn(ILOAD, 1); mv.visitInsn(ICONST_3); Label l0 = new Label(); mv.visitJumpInsn(IF_ICMPNE, l0); mv.visitLdcInsn(new Double("2.0")); mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false); mv.visitVarInsn(ASTORE, 2); mv.visitLabel(l0); mv.visitFrame(F_FULL, 3, new Object[]{ "com/ea/async/Bogus", INTEGER, "java/lang/Number" }, 0, new Object[0]); mv.visitVarInsn(ALOAD, 2); mv.visitInsn(ARETURN); mv.visitMaxs(2, 3); mv.visitEnd(); Frame<BasicValue>[] frames = new FrameAnalyzer().analyze("com/ea/async/Bogus", mv); // when the frameNode is not used by the analyzer this will return java/lang/Object Frame<BasicValue> frame = frames[frames.length - 1]; assertEquals("com/ea/async/Bogus", frame.getLocal(0).getType().getInternalName()); assertEquals("I", frame.getLocal(1).getType().toString()); assertEquals("java/lang/Number", frame.getLocal(2).getType().getInternalName()); }
@Test public void testAwaitInitRemoval() throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException, IOException, AnalyzerException { StaticUse.callInit(); ClassReader cr = new ClassReader(StaticUse.class.getResourceAsStream(StaticUse.class.getName().replaceAll("^.*[.]", "") + ".class")); assertTrue(mentionsAwait(cr)); final byte[] bytes = new Transformer().transform(getClass().getClassLoader(), cr); ClassReader cr2 = new ClassReader(bytes); assertFalse(mentionsAwait(cr2)); }