Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * fb-contrib - Auxiliary detectors for Java programs
   * Copyright (C) 2005-2014 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.Map;
 import java.util.Set;
 
 import  org.apache.bcel.Constants;
 import  org.apache.bcel.classfile.Code;
 import  org.apache.bcel.classfile.Method;
 import  org.apache.bcel.generic.Type;
 
 
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
 {
     private static Map<StringIntegersyncCtors = new HashMap<StringInteger>();
     static {
         .put("java/util/Vector", Integer.valueOf(Constants.MAJOR_1_1));
         .put("java/util/Hashtable", Integer.valueOf(Constants.MAJOR_1_1));
         .put("java/lang/StringBuffer", Integer.valueOf(Constants.MAJOR_1_5));
     }
     private static Set<StringsyncMethods = new HashSet<String>();
     static {
         .add("synchronizedCollection");
         .add("synchronizedList");
         .add("synchronizedMap");
         .add("synchronizedSet");
         .add("synchronizedSortedMap");
         .add("synchronizedSortedSet");
     }
     
     private BugReporter bugReporter;
     private OpcodeStack stack;
     private Map<IntegerCollectionRegInfosyncRegs;
     private int classVersion;
    
    
constructs a LSYC detector given the reporter to report bugs on

Parameters:
bugReporter the sync of bug reports
 
     public LocalSynchronizedCollection(BugReporter bugReporter) {
         this. = bugReporter;
     }
    
    
implements the visitor to create and clear the stack and syncRegs

Parameters:
classContext the context object of the currently parsed class
 
     @Override
     public void visitClassContext(ClassContext classContext) {
         try {
              = new OpcodeStack();
              = new HashMap<IntegerCollectionRegInfo>();
              = classContext.getJavaClass().getMajor();
             super.visitClassContext(classContext);
         } finally {
              = null;
              = null;
         }
     }
    
implements the visitor to collect parameter registers

Parameters:
obj the context object of the currently parsed method
    @Override
    public void visitMethod(Method obj) {
        .clear();
        int[] parmRegs = RegisterUtils.getParameterRegisters(obj);
        for (int pr : parmRegs) {
        	.put(Integer.valueOf(pr), 
        				 new CollectionRegInfo(RegisterUtils.getLocalVariableEndRange(obj.getLocalVariableTable(), pr, 0)));
        }
    }
    
    
implements the visitor to reset the stack

Parameters:
obj the context object of the currently parsed code block
    @Override
    public void visitCode(Code obj) {
        .resetForMethodEntry(this);
        super.visitCode(obj);
        
        for (Map.Entry<IntegerCollectionRegInfoentry : .entrySet()) {
            CollectionRegInfo cri = entry.getValue();
            if (!cri.getIgnore()) {
                .reportBug(new BugInstance(this"LSYC_LOCAL_SYNCHRONIZED_COLLECTION"cri.getPriority())
                            .addClass(this)
                            .addMethod(this)
                            .addSourceLine(cri.getSourceLineAnnotation()));
            }
                
        }
    }
    
    
implements the visitor to find stores to locals of synchronized collections

Parameters:
seen the opcode of the currently parsed instruction
    @Override
    public void sawOpcode(int seen) {
        Integer tosIsSyncColReg = null;
        try {
            .precomputation(this);
            
            if (seen == INVOKESPECIAL) {
                if ("<init>".equals(getNameConstantOperand())) {
                	Integer minVersion = .get(getClassConstantOperand());
                	if ((minVersion != null) && ( >= minVersion.intValue())) {
                        tosIsSyncColReg = Integer.valueOf(-1);
                    }
                }
            } else if (seen == INVOKESTATIC) {
                if ("java/util/Collections".equals(getClassConstantOperand())) {
                    if (.contains(getNameConstantOperand())) {
                        tosIsSyncColReg = Integer.valueOf(-1);
                    }
                }
            } else if ((seen == ASTORE) || ((seen >= ASTORE_0) && (seen <= ASTORE_3))) {
                if (.getStackDepth() > 0) {
                    OpcodeStack.Item item = .getStackItem(0);
                    int reg = RegisterUtils.getAStoreReg(thisseen);
                    if (item.getUserValue() != null) {
                        if (!.containsKey(Integer.valueOf(reg))) {
                            CollectionRegInfo cri = new CollectionRegInfo(SourceLineAnnotation.fromVisitedInstruction(this), RegisterUtils.getLocalVariableEndRange(getMethod().getLocalVariableTable(), reggetNextPC()));
                            .put(Integer.valueOf(reg), cri);
                    
                        }
                    } else {
                        CollectionRegInfo cri = .get(Integer.valueOf(reg));
                        if (cri == null) {
                            cri = new CollectionRegInfo(RegisterUtils.getLocalVariableEndRange(getMethod().getLocalVariableTable(), reggetNextPC()));
                            .put(Integer.valueOf(reg), cri);
                        }
                        cri.setIgnore();
                    }
                }
            } else if ((seen == ALOAD) || ((seen >= ALOAD_0) && (seen <= ALOAD_3))) {
                int reg = RegisterUtils.getALoadReg(thisseen);
                CollectionRegInfo cri = .get(Integer.valueOf(reg));
                if ((cri != null) && !cri.getIgnore())
                    tosIsSyncColReg = Integer.valueOf(reg);
            } else if ((seen == PUTFIELD) || (seen == ARETURN)) {
                if (.getStackDepth() > 0) {
                    OpcodeStack.Item item = .getStackItem(0);
                    .remove(item.getUserValue());
                }               
            }       
            
            if (.size() > 0) {
                if ((seen == INVOKESPECIAL)
                ||  (seen == INVOKEINTERFACE)
                ||  (seen == INVOKEVIRTUAL)
                ||  (seen == INVOKESTATIC)) {
                    String sig = getSigConstantOperand();
                    int argCount = Type.getArgumentTypes(sig).length;
                    if (.getStackDepth() >= argCount) {
                        for (int i = 0; i < argCounti++) {
                            OpcodeStack.Item item = .getStackItem(i);
                            CollectionRegInfo cri = .get(item.getUserValue());
                            if (cri != null)
                                cri.setPriority(LOW_PRIORITY);
                        }
                    }
                } else if (seen == MONITORENTER) {
                    //Assume if synchronized blocks are used then something tricky is going on.
                    //There is really no valid reason for this, other than folks who use
                    //synchronized blocks tend to know what's going on.
                    if (.getStackDepth() > 0) {
                        OpcodeStack.Item item = .getStackItem(0);
                        .remove(item.getUserValue());
                    }
                } else if (seen == AASTORE) {
                	if (.getStackDepth() > 0) {
                		OpcodeStack.Item item = .getStackItem(0);
                		.remove(item.getUserValue());
                	}
                }
            }
            
            int curPC = getPC();
            Iterator<CollectionRegInfoit = .values().iterator();
            while (it.hasNext()) {
                CollectionRegInfo cri = it.next();
                if (cri.getEndPCRange() < curPC) {
                    if (!cri.getIgnore()) {
                        .reportBug(new BugInstance(this"LSYC_LOCAL_SYNCHRONIZED_COLLECTION"cri.getPriority())
                                .addClass(this)
                                .addMethod(this)
                                .addSourceLine(cri.getSourceLineAnnotation()));                 
                    }
                    it.remove();
                }
            }
        } finally {
			TernaryPatcher.pre(seen);
			.sawOpcode(thisseen);
			TernaryPatcher.post(seen);
            if (tosIsSyncColReg != null) {
                if (.getStackDepth() > 0) {
                    OpcodeStack.Item item = .getStackItem(0);
                    item.setUserValue(tosIsSyncColReg);
                }
            }
        }
    }
        
    static class CollectionRegInfo
    {
        private SourceLineAnnotation slAnnotation;
        private int priority = HIGH_PRIORITY;
        private int endPCRange = .;
        
        public CollectionRegInfo(SourceLineAnnotation slaint endPC) {
             = sla;
             = endPC;
        }
        
        public CollectionRegInfo(int endPC) {
             = null;
             = endPC;
        }
        
        public SourceLineAnnotation getSourceLineAnnotation() {
            return ;
        }
        
        public void setEndPCRange(int pc) {
             = pc;
        }
        
        public int getEndPCRange() {
            return ;
        }
        
        public void setIgnore() {
             = null;
        }
        
        public boolean getIgnore() {
            return  == null;
        }
        
        public void setPriority(int newPriority) {
            if (newPriority > )
                 = newPriority;
        }
        
        public int getPriority() {
            return ;
        }
    }
New to GrepCode? Check out our FAQ X