@Override
public void reportMatch(ClassContext classContext, Method method, ByteCodePatternMatch match) throws CFGBuilderException,
DataflowAnalysisException {
JavaClass javaClass = classContext.getJavaClass();
MethodGen methodGen = classContext.getMethodGen(method);
CFG cfg = classContext.getCFG(method);
// Get the variable referenced in the pattern instance.
BindingSet bindingSet = match.getBindingSet();
Binding binding = bindingSet.lookup("f");
// Look up the field as an XField.
// If it is volatile, then the instance is not a bug.
FieldVariable field = (FieldVariable) binding.getVariable();
XField xfield = Hierarchy.findXField(field.getClassName(), field.getFieldName(), field.getFieldSig(),
field.isStatic());
if (!xfield.isResolved()) {
return;
}
// XXX: for now, ignore lazy initialization of instance fields
if (!xfield.isStatic()) {
return;
}
// Definitely ignore synthetic class$ fields
if (xfield.getName().startsWith("class$") || xfield.getName().startsWith("array$")) {
if (DEBUG) {
System.out.println("Ignoring field " + xfield.getName());
}
return;
}
// Ignore non-reference fields
String signature = xfield.getSignature();
if (!signature.startsWith("[") && !signature.startsWith("L")) {
if (DEBUG) {
System.out.println("Ignoring non-reference field " + xfield.getName());
}
return;
}
// Strings are (mostly) safe to pass by data race in 1.5
if (signature.equals("Ljava/lang/String;")) {
return;
}
// GUI types should not be accessed from multiple threads
if (signature.charAt(0) == 'L') {
ClassDescriptor fieldType = DescriptorFactory.createClassDescriptorFromFieldSignature(signature);
while (fieldType != null) {
XClass fieldClass;
try {
fieldClass = Global.getAnalysisCache().getClassAnalysis(XClass.class, fieldType);
} catch (CheckedAnalysisException e) {
break;
}
String name = fieldClass.getClassDescriptor().getClassName();
if (name.startsWith("java/awt") || name.startsWith("javax/swing")) {
return;
}
if (name.equals("java/lang/Object")) {
break;
}
fieldType = fieldClass.getSuperclassDescriptor();
}
}
// Get locations matching the beginning of the object creation,
// and the final field store.
PatternElementMatch createBegin = match.getFirstLabeledMatch("createObject");
PatternElementMatch store = match.getFirstLabeledMatch("end");
PatternElementMatch test = match.getFirstLabeledMatch("test");
InstructionHandle testInstructionHandle = test.getMatchedInstructionInstructionHandle();
if (reported.get(testInstructionHandle.getPosition())) {
return;
}
// Get all blocks
//
// (1) dominated by the wildcard instruction matching
// the beginning of the instructions creating the object, and
// (2) postdominated by the field store
//
// Exception edges are not considered in computing
// dominators/postdominators.
// We will consider this to be all of the code that creates
// the object.
DominatorsAnalysis domAnalysis = classContext.getNonExceptionDominatorsAnalysis(method);
PostDominatorsAnalysis postDomAnalysis = classContext.getNonExceptionPostDominatorsAnalysis(method);
BitSet extent = domAnalysis.getAllDominatedBy(createBegin.getBasicBlock());
BitSet postDom = postDomAnalysis.getAllDominatedBy(store.getBasicBlock());
// System.out.println("Extent: " + extent);
if (DEBUG) {
System.out.println("test dominates: " + extent);
System.out.println("Field store postdominates " + postDom);
}
extent.and(postDom);
if (DEBUG) {
System.out.println("extent: " + extent);
}
// Check all instructions in the object creation extent
//
// (1) to determine the common lock set, and
// (2) to check for NEW and Invoke instructions that might create an
// object
//
// We ignore matches where a lock is held consistently,
// or if the extent does not appear to create a new object.
LockDataflow lockDataflow = classContext.getLockDataflow(method);
LockSet lockSet = null;
boolean sawNEW = false, sawINVOKE = false;
for (BasicBlock block : cfg.getBlocks(extent)) {
for (Iterator<InstructionHandle> j = block.instructionIterator(); j.hasNext();) {
InstructionHandle handle = j.next();
if (handle.equals(store.getMatchedInstructionInstructionHandle())) {
break;
}
Location location = new Location(handle, block);
// Keep track of whether we saw any instructions
// that might actually have created a new object.
Instruction ins = handle.getInstruction();
if (DEBUG) {
System.out.println(location);
}
if (ins instanceof AllocationInstruction) {
sawNEW = true;
} else if (ins instanceof InvokeInstruction) {
if (ins instanceof INVOKESTATIC
&& ((INVOKESTATIC) ins).getMethodName(classContext.getConstantPoolGen()).startsWith("new")) {
sawNEW = true;
}
sawINVOKE = true;
}
// Compute lock set intersection for all matched
// instructions.
LockSet insLockSet = lockDataflow.getFactAtLocation(location);
if (lockSet == null) {
lockSet = new LockSet();
lockSet.copyFrom(insLockSet);
} else {
lockSet.intersectWith(insLockSet);
}
}
}
if (!(sawNEW || sawINVOKE)) {
return;
}
if (lockSet == null) {
throw new IllegalStateException("lock set is null");
}
if (!lockSet.isEmpty()) {
return;
}
boolean sawGetStaticAfterPutStatic = false;
check: if (signature.startsWith("[") || signature.startsWith("L")) {
BitSet postStore = domAnalysis.getAllDominatedBy(store.getBasicBlock());
for (BasicBlock block : cfg.getBlocks(postStore)) {
for (Iterator<InstructionHandle> j = block.instructionIterator(); j.hasNext();) {
InstructionHandle handle = j.next();
InstructionHandle nextHandle = handle.getNext();
Instruction ins = handle.getInstruction();
if (ins instanceof GETSTATIC && potentialInitialization(nextHandle)) {
XField field2 = XFactory.createXField((FieldInstruction) ins, methodGen.getConstantPool());
if (xfield.equals(field2)) {
sawGetStaticAfterPutStatic = true;
break check;
}
}