[Fb-contrib-commit] fb-contrib/src/com/mebigfatguy/fbcontrib/detect LocalSynchronizedCollection.java
Brought to you by:
dbrosius
From: Dave B. <dbr...@us...> - 2006-03-11 05:01:39
|
Update of /cvsroot/fb-contrib/fb-contrib/src/com/mebigfatguy/fbcontrib/detect In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv9538/src/com/mebigfatguy/fbcontrib/detect Added Files: LocalSynchronizedCollection.java Log Message: intial checkin - new LSYC detector --- NEW FILE: LocalSynchronizedCollection.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.HashSet; import java.util.Map; import java.util.Set; import org.apache.bcel.classfile.Code; 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.SourceLineAnnotation; import edu.umd.cs.findbugs.StatelessDetector; /** * looks for allocations of synchronized collections that are stored in local variables, and * never stored in fields or returned from methods. As local variables are by definition * thread safe, using synchronized collections in this context makes no sense. */ public class LocalSynchronizedCollection extends BytecodeScanningDetector implements StatelessDetector { private static Set<String> syncCtors = new HashSet<String>(); static { syncCtors.add("java/util/Vector"); syncCtors.add("java/util/Hashtable"); } private static Set<String> syncMethods = new HashSet<String>(); static { syncMethods.add("synchronizedCollection"); syncMethods.add("synchronizedList"); syncMethods.add("synchronizedMap"); syncMethods.add("synchronizedSet"); syncMethods.add("synchronizedSortedMap"); syncMethods.add("synchronizedSortedSet"); } private BugReporter bugReporter; private OpcodeStack stack = new OpcodeStack(); private Map<Integer, SourceLineAnnotation> syncRegs = new HashMap<Integer, SourceLineAnnotation>(); /** * constructs a LSYC detector given the reporter to report bugs on * @param bugReporter the sync of bug reports */ public LocalSynchronizedCollection(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 * * @param obj the context object of the currently parsed code block */ @Override public void visitCode(Code obj) { stack.resetForMethodEntry(this); syncRegs.clear(); super.visitCode(obj); for (Map.Entry<Integer, SourceLineAnnotation> entry : syncRegs.entrySet()) { bugReporter.reportBug(new BugInstance(this, "LSYC_LOCAL_SYNCHRONIZED_COLLECTION", NORMAL_PRIORITY) .addClass(this) .addMethod(this) .addSourceLine(entry.getValue())); } } /** * implements the visitor to find stores to locals of synchronized collections * * @param seen the opcode of the currently parsed instruction */ @Override public void sawOpcode(int seen) { Integer tosIsSyncColReg = null; try { stack.mergeJumps(this); if (seen == INVOKESPECIAL) { if ("<init>".equals(getNameConstantOperand())) { if (syncCtors.contains(getClassConstantOperand())) { tosIsSyncColReg = new Integer(-1); } } } else if (seen == INVOKESTATIC) { if ("java/util/Collections".equals(getClassConstantOperand())) { if (syncMethods.contains(getNameConstantOperand())) { tosIsSyncColReg = new Integer(-1); } } } else if ((seen == ASTORE) || ((seen >= ASTORE_0) && (seen <= ASTORE_3))) { if (stack.getStackDepth() > 0) { OpcodeStack.Item item = stack.getStackItem(0); if (item.getUserValue() != null) { int reg = getAStoreReg(seen); if (!syncRegs.containsKey(reg)) syncRegs.put(new Integer(reg), SourceLineAnnotation.fromVisitedInstruction(this)); } } } else if ((seen == ALOAD) || ((seen >= ALOAD_0) && (seen <= ALOAD_3))) { int reg = getALoadReg(seen); if (syncRegs.containsKey(new Integer(reg))) tosIsSyncColReg = new Integer(reg); } else if ((seen == PUTFIELD) || (seen == ARETURN)) { if (stack.getStackDepth() > 0) { OpcodeStack.Item item = stack.getStackItem(0); syncRegs.remove(item.getUserValue()); } } } finally { stack.sawOpcode(this, seen); if (tosIsSyncColReg != null) { if (stack.getStackDepth() > 0) { OpcodeStack.Item item = stack.getStackItem(0); item.setUserValue(tosIsSyncColReg); } } } } /** * returns the register used to store a reference * * @param seen the opcode of the store * @return the register stored into */ private int getAStoreReg(int seen) { if (seen == ASTORE) return getRegisterOperand(); return seen - ASTORE_0; } /** * returns the register used to load a reference * * @param seen the opcode of the load * @return the register loaded from */ private int getALoadReg(int seen) { if (seen == ALOAD) return getRegisterOperand(); return seen - ALOAD_0; } } |