Thread: [Fb-contrib-commit] SF.net SVN: fb-contrib: [520] trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/det
Brought to you by:
dbrosius
From: <dbr...@us...> - 2006-05-09 06:48:29
|
Revision: 520 Author: dbrosius Date: 2006-05-08 23:48:21 -0700 (Mon, 08 May 2006) ViewCVS: http://svn.sourceforge.net/fb-contrib/?rev=520&view=rev Log Message: ----------- Initial checkin - NMCS - far from working Added Paths: ----------- trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/NeedlessMemberCollectionSynchronization.java Added: trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/NeedlessMemberCollectionSynchronization.java =================================================================== --- trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/NeedlessMemberCollectionSynchronization.java (rev 0) +++ trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/NeedlessMemberCollectionSynchronization.java 2006-05-09 06:48:21 UTC (rev 520) @@ -0,0 +1,206 @@ +/* + * 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.Repository; +import org.apache.bcel.classfile.Code; +import org.apache.bcel.classfile.Field; +import org.apache.bcel.classfile.JavaClass; + +import edu.umd.cs.findbugs.BugReporter; +import edu.umd.cs.findbugs.BytecodeScanningDetector; +import edu.umd.cs.findbugs.FieldAnnotation; +import edu.umd.cs.findbugs.OpcodeStack; +import edu.umd.cs.findbugs.ba.ClassContext; + +/** + * looks for private collection members, either static or instance, that are only initialized in + * the clinit or init, but are synchronized. This is not necessary as the constructor or static + * initializer are guaranteed to be thread safe. + */ +public class NeedlessMemberCollectionSynchronization extends BytecodeScanningDetector { + private static JavaClass collectionClass; + static { + try { + collectionClass = Repository.lookupClass("java/util/Collection"); + } catch (ClassNotFoundException cnfe) { + collectionClass = null; + } + } + private static Set<String> syncCollections = new HashSet<String>(); + static { + syncCollections.add("java/util/Vector"); + syncCollections.add("java/util/Hashtable"); + } + private static final int IN_METHOD = 0; + private static final int IN_CLINIT = 1; + private static final int IN_INIT = 2; + + private BugReporter bugReporter; + private Map<String, FieldAnnotation> staticCollectionFields; + private Map<String, FieldAnnotation> instanceCollectionFields; + private Map<Integer, String> staticAliases; + private Map<Integer, String> instanceAliases; + private OpcodeStack stack; + private int state; + + /** + * constructs a NMCS detector given the reporter to report bugs on + * @param bugReporter the sync of bug reports + */ + public NeedlessMemberCollectionSynchronization(BugReporter bugReporter) { + this.bugReporter = bugReporter; + } + + @Override + public void visitClassContext(ClassContext classContext) { + try { + if (collectionClass != null) { + staticCollectionFields = new HashMap<String, FieldAnnotation>(); + instanceCollectionFields = new HashMap<String, FieldAnnotation>(); + staticAliases = new HashMap<Integer, String>(); + instanceAliases = new HashMap<Integer, String>(); + stack = new OpcodeStack(); + super.visitClassContext(classContext); + } + } finally { + staticCollectionFields = null; + instanceCollectionFields = null; + staticAliases = null; + instanceAliases = null; + stack = null; + } + } + + @Override + public void visitField(Field obj) { + if (obj.isPrivate()) { + String signature = obj.getSignature(); + if (signature.charAt(0) == 'L') { + try { + JavaClass cls = Repository.lookupClass(signature); + if (cls.implementationOf(collectionClass)) { + FieldAnnotation fa = FieldAnnotation.fromVisitedField(this); + if (obj.isStatic()) + staticCollectionFields.put(fa.getFieldName(), fa); + else + instanceCollectionFields.put(fa.getFieldName(), fa); + } + } catch (ClassNotFoundException cnfe) { + bugReporter.reportMissingClass(cnfe); + } + } + } + } + + @Override + public void visitCode(Code obj) { + if ((staticCollectionFields.size() + instanceCollectionFields.size()) > 0) { + staticAliases.clear(); + instanceAliases.clear(); + String methodName = getMethodName(); + if ("<clinit>".equals(methodName)) + state = IN_CLINIT; + else if ("<init>".equals(methodName)) + state = IN_INIT; + else + state = IN_METHOD; + stack.resetForMethodEntry(this); + super.visitCode(obj); + } + } + + @Override + public void sawOpcode(int seen) { + switch (state) { + case IN_CLINIT: + sawCLInitOpcode(seen); + break; + + case IN_INIT: + sawInitOpcode(seen); + break; + + case IN_METHOD: + sawMethodOpcode(seen); + } + } + + private void sawCLInitOpcode(int seen) { + boolean isSyncCollection = false; + try { + stack.mergeJumps(this); + isSyncCollection = isSyncCollectionCreation(seen); + } finally { + stack.sawOpcode(this, seen); + if (isSyncCollection) { + if (stack.getStackDepth() > 0) { + OpcodeStack.Item item = stack.getStackItem(0); + item.setUserValue(Boolean.TRUE); + } + } + } + } + + private void sawInitOpcode(int seen) { + boolean isSyncCollection = false; + try { + stack.mergeJumps(this); + isSyncCollection = isSyncCollectionCreation(seen); + } finally { + stack.sawOpcode(this, seen); + if (isSyncCollection) { + if (stack.getStackDepth() > 0) { + OpcodeStack.Item item = stack.getStackItem(0); + item.setUserValue(Boolean.TRUE); + } + } + } + } + + private void sawMethodOpcode(int seen) { + try { + stack.mergeJumps(this); + if (isSyncCollectionCreation(seen)) { + + } + } finally { + stack.sawOpcode(this, seen); + } + + } + + private boolean isSyncCollectionCreation(int seen) { + if (seen == INVOKESPECIAL) { + if ("<init>".equals(getNameConstantOperand())) { + return (syncCollections.contains(getClassConstantOperand())); + } + } else if (seen == INVOKESTATIC) { + String methodName = getNameConstantOperand(); + return "java/util/Collections".equals(getClassConstantOperand()) + && ("synchronizedMap".equals(methodName) || "synchronizedSet".equals(methodName)); + } + return false; + } +} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dbr...@us...> - 2006-05-09 07:09:11
|
Revision: 521 Author: dbrosius Date: 2006-05-09 00:08:59 -0700 (Tue, 09 May 2006) ViewCVS: http://svn.sourceforge.net/fb-contrib/?rev=521&view=rev Log Message: ----------- collect srcline annotations for creations of sync'ed collections Modified Paths: -------------- trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/NeedlessMemberCollectionSynchronization.java Modified: trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/NeedlessMemberCollectionSynchronization.java =================================================================== --- trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/NeedlessMemberCollectionSynchronization.java 2006-05-09 06:48:21 UTC (rev 520) +++ trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/NeedlessMemberCollectionSynchronization.java 2006-05-09 07:08:59 UTC (rev 521) @@ -32,6 +32,7 @@ import edu.umd.cs.findbugs.BytecodeScanningDetector; import edu.umd.cs.findbugs.FieldAnnotation; import edu.umd.cs.findbugs.OpcodeStack; +import edu.umd.cs.findbugs.SourceLineAnnotation; import edu.umd.cs.findbugs.ba.ClassContext; /** @@ -64,6 +65,7 @@ private Map<Integer, String> instanceAliases; private OpcodeStack stack; private int state; + private String className; /** * constructs a NMCS detector given the reporter to report bugs on @@ -82,6 +84,8 @@ staticAliases = new HashMap<Integer, String>(); instanceAliases = new HashMap<Integer, String>(); stack = new OpcodeStack(); + JavaClass cls = classContext.getJavaClass(); + className = cls.getClassName(); super.visitClassContext(classContext); } } finally { @@ -152,6 +156,9 @@ try { stack.mergeJumps(this); isSyncCollection = isSyncCollectionCreation(seen); + if (seen == PUTFIELD) { + processCollectionStore(PUTSTATIC, seen); + } } finally { stack.sawOpcode(this, seen); if (isSyncCollection) { @@ -168,6 +175,8 @@ try { stack.mergeJumps(this); isSyncCollection = isSyncCollectionCreation(seen); + processCollectionStore(PUTFIELD, seen); + } finally { stack.sawOpcode(this, seen); if (isSyncCollection) { @@ -203,4 +212,28 @@ } return false; } + + private void processCollectionStore(int fieldOp, int seen) { + if (seen == fieldOp) { + String fieldClassName = getClassConstantOperand(); + String fieldName = getNameConstantOperand(); + if (fieldClassName.equals(className)) { + if (stack.getStackDepth() > 0) { + OpcodeStack.Item item = stack.getStackItem(0); + if (item.getUserValue() != null) { + Map<String, FieldAnnotation> fields; + if (fieldOp == PUTFIELD) + fields = instanceCollectionFields; + else + fields = staticCollectionFields; + + FieldAnnotation fa = fields.get(fieldName); + if (fa != null) { + fa.setSourceLines(SourceLineAnnotation.fromVisitedInstruction(this)); + } + } + } + } + } + } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dbr...@us...> - 2006-05-09 07:41:18
|
Revision: 524 Author: dbrosius Date: 2006-05-09 00:41:02 -0700 (Tue, 09 May 2006) ViewCVS: http://svn.sourceforge.net/fb-contrib/?rev=524&view=rev Log Message: ----------- a lil more... far from done Modified Paths: -------------- trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/NeedlessMemberCollectionSynchronization.java Modified: trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/NeedlessMemberCollectionSynchronization.java =================================================================== --- trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/NeedlessMemberCollectionSynchronization.java 2006-05-09 07:25:51 UTC (rev 523) +++ trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/NeedlessMemberCollectionSynchronization.java 2006-05-09 07:41:02 UTC (rev 524) @@ -156,9 +156,7 @@ try { stack.mergeJumps(this); isSyncCollection = isSyncCollectionCreation(seen); - if (seen == PUTFIELD) { - processCollectionStore(PUTSTATIC, seen); - } + processCollectionStore(PUTSTATIC, seen); } finally { stack.sawOpcode(this, seen); if (isSyncCollection) { @@ -176,7 +174,6 @@ stack.mergeJumps(this); isSyncCollection = isSyncCollectionCreation(seen); processCollectionStore(PUTFIELD, seen); - } finally { stack.sawOpcode(this, seen); if (isSyncCollection) { @@ -191,9 +188,9 @@ private void sawMethodOpcode(int seen) { try { stack.mergeJumps(this); - if (isSyncCollectionCreation(seen)) { - - } + + //look for code that alters the collection, passes it to a method, returns it, etc + //watch out for aliases } finally { stack.sawOpcode(this, seen); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dbr...@us...> - 2006-05-10 03:07:25
|
Revision: 525 Author: dbrosius Date: 2006-05-09 20:07:18 -0700 (Tue, 09 May 2006) ViewCVS: http://svn.sourceforge.net/fb-contrib/?rev=525&view=rev Log Message: ----------- start reporting bugs... it is now way to liberal and reports many false positives. No aliases checking yet. Modified Paths: -------------- trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/NeedlessMemberCollectionSynchronization.java Modified: trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/NeedlessMemberCollectionSynchronization.java =================================================================== --- trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/NeedlessMemberCollectionSynchronization.java 2006-05-09 07:41:02 UTC (rev 524) +++ trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/NeedlessMemberCollectionSynchronization.java 2006-05-10 03:07:18 UTC (rev 525) @@ -27,7 +27,9 @@ import org.apache.bcel.classfile.Code; import org.apache.bcel.classfile.Field; import org.apache.bcel.classfile.JavaClass; +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.FieldAnnotation; @@ -54,6 +56,29 @@ syncCollections.add("java/util/Vector"); syncCollections.add("java/util/Hashtable"); } + private static Set<String> modifyingMethods = new HashSet<String>(); + static { + modifyingMethods.add("add"); + modifyingMethods.add("addAll"); + modifyingMethods.add("addFirst"); + modifyingMethods.add("addElement"); + modifyingMethods.add("addLast"); + modifyingMethods.add("clear"); + modifyingMethods.add("insertElementAt"); + modifyingMethods.add("put"); + modifyingMethods.add("remove"); + modifyingMethods.add("removeAll"); + modifyingMethods.add("removeAllElements"); + modifyingMethods.add("removeElement"); + modifyingMethods.add("removeElementAt"); + modifyingMethods.add("removeFirst"); + modifyingMethods.add("removeLast"); + modifyingMethods.add("removeRange"); + modifyingMethods.add("retainAll"); + modifyingMethods.add("set"); + modifyingMethods.add("setElementAt"); + modifyingMethods.add("setSize"); + } private static final int IN_METHOD = 0; private static final int IN_CLINIT = 1; private static final int IN_INIT = 2; @@ -87,6 +112,17 @@ JavaClass cls = classContext.getJavaClass(); className = cls.getClassName(); super.visitClassContext(classContext); + for (FieldAnnotation fa : staticCollectionFields.values()) { + bugReporter.reportBug(new BugInstance(this, "NMCS_NEEDLESS_MEMBER_COLLECTION_SYNCHRONIZATION", NORMAL_PRIORITY) + .addClass(this) + .addField(fa)); + } + for (FieldAnnotation fa : instanceCollectionFields.values()) { + bugReporter.reportBug(new BugInstance(this, "NMCS_NEEDLESS_MEMBER_COLLECTION_SYNCHRONIZATION", NORMAL_PRIORITY) + .addClass(this) + .addField(fa)); + } + } } finally { staticCollectionFields = null; @@ -189,6 +225,56 @@ try { stack.mergeJumps(this); + switch (seen) { + case INVOKEVIRTUAL: + case INVOKEINTERFACE: + String methodName = getNameConstantOperand(); + if (modifyingMethods.contains(methodName)) { + String signature = getSigConstantOperand(); + int parmCount = Type.getArgumentTypes(signature).length; + if (stack.getStackDepth() > parmCount) { + OpcodeStack.Item item = stack.getStackItem(parmCount); + FieldAnnotation fa = item.getField(); + if (fa != null) { + if (fa.isStatic()) + staticCollectionFields.remove(fa.getFieldName()); + else + instanceCollectionFields.remove(fa.getFieldName()); + } else { + int reg = item.getRegisterNumber(); + if (reg >= 0) { + Integer register = new Integer(reg); + String fName = staticAliases.get(register); + if (fName != null) { + staticCollectionFields.remove(fName); + staticAliases.remove(register); + } else { + fName = instanceAliases.get(register); + if (fName != null) { + instanceCollectionFields.remove(fName); + instanceAliases.remove(register); + } + } + } + } + } + } + break; + + case ARETURN: + if (stack.getStackDepth() > 0) { + OpcodeStack.Item item = stack.getStackItem(0); + FieldAnnotation fa = item.getField(); + if (fa != null) { + if (fa.isStatic()) + staticCollectionFields.remove(fa.getFieldName()); + else + instanceCollectionFields.remove(fa.getFieldName()); + } + } + break; + } + //look for code that alters the collection, passes it to a method, returns it, etc //watch out for aliases } finally { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dbr...@us...> - 2006-05-10 03:12:50
|
Revision: 526 Author: dbrosius Date: 2006-05-09 20:12:34 -0700 (Tue, 09 May 2006) ViewCVS: http://svn.sourceforge.net/fb-contrib/?rev=526&view=rev Log Message: ----------- don't report fields that don't have sourcelines. These collections haven't been checked to see that they are actually synchronized. Modified Paths: -------------- trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/NeedlessMemberCollectionSynchronization.java Modified: trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/NeedlessMemberCollectionSynchronization.java =================================================================== --- trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/NeedlessMemberCollectionSynchronization.java 2006-05-10 03:07:18 UTC (rev 525) +++ trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/NeedlessMemberCollectionSynchronization.java 2006-05-10 03:12:34 UTC (rev 526) @@ -113,14 +113,18 @@ className = cls.getClassName(); super.visitClassContext(classContext); for (FieldAnnotation fa : staticCollectionFields.values()) { - bugReporter.reportBug(new BugInstance(this, "NMCS_NEEDLESS_MEMBER_COLLECTION_SYNCHRONIZATION", NORMAL_PRIORITY) - .addClass(this) - .addField(fa)); + if (fa.getSourceLines() != null) { + bugReporter.reportBug(new BugInstance(this, "NMCS_NEEDLESS_MEMBER_COLLECTION_SYNCHRONIZATION", NORMAL_PRIORITY) + .addClass(this) + .addField(fa)); + } } for (FieldAnnotation fa : instanceCollectionFields.values()) { - bugReporter.reportBug(new BugInstance(this, "NMCS_NEEDLESS_MEMBER_COLLECTION_SYNCHRONIZATION", NORMAL_PRIORITY) - .addClass(this) - .addField(fa)); + if (fa.getSourceLines() != null) { + bugReporter.reportBug(new BugInstance(this, "NMCS_NEEDLESS_MEMBER_COLLECTION_SYNCHRONIZATION", NORMAL_PRIORITY) + .addClass(this) + .addField(fa)); + } } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dbr...@us...> - 2006-05-10 03:24:59
|
Revision: 527 Author: dbrosius Date: 2006-05-09 20:24:54 -0700 (Tue, 09 May 2006) ViewCVS: http://svn.sourceforge.net/fb-contrib/?rev=527&view=rev Log Message: ----------- no need to differentiate static from instance collections Modified Paths: -------------- trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/NeedlessMemberCollectionSynchronization.java Modified: trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/NeedlessMemberCollectionSynchronization.java =================================================================== --- trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/NeedlessMemberCollectionSynchronization.java 2006-05-10 03:12:34 UTC (rev 526) +++ trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/NeedlessMemberCollectionSynchronization.java 2006-05-10 03:24:54 UTC (rev 527) @@ -53,8 +53,8 @@ } private static Set<String> syncCollections = new HashSet<String>(); static { - syncCollections.add("java/util/Vector"); - syncCollections.add("java/util/Hashtable"); + syncCollections.add("java.util.Vector"); + syncCollections.add("java.util.Hashtable"); } private static Set<String> modifyingMethods = new HashSet<String>(); static { @@ -84,10 +84,8 @@ private static final int IN_INIT = 2; private BugReporter bugReporter; - private Map<String, FieldAnnotation> staticCollectionFields; - private Map<String, FieldAnnotation> instanceCollectionFields; - private Map<Integer, String> staticAliases; - private Map<Integer, String> instanceAliases; + private Map<String, FieldAnnotation> collectionFields; + private Map<Integer, String> aliases; private OpcodeStack stack; private int state; private String className; @@ -104,35 +102,23 @@ public void visitClassContext(ClassContext classContext) { try { if (collectionClass != null) { - staticCollectionFields = new HashMap<String, FieldAnnotation>(); - instanceCollectionFields = new HashMap<String, FieldAnnotation>(); - staticAliases = new HashMap<Integer, String>(); - instanceAliases = new HashMap<Integer, String>(); + collectionFields = new HashMap<String, FieldAnnotation>(); + aliases = new HashMap<Integer, String>(); stack = new OpcodeStack(); JavaClass cls = classContext.getJavaClass(); className = cls.getClassName(); super.visitClassContext(classContext); - for (FieldAnnotation fa : staticCollectionFields.values()) { + for (FieldAnnotation fa : collectionFields.values()) { if (fa.getSourceLines() != null) { bugReporter.reportBug(new BugInstance(this, "NMCS_NEEDLESS_MEMBER_COLLECTION_SYNCHRONIZATION", NORMAL_PRIORITY) .addClass(this) .addField(fa)); } } - for (FieldAnnotation fa : instanceCollectionFields.values()) { - if (fa.getSourceLines() != null) { - bugReporter.reportBug(new BugInstance(this, "NMCS_NEEDLESS_MEMBER_COLLECTION_SYNCHRONIZATION", NORMAL_PRIORITY) - .addClass(this) - .addField(fa)); - } - } - } } finally { - staticCollectionFields = null; - instanceCollectionFields = null; - staticAliases = null; - instanceAliases = null; + collectionFields = null; + aliases = null; stack = null; } } @@ -146,10 +132,7 @@ JavaClass cls = Repository.lookupClass(signature.substring(1, signature.length() - 1)); if (cls.implementationOf(collectionClass)) { FieldAnnotation fa = FieldAnnotation.fromVisitedField(this); - if (obj.isStatic()) - staticCollectionFields.put(fa.getFieldName(), fa); - else - instanceCollectionFields.put(fa.getFieldName(), fa); + collectionFields.put(fa.getFieldName(), fa); } } catch (ClassNotFoundException cnfe) { bugReporter.reportMissingClass(cnfe); @@ -160,9 +143,8 @@ @Override public void visitCode(Code obj) { - if ((staticCollectionFields.size() + instanceCollectionFields.size()) > 0) { - staticAliases.clear(); - instanceAliases.clear(); + if (collectionFields.size() > 0) { + aliases.clear(); String methodName = getMethodName(); if ("<clinit>".equals(methodName)) state = IN_CLINIT; @@ -240,24 +222,15 @@ OpcodeStack.Item item = stack.getStackItem(parmCount); FieldAnnotation fa = item.getField(); if (fa != null) { - if (fa.isStatic()) - staticCollectionFields.remove(fa.getFieldName()); - else - instanceCollectionFields.remove(fa.getFieldName()); + collectionFields.remove(fa.getFieldName()); } else { int reg = item.getRegisterNumber(); if (reg >= 0) { Integer register = new Integer(reg); - String fName = staticAliases.get(register); + String fName = aliases.get(register); if (fName != null) { - staticCollectionFields.remove(fName); - staticAliases.remove(register); - } else { - fName = instanceAliases.get(register); - if (fName != null) { - instanceCollectionFields.remove(fName); - instanceAliases.remove(register); - } + collectionFields.remove(fName); + aliases.remove(register); } } } @@ -270,10 +243,7 @@ OpcodeStack.Item item = stack.getStackItem(0); FieldAnnotation fa = item.getField(); if (fa != null) { - if (fa.isStatic()) - staticCollectionFields.remove(fa.getFieldName()); - else - instanceCollectionFields.remove(fa.getFieldName()); + collectionFields.remove(fa.getFieldName()); } } break; @@ -308,13 +278,7 @@ if (stack.getStackDepth() > 0) { OpcodeStack.Item item = stack.getStackItem(0); if (item.getUserValue() != null) { - Map<String, FieldAnnotation> fields; - if (fieldOp == PUTFIELD) - fields = instanceCollectionFields; - else - fields = staticCollectionFields; - - FieldAnnotation fa = fields.get(fieldName); + FieldAnnotation fa = collectionFields.get(fieldName); if (fa != null) { fa.setSourceLines(SourceLineAnnotation.fromVisitedInstruction(this)); } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dbr...@us...> - 2006-05-10 04:20:19
|
Revision: 528 Author: dbrosius Date: 2006-05-09 21:20:11 -0700 (Tue, 09 May 2006) ViewCVS: http://svn.sourceforge.net/fb-contrib/?rev=528&view=rev Log Message: ----------- relying on getSourceLines being non null to signify a synchronied collection is both brittle and just plain wrong, as getSourceLines generates one, whether or not it was set. So use a first class class to hold this info. Modified Paths: -------------- trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/NeedlessMemberCollectionSynchronization.java Modified: trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/NeedlessMemberCollectionSynchronization.java =================================================================== --- trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/NeedlessMemberCollectionSynchronization.java 2006-05-10 03:24:54 UTC (rev 527) +++ trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/NeedlessMemberCollectionSynchronization.java 2006-05-10 04:20:11 UTC (rev 528) @@ -51,10 +51,18 @@ collectionClass = null; } } + private static JavaClass mapClass; + static { + try { + mapClass = Repository.lookupClass("java/util/Map"); + } catch (ClassNotFoundException cnfe) { + mapClass = null; + } + } private static Set<String> syncCollections = new HashSet<String>(); static { - syncCollections.add("java.util.Vector"); - syncCollections.add("java.util.Hashtable"); + syncCollections.add("java/util/Vector"); + syncCollections.add("java/util/Hashtable"); } private static Set<String> modifyingMethods = new HashSet<String>(); static { @@ -84,7 +92,7 @@ private static final int IN_INIT = 2; private BugReporter bugReporter; - private Map<String, FieldAnnotation> collectionFields; + private Map<String, FieldInfo> collectionFields; private Map<Integer, String> aliases; private OpcodeStack stack; private int state; @@ -101,18 +109,18 @@ @Override public void visitClassContext(ClassContext classContext) { try { - if (collectionClass != null) { - collectionFields = new HashMap<String, FieldAnnotation>(); + if ((collectionClass != null) && (mapClass != null)) { + collectionFields = new HashMap<String, FieldInfo>(); aliases = new HashMap<Integer, String>(); stack = new OpcodeStack(); JavaClass cls = classContext.getJavaClass(); className = cls.getClassName(); super.visitClassContext(classContext); - for (FieldAnnotation fa : collectionFields.values()) { - if (fa.getSourceLines() != null) { + for (FieldInfo fi : collectionFields.values()) { + if (fi.isSynchronized()) { bugReporter.reportBug(new BugInstance(this, "NMCS_NEEDLESS_MEMBER_COLLECTION_SYNCHRONIZATION", NORMAL_PRIORITY) .addClass(this) - .addField(fa)); + .addField(fi.getFieldAnnotation())); } } } @@ -130,9 +138,9 @@ if (signature.charAt(0) == 'L') { try { JavaClass cls = Repository.lookupClass(signature.substring(1, signature.length() - 1)); - if (cls.implementationOf(collectionClass)) { + if (cls.implementationOf(collectionClass) || cls.implementationOf(mapClass)) { FieldAnnotation fa = FieldAnnotation.fromVisitedField(this); - collectionFields.put(fa.getFieldName(), fa); + collectionFields.put(fa.getFieldName(), new FieldInfo(fa)); } } catch (ClassNotFoundException cnfe) { bugReporter.reportMissingClass(cnfe); @@ -178,7 +186,8 @@ try { stack.mergeJumps(this); isSyncCollection = isSyncCollectionCreation(seen); - processCollectionStore(PUTSTATIC, seen); + if (seen == PUTSTATIC) + processCollectionStore(seen); } finally { stack.sawOpcode(this, seen); if (isSyncCollection) { @@ -195,7 +204,8 @@ try { stack.mergeJumps(this); isSyncCollection = isSyncCollectionCreation(seen); - processCollectionStore(PUTFIELD, seen); + if (seen == PUTFIELD) + processCollectionStore(seen); } finally { stack.sawOpcode(this, seen); if (isSyncCollection) { @@ -270,21 +280,42 @@ return false; } - private void processCollectionStore(int fieldOp, int seen) { - if (seen == fieldOp) { - String fieldClassName = getClassConstantOperand(); - String fieldName = getNameConstantOperand(); - if (fieldClassName.equals(className)) { - if (stack.getStackDepth() > 0) { - OpcodeStack.Item item = stack.getStackItem(0); - if (item.getUserValue() != null) { - FieldAnnotation fa = collectionFields.get(fieldName); - if (fa != null) { - fa.setSourceLines(SourceLineAnnotation.fromVisitedInstruction(this)); - } + private void processCollectionStore(int seen) { + String fieldClassName = getClassConstantOperand(); + String fieldName = getNameConstantOperand(); + if (fieldClassName.equals(className)) { + if (stack.getStackDepth() > 0) { + OpcodeStack.Item item = stack.getStackItem(0); + if (item.getUserValue() != null) { + FieldInfo fi = collectionFields.get(fieldName); + if (fi != null) { + fi.getFieldAnnotation().setSourceLines(SourceLineAnnotation.fromVisitedInstruction(this)); + fi.setSynchronized(); } } } } } + + static class FieldInfo { + private FieldAnnotation fieldAnnotation; + private boolean isSynchronized; + + public FieldInfo(FieldAnnotation fa) { + fieldAnnotation = fa; + isSynchronized = false; + } + + public void setSynchronized() { + isSynchronized = true; + } + + public FieldAnnotation getFieldAnnotation() { + return fieldAnnotation; + } + + public boolean isSynchronized() { + return isSynchronized; + } + } } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dbr...@us...> - 2006-05-11 23:33:09
|
Revision: 531 Author: dbrosius Date: 2006-05-11 16:32:58 -0700 (Thu, 11 May 2006) ViewCVS: http://svn.sourceforge.net/fb-contrib/?rev=531&view=rev Log Message: ----------- fix compare of dotted vs. slashed full classnames Modified Paths: -------------- trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/NeedlessMemberCollectionSynchronization.java Modified: trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/NeedlessMemberCollectionSynchronization.java =================================================================== --- trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/NeedlessMemberCollectionSynchronization.java 2006-05-11 04:43:40 UTC (rev 530) +++ trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/NeedlessMemberCollectionSynchronization.java 2006-05-11 23:32:58 UTC (rev 531) @@ -296,7 +296,7 @@ } private void processCollectionStore(int seen) { - String fieldClassName = getClassConstantOperand(); + String fieldClassName = getDottedClassConstantOperand(); String fieldName = getNameConstantOperand(); if (fieldClassName.equals(className)) { if (stack.getStackDepth() > 0) { This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dbr...@us...> - 2006-05-15 02:06:58
|
Revision: 534 Author: dbrosius Date: 2006-05-14 19:06:52 -0700 (Sun, 14 May 2006) ViewCVS: http://svn.sourceforge.net/fb-contrib/?rev=534&view=rev Log Message: ----------- javadoc Modified Paths: -------------- trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/NeedlessMemberCollectionSynchronization.java Modified: trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/NeedlessMemberCollectionSynchronization.java =================================================================== --- trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/NeedlessMemberCollectionSynchronization.java 2006-05-12 04:39:51 UTC (rev 533) +++ trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/NeedlessMemberCollectionSynchronization.java 2006-05-15 02:06:52 UTC (rev 534) @@ -106,6 +106,12 @@ this.bugReporter = bugReporter; } + /** + * implements the visitor to clear the collectionFields and stack + * and to report collections that remain unmodified out of clinit or init + * + * @param classContext the context object of the currently parsed class + */ @Override public void visitClassContext(ClassContext classContext) { try { @@ -131,6 +137,11 @@ } } + /** + * implements the visitor to find collection fields + * + * @param obj the context object of the currently parse field + */ @Override public void visitField(Field obj) { if (obj.isPrivate()) { @@ -149,6 +160,11 @@ } } + /** + * implements the visitor to set the state based on the type of method being parsed + * + * @param obj the context object of the currently parsed code block + */ @Override public void visitCode(Code obj) { if (collectionFields.size() > 0) { @@ -165,6 +181,11 @@ } } + /** + * implements the visitor to call the approriate visitor based on state + * + * @param seen the opcode of the currently parsed instruction + */ @Override public void sawOpcode(int seen) { switch (state) { @@ -182,6 +203,12 @@ } } + /** + * handle <clinit> blocks by looking for putstatic calls referencing + * synchronized collections + * + * @param seen the opcode of the currently parsed instruction + */ private void sawCLInitOpcode(int seen) { boolean isSyncCollection = false; try { @@ -200,6 +227,12 @@ } } + /** + * handle <init> blocks by looking for putfield calls referencing + * synchronized collections + * + * @param seen the opcode of the currently parsed instruction + */ private void sawInitOpcode(int seen) { boolean isSyncCollection = false; try { @@ -218,6 +251,12 @@ } } + /** + * handles regular methods by looking for methods on collections that + * are modifying and removes those collections from the ones under review + * + * @param seen the opcode of the currently parsed instruction + */ private void sawMethodOpcode(int seen) { boolean isSyncCollection = false; try { @@ -290,6 +329,12 @@ } + /** + * returns whether this instruction is creating a synchronized collection + * + * @param seen the opcode of the currently parsed instruction + * @return whether a synchronized collection has just been created + */ private boolean isSyncCollectionCreation(int seen) { if (seen == INVOKESPECIAL) { if ("<init>".equals(getNameConstantOperand())) { @@ -303,6 +348,12 @@ return false; } + /** + * sets the source line annotation of a store to a collection if that collection + * is synchronized. + * + * @param seen the opcode of the currently parsed instruction + */ private void processCollectionStore(int seen) { String fieldClassName = getDottedClassConstantOperand(); String fieldName = getNameConstantOperand(); @@ -322,6 +373,10 @@ } } + /** + * holds information about a field, namely the annotation and + * whether the collection is synchronized. + */ static class FieldInfo { private FieldAnnotation fieldAnnotation; private boolean isSynchronized; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dbr...@us...> - 2006-05-16 03:10:57
|
Revision: 537 Author: dbrosius Date: 2006-05-15 20:10:39 -0700 (Mon, 15 May 2006) ViewCVS: http://svn.sourceforge.net/fb-contrib/?rev=537&view=rev Log Message: ----------- don't report NMCS on fields that are passed as parameters to methods in ordinary methods Modified Paths: -------------- trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/NeedlessMemberCollectionSynchronization.java Modified: trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/NeedlessMemberCollectionSynchronization.java =================================================================== --- trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/NeedlessMemberCollectionSynchronization.java 2006-05-15 03:31:05 UTC (rev 536) +++ trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/NeedlessMemberCollectionSynchronization.java 2006-05-16 03:10:39 UTC (rev 537) @@ -288,7 +288,12 @@ } } } + removeCollectionParameters(); break; + + case INVOKESTATIC: + removeCollectionParameters(); + break; case ARETURN: if (stack.getStackDepth() > 0) { @@ -372,6 +377,24 @@ } } } + + /** + * removes collection fields that are passed to other methods as arguments + * + * @param seen the opcode of the currently parsed instruction + */ + private void removeCollectionParameters() { + int parmCount = Type.getArgumentTypes(getSigConstantOperand()).length; + if (stack.getStackDepth() >= parmCount) { + for (int i = 0; i < parmCount; i++) { + OpcodeStack.Item item = stack.getStackItem(i); + FieldAnnotation fa = item.getField(); + if (fa != null) { + collectionFields.remove(fa.getFieldName()); + } + } + } + } /** * holds information about a field, namely the annotation and This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |
From: <dbr...@us...> - 2006-05-17 05:26:52
|
Revision: 543 Author: dbrosius Date: 2006-05-16 22:26:47 -0700 (Tue, 16 May 2006) ViewCVS: http://svn.sourceforge.net/fb-contrib/?rev=543&view=rev Log Message: ----------- use Integer14.valueOf Modified Paths: -------------- trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/NeedlessMemberCollectionSynchronization.java Modified: trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/NeedlessMemberCollectionSynchronization.java =================================================================== --- trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/NeedlessMemberCollectionSynchronization.java 2006-05-17 05:10:55 UTC (rev 542) +++ trunk/fb-contrib/src/com/mebigfatguy/fbcontrib/detect/NeedlessMemberCollectionSynchronization.java 2006-05-17 05:26:47 UTC (rev 543) @@ -29,6 +29,8 @@ import org.apache.bcel.classfile.JavaClass; import org.apache.bcel.generic.Type; +import com.mebigfatguy.fbcontrib.utils.Integer14; + import edu.umd.cs.findbugs.BugInstance; import edu.umd.cs.findbugs.BugReporter; import edu.umd.cs.findbugs.BytecodeScanningDetector; @@ -278,7 +280,7 @@ } else { int reg = item.getRegisterNumber(); if (reg >= 0) { - Integer register = new Integer(reg); + Integer register = Integer14.valueOf(reg); String fName = aliases.get(register); if (fName != null) { collectionFields.remove(fName); This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |