1 19 20 package edu.umd.cs.findbugs.detect; 21 22 23 import edu.umd.cs.findbugs.*; 24 import java.util.*; 25 import org.apache.bcel.Repository; 26 import org.apache.bcel.classfile.*; 27 28 public class FindDoubleCheck extends BytecodeScanningDetector { 29 static final boolean DEBUG = false; 30 int stage = 0; 31 int startPC, endPC; 32 int count; 33 boolean sawMonitorEnter; 34 Set<FieldAnnotation> fields = new HashSet<FieldAnnotation>(); 35 Set<FieldAnnotation> twice = new HashSet<FieldAnnotation>(); 36 FieldAnnotation pendingFieldLoad; 37 38 int countSinceGetReference; 39 int countSinceGetBoolean; 40 private BugReporter bugReporter; 41 42 public FindDoubleCheck(BugReporter bugReporter) { 43 this.bugReporter = bugReporter; 44 } 45 46 @Override 47 public void visit(Method obj) { 48 if (DEBUG) System.out.println(getFullyQualifiedMethodName()); 49 super.visit(obj); 50 fields.clear(); 51 twice.clear(); 52 stage = 0; 53 count = 0; 54 countSinceGetReference = 1000; 55 countSinceGetBoolean = 1000; 56 sawMonitorEnter = false; 57 pendingFieldLoad = null; 58 } 59 60 @Override 61 public void sawOpcode(int seen) { 62 if (DEBUG) System.out.println(getPC() + " " + OPCODE_NAMES[seen] + " " + stage + " " + count + " " + countSinceGetReference); 63 64 if (seen == MONITORENTER) sawMonitorEnter = true; 65 if (seen == GETFIELD || seen == GETSTATIC) { 66 pendingFieldLoad = FieldAnnotation.fromReferencedField(this); 67 if (DEBUG) System.out.println(" " + pendingFieldLoad); 68 String sig = getSigConstantOperand(); 69 if (sig.equals("Z")) { 70 countSinceGetBoolean = 0; 71 countSinceGetReference++; 72 } else if (sig.startsWith("L") || sig.startsWith("[")) { 73 countSinceGetBoolean++; 74 countSinceGetReference = 0; 75 } 76 } else { 77 countSinceGetReference++; 78 } 79 switch (stage) { 80 case 0: 81 if (((seen == IFNULL || seen == IFNONNULL) && countSinceGetReference < 5) 82 || ((seen == IFEQ || seen == IFNE) && countSinceGetBoolean < 5)) { 83 int b = getBranchOffset(); 84 if (DEBUG) { 85 System.out.println("branch offset is : " + b); 86 } 87 if (b > 0 88 && !(seen == IFNULL && b > 9) 89 && !(seen == IFEQ && (b > 9 && b < 34)) 90 && !(seen == IFNE && (b > 9 && b < 34)) 91 && (!sawMonitorEnter)) { 92 fields.add(pendingFieldLoad); 93 startPC = getPC(); 94 stage = 1; 95 } 96 } 97 count = 0; 98 break; 99 case 1: 100 if (seen == MONITORENTER) { 101 stage = 2; 102 count = 0; 103 } else if (((seen == IFNULL || seen == IFNONNULL) && countSinceGetReference < 5) 104 || ((seen == IFEQ || seen == IFNE) && countSinceGetBoolean < 5)) { 105 int b = getBranchOffset(); 106 if (b > 0 && (seen == IFNONNULL || b < 10)) { 107 fields.add(pendingFieldLoad); 108 startPC = getPC(); 109 count = 0; 110 } 111 } else { 112 count++; 113 if (count > 10) stage = 0; 114 } 115 break; 116 case 2: 117 if (((seen == IFNULL || seen == IFNONNULL) && countSinceGetReference < 5) 118 || ((seen == IFEQ || seen == IFNE) && countSinceGetBoolean < 5)) { 119 if (getBranchOffset() >= 0 && fields.contains(pendingFieldLoad)) { 120 endPC = getPC(); 121 stage++; 122 twice.add(pendingFieldLoad); 123 break; 124 } 125 } 126 count++; 127 if (count > 10) stage = 0; 128 break; 129 case 3: 130 if (seen == PUTFIELD || seen == PUTSTATIC) { 131 FieldAnnotation f = FieldAnnotation.fromReferencedField(this); 132 if (DEBUG) System.out.println(" " + f); 133 if (twice.contains(f) && !getNameConstantOperand().startsWith("class$") 134 && !getSigConstantOperand().equals("Ljava/lang/String;")) { 135 Field declaration = findField(getClassConstantOperand(), getNameConstantOperand()); 136 141 if (declaration == null || !declaration.isVolatile()) 142 bugReporter.reportBug(new BugInstance(this, "DC_DOUBLECHECK", NORMAL_PRIORITY) 143 .addClassAndMethod(this) 144 .addField(f).describe("FIELD_ON") 145 .addSourceLineRange(this, startPC, endPC)); 146 stage++; 147 } 148 } 149 break; 150 default: 151 } 152 } 153 154 Field findField(String className, String fieldName) { 155 try { 156 JavaClass fieldDefinedIn = getThisClass(); 158 if (!className.equals(getClassName())) { 159 161 fieldDefinedIn = Repository.lookupClass(className); 162 } 163 Field[] f = fieldDefinedIn.getFields(); 164 for (Field aF : f) 165 if (aF.getName().equals(fieldName)) { 166 return aF; 168 } 169 return null; 170 } catch (ClassNotFoundException e) { 171 return null; 172 } 173 } 174 175 } 176 | Popular Tags |