/*
* FindBugs - Find bugs in Java programs
* Copyright (C) 2004-2006 University of Maryland
*
* 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 edu.umd.cs.findbugs.detect;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Pattern;
import org.apache.bcel.classfile.Code;
import edu.umd.cs.findbugs.BugAccumulator;
import edu.umd.cs.findbugs.BugInstance;
import edu.umd.cs.findbugs.BugReporter;
import edu.umd.cs.findbugs.OpcodeStack;
import edu.umd.cs.findbugs.SourceLineAnnotation;
import edu.umd.cs.findbugs.StringAnnotation;
import edu.umd.cs.findbugs.ba.AnalysisContext;
import edu.umd.cs.findbugs.ba.FieldSummary;
import edu.umd.cs.findbugs.ba.XField;
import edu.umd.cs.findbugs.ba.XMethod;
import edu.umd.cs.findbugs.bcel.OpcodeStackDetector;
public class SynchronizationOnSharedBuiltinConstant extends OpcodeStackDetector {
final Set<String> badSignatures;
final BugAccumulator bugAccumulator;
public SynchronizationOnSharedBuiltinConstant(BugReporter bugReporter) {
this.bugAccumulator = new BugAccumulator(bugReporter);
badSignatures = new HashSet<String>();
badSignatures.addAll(Arrays.asList(new String[] { "Ljava/lang/Boolean;", "Ljava/lang/Double;", "Ljava/lang/Float;",
"Ljava/lang/Byte;", "Ljava/lang/Character;", "Ljava/lang/Short;", "Ljava/lang/Integer;", "Ljava/lang/Long;" }));
}
private static boolean newlyConstructedObject(OpcodeStack.Item item) {
XMethod method = item.getReturnValueOf();
if (method == null)
return false;
return method.getName().equals("<init>");
}
private static final Pattern identified = Pattern.compile("\\p{Alnum}+");
BugInstance pendingBug;
int monitorEnterPC;
String syncSignature;
boolean isSyncOnBoolean;
@Override
public void visit(Code obj) {
super.visit(obj);
accumulateBug();
bugAccumulator.reportAccumulatedBugs();
}
@Override
public void sawOpcode(int seen) {
switch (seen) {
case MONITORENTER:
OpcodeStack.Item top = stack.getStackItem(0);
if (pendingBug != null) {
accumulateBug();
}
monitorEnterPC = getPC();
syncSignature = top.getSignature();
isSyncOnBoolean = false;
Object constant = top.getConstant();
if (syncSignature.equals("Ljava/lang/String;") && constant instanceof String) {
pendingBug = new BugInstance(this, "DL_SYNCHRONIZATION_ON_SHARED_CONSTANT", NORMAL_PRIORITY)
.addClassAndMethod(this);
String value = (String) constant;
if (identified.matcher(value).matches())
pendingBug.addString(value).describe(StringAnnotation.STRING_CONSTANT_ROLE);
} else if (badSignatures.contains(syncSignature)) {
isSyncOnBoolean = syncSignature.equals("Ljava/lang/Boolean;");
XField field = top.getXField();
FieldSummary fieldSummary = AnalysisContext.currentAnalysisContext().getFieldSummary();
OpcodeStack.Item summary = fieldSummary.getSummary(field);
int priority = NORMAL_PRIORITY;
if (isSyncOnBoolean)
priority--;
if (newlyConstructedObject(summary))
pendingBug = new BugInstance(this, "DL_SYNCHRONIZATION_ON_UNSHARED_BOXED_PRIMITIVE", NORMAL_PRIORITY)
.addClassAndMethod(this).addType(syncSignature).addOptionalField(field)
.addOptionalLocalVariable(this, top);
else if (isSyncOnBoolean)
pendingBug = new BugInstance(this, "DL_SYNCHRONIZATION_ON_BOOLEAN", priority).addClassAndMethod(this)
.addOptionalField(field).addOptionalLocalVariable(this, top);
else
pendingBug = new BugInstance(this, "DL_SYNCHRONIZATION_ON_BOXED_PRIMITIVE", priority).addClassAndMethod(this)
.addType(syncSignature).addOptionalField(field).addOptionalLocalVariable(this, top);
}
break;
case MONITOREXIT:
accumulateBug();
break;
}
}
/**
*
*/
private void accumulateBug() {
if (pendingBug == null)
return;
bugAccumulator.accumulateBug(pendingBug, SourceLineAnnotation.fromVisitedInstruction(this, monitorEnterPC));
pendingBug = null;
}
}