Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * fb-contrib - Auxiliary detectors for Java programs
   * Copyright (C) 2005-2013 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;
 
 
 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.ba.ClassContext;

looks for methods that are implemented using synchronized blocks, but are overly synchronized because the beginning of the block only accesses local variables, and not member variables, or this.
 
 public class BloatedSynchronizedBlock extends BytecodeScanningDetector
 {
 	private final BugReporter bugReporter;
 	private static final String BSB_MIN_SAFE_CODE_SIZE = "fb-contrib.bsb.minsize";
 	private OpcodeStack stack;
 	private Set<IntegerunsafeAliases;
 	private Map<IntegerIntegerbranchInfo;
 	private int syncPC;
 	private boolean isStatic;
 	private final int minSafeCodeLength;
 	private boolean unsafeCallOccurred;

    
constructs a BSB detector given the reporter to report bugs on

Parameters:
bugReporter the sync of bug reports
 		
 	public BloatedSynchronizedBlock(BugReporter bugReporter) {
 		this. = bugReporter;
 	}
 	
 	public void visitClassContext(ClassContext classContext) {
 		try {
 			 = new OpcodeStack();
 			super.visitClassContext(classContext);
 		} finally {
 			 = null;
 			 = null;
 			 = null;
 		}
 	}

looks for methods that contain a MONITORENTER opcodes

Parameters:
method the context object of the current method
Returns:
if the class uses synchronization
 
 	public boolean prescreen(Method method) {
 		BitSet bytecodeSet = getClassContext().getBytecodeSet(method);
 		return (bytecodeSet != null) && (bytecodeSet.get(Constants.MONITORENTER));
 	}

implement the visitor to reset the sync count, the stack, and gather some information

Parameters:
obj the context object for the currently parsed method
 
 	public void visitCode(Code obj) {
 		Method m = getMethod();
		if (prescreen(m)) {
			if (m.isSynchronized())
				 = 0;
			else
				 = -1;
			 = m.isStatic();
			.resetForMethodEntry(this);
		}
	}

implement the visitor to find bloated sync blocks. This implementation only checks the outer most block

Parameters:
seen the opcode of the currently parsed instruction
	public void sawOpcode(int seen) {
		try {
			.mergeJumps(this);
			if ( && ((seen == ASTORE) || ((seen >= ASTORE_0) && (seen <= ASTORE_3)))) {
				int storeReg = RegisterUtils.getAStoreReg(thisseen);
				if (storeReg >= 0)
					.add(Integer.valueOf(storeReg));
			}
			if ((seen == INVOKEVIRTUAL)
			||  (seen == INVOKESPECIAL)
			||  (seen == INVOKEINTERFACE)) {
				String methodSig = getSigConstantOperand();
				Type returnType = Type.getReturnType(methodSig);
				if (!(returnType.equals(Type.VOID))) {
					int parmCount = Type.getArgumentTypes(methodSig).length;
					if (.getStackDepth() > parmCount) {
						OpcodeStack.Item itm = .getStackItem(parmCount);
						 = .contains(Integer.valueOf(itm.getRegisterNumber()));
else
else
else if (seen == INVOKESTATIC)
                 = (getDottedClassConstantOperand().equals(this.getClassContext().getJavaClass().getClassName()));
			else if (((seen >= IFEQ) && (seen <= GOTO)) || (seen == GOTO_W))
			{
				Integer from = Integer.valueOf(getPC());
				Integer to = Integer.valueOf(getBranchTarget());
				.put(fromto);
			}
			else
			if (seen == MONITORENTER) {
				if ( < 0) {
					if (.getStackDepth() > 0) {
						OpcodeStack.Item itm = .getStackItem(0);
						int monitorReg = itm.getRegisterNumber();
						if (monitorReg >= 0) {
							.add(Integer.valueOf(monitorReg));
					}
				}
			}
			else if (seen == MONITOREXIT)
				 = -1;
			else if ( >= 0) {
				//TODO: probably static calls are unsafe only if the monitor is on a static
				boolean unsafe = ;
				unsafe |= ((seen == PUTFIELD) || (seen == GETFIELD) || (seen == GETSTATIC)  || (seen == PUTSTATIC));
				unsafe |= (!) && ((seen == ALOAD_0) || (seen == ASTORE_0));
				int aloadReg = RegisterUtils.getALoadReg(thisseen);
				unsafe |= (aloadReg >= 0) && .contains(Integer.valueOf(aloadReg));
				if (unsafe) {
					//If a branch exists in the safe code, make sure the entire branch
					//is in the safe code, otherwise trim before the branch
					int pc = getPC();
					if ((pc - ) > ) {
						for (Map.Entry<IntegerIntegerentry : .entrySet()) {
							int bStart = entry.getKey().intValue();
							if ((bStart >= ) && (bStart <= pc)) {
								int bEnd = entry.getValue().intValue();
								if (bEnd > pc) {
									pc = bStart - 1;
								}
							}
						}
						if ((pc - ) > ) {
							.reportBug(new BugInstance(this"BSB_BLOATED_SYNCHRONIZED_BLOCK", NORMAL_PRIORITY)
											.addClass(this)
											.addMethod(this)
											.addSourceLineRange(this + 1, pc));
						}
					}
					 = -1;
				}
			}
finally {
			.sawOpcode(thisseen);
		}
	}
New to GrepCode? Check out our FAQ X