[Fb-contrib-commit] fb-contrib/src/com/mebigfatguy/fbcontrib/detect ArrayWrappedCallByReference.java
Brought to you by:
dbrosius
|
From: Dave B. <dbr...@us...> - 2006-01-23 07:53:14
|
Update of /cvsroot/fb-contrib/fb-contrib/src/com/mebigfatguy/fbcontrib/detect In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv9694/src/com/mebigfatguy/fbcontrib/detect Added Files: ArrayWrappedCallByReference.java Log Message: initial checkin new AWCBR detector - semi working (requires findbugs.jar 0.95) --- NEW FILE: ArrayWrappedCallByReference.java --- /* * fb-contrib - Auxilliary detectors for Java programs * Copyright (C) 2005-2006 Dave Brosius * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package com.mebigfatguy.fbcontrib.detect; import java.util.HashMap; import java.util.Map; import org.apache.bcel.classfile.Code; import org.apache.bcel.generic.Type; import edu.umd.cs.findbugs.BugInstance; import edu.umd.cs.findbugs.BugReporter; import edu.umd.cs.findbugs.BytecodeScanningDetector; import edu.umd.cs.findbugs.OpcodeStack; import edu.umd.cs.findbugs.StatelessDetector; /** * Looks for methods that use an array of length one to pass a variable to achieve call * by pointer ala C++. It is better to define a proper return class type that holds all * the relevant information retrieved from the called method. */ public class ArrayWrappedCallByReference extends BytecodeScanningDetector implements StatelessDetector { static class WrapperInfo { static final int WAS_STORED = 0; static final int WAS_ARG = 1; static final int WAS_LOADED = 2; public int wrappedReg; public int state; public WrapperInfo(int reg) { wrappedReg = reg; state = WAS_STORED; } } private BugReporter bugReporter; private OpcodeStack stack = new OpcodeStack(); private Map<Integer, WrapperInfo> wrappers = new HashMap<Integer, WrapperInfo>(); /** * constructs a AWCBR detector given the reporter to report bugs on * @param bugReporter the sync of bug reports */ public ArrayWrappedCallByReference(BugReporter bugReporter) { this.bugReporter = bugReporter; } /** * clone this detector so that it can be a StatelessDetector * * @return a clone of this object */ @Override public Object clone() throws CloneNotSupportedException { return super.clone(); } /** * implements the visitor to reset the stack of opcodes * * @param obj the context object for the currently parsed code block */ @Override public void visitCode(Code obj) { stack.resetForMethodEntry(this); wrappers.clear(); super.visitCode(obj); } /** * implements the visitor to wrapped array parameter calls * * @param seen the currently visitor opcode */ @Override public void sawOpcode(int seen) { Integer userValue = null; try { if ((seen == NEWARRAY) || (seen == ANEWARRAY)) { if (stack.getStackDepth() > 0) { OpcodeStack.Item itm = stack.getStackItem(0); Integer size = (Integer)itm.getConstant(); if ((size != null) && (size.intValue() == 1)) { userValue = new Integer(-1); } } } else if ((seen >= IASTORE) && (seen <= SASTORE)) { if (stack.getStackDepth() >= 2) { OpcodeStack.Item itm = stack.getStackItem(2); int reg = itm.getRegisterNumber(); if (reg != -1) { WrapperInfo wi = wrappers.get(new Integer(reg)); if (wi != null) { OpcodeStack.Item elItm = stack.getStackItem(0); wi.wrappedReg = elItm.getRegisterNumber(); } } else { OpcodeStack.Item elItm = stack.getStackItem(0); if (elItm.getRegisterNumber() != -1) userValue = new Integer(elItm.getRegisterNumber()); } } } else if ((seen == ASTORE) || ((seen >= ASTORE_0) && (seen <= ASTORE_3))) { if (stack.getStackDepth() >= 1) { OpcodeStack.Item itm = stack.getStackItem(0); if (itm.getSignature().charAt(0) == '[') { int reg = getAStoreReg(seen); Integer elReg = (Integer)itm.getUserValue(); if (elReg != null) wrappers.put(new Integer(reg), new WrapperInfo(elReg)); } else { Integer elReg = (Integer)itm.getUserValue(); if (elReg != null) { int reg = getAStoreReg(seen); if (elReg.intValue() == reg) { bugReporter.reportBug(new BugInstance(this, "AWCBR_ARRAY_WRAPPED_CALL_BY_REFERENCE", NORMAL_PRIORITY ) .addClass(this) .addMethod(this) .addSourceLine(this)); } } } } } else if ((seen == INVOKEVIRTUAL) || (seen == INVOKEINTERFACE) || (seen == INVOKESPECIAL) || (seen == INVOKESTATIC)) { String sig = getSigConstantOperand(); Type[] args = Type.getArgumentTypes(sig); if (stack.getStackDepth() >= args.length) { for (int i = 0; i < args.length; i++) { Type t = args[i]; if (t.getSignature().charAt(0) == '[') { OpcodeStack.Item itm = stack.getStackItem(args.length - i - 1); int arrayReg = itm.getRegisterNumber(); WrapperInfo wi = wrappers.get(new Integer(arrayReg)); if (wi != null) wi.state = WrapperInfo.WAS_ARG; } } } } else if ((seen >= IALOAD) && (seen <= SALOAD)) { if (stack.getStackDepth() >= 2) { OpcodeStack.Item arItm = stack.getStackItem(1); int arReg = arItm.getRegisterNumber(); WrapperInfo wi = wrappers.get(new Integer(arReg)); if (wi != null) { userValue = wi.wrappedReg; } } } else if ((seen == ALOAD) || ((seen >= ALOAD_0) && (seen <= ALOAD_3))) { int reg = getALoadReg(seen); WrapperInfo wi = wrappers.get(new Integer(reg)); if (wi != null) userValue = new Integer(wi.wrappedReg); } else if (((seen == ISTORE) || ((seen >= ISTORE_0) && (seen <= ISTORE_3))) || ((seen == LSTORE) || ((seen >= LSTORE_0) && (seen <= LSTORE_3))) || ((seen == DSTORE) || ((seen >= DSTORE_0) && (seen <= DSTORE_3))) || ((seen == FSTORE) || ((seen >= FSTORE_0) && (seen <= FSTORE_3)))) { if (stack.getStackDepth() >= 1) { OpcodeStack.Item itm = stack.getStackItem(0); Integer elReg = (Integer)itm.getUserValue(); if (elReg != null) { int reg = getStoreReg(seen); if (elReg.intValue() == reg) { bugReporter.reportBug(new BugInstance(this, "AWCBR_ARRAY_WRAPPED_CALL_BY_REFERENCE", NORMAL_PRIORITY ) .addClass(this) .addMethod(this) .addSourceLine(this)); } } } } } finally { stack.sawOpcode(this, seen); if (userValue != null) { if (stack.getStackDepth() > 0) { OpcodeStack.Item itm = stack.getStackItem(0); itm.setUserValue(userValue); } } } } private int getAStoreReg(int seen) { if (seen == ASTORE) return getRegisterOperand(); return seen - ASTORE_0; } private int getALoadReg(int seen) { if (seen == ALOAD) return getRegisterOperand(); return seen - ALOAD_0; } private int getStoreReg(int seen) { if ((seen == ASTORE) || (seen == ISTORE) || (seen == LSTORE) || (seen == FSTORE) || (seen == DSTORE)) return getRegisterOperand(); if (seen <= ISTORE_3) return seen - ISTORE_0; else if (seen <= LSTORE_3) return seen - LSTORE_0; else if (seen <= FSTORE_3) return seen - FSTORE_0; else if (seen <= DSTORE_3) return seen - DSTORE_0; return seen - ASTORE_0; } } |