1 19 20 package edu.umd.cs.findbugs.detect; 21 22 import edu.umd.cs.findbugs.*; 23 import org.apache.bcel.Repository; 24 import org.apache.bcel.classfile.Method; 25 26 public class ReadReturnShouldBeChecked extends BytecodeScanningDetector 27 implements StatelessDetector { 28 29 boolean sawRead = false; 30 31 boolean sawSkip = false; 32 33 boolean recentCallToAvailable = false; 34 35 int sawAvailable = 0; 36 37 boolean wasBufferedInputStream = false; 38 39 private BugReporter bugReporter; 40 41 private int readPC, skipPC; 42 43 private String lastCallClass = null, lastCallMethod = null, 44 lastCallSig = null; 45 46 public ReadReturnShouldBeChecked(BugReporter bugReporter) { 47 this.bugReporter = bugReporter; 48 } 49 50 @Override 51 public void visit(Method obj) { 52 sawAvailable = 0; 53 sawRead = false; 54 sawSkip = false; 55 } 57 58 private boolean isInputStream() { 59 try { 60 if (lastCallClass.startsWith("[")) return false; 61 return (Repository.instanceOf(lastCallClass, 62 "java.io.InputStream") 63 || Repository.implementationOf(lastCallClass, 64 "java.io.DataInput") || Repository 65 .instanceOf(lastCallClass, "java.io.Reader")) 66 && !Repository.instanceOf(lastCallClass, 67 "java.io.ByteArrayInputStream"); 68 } catch (ClassNotFoundException e) { 69 return false; 70 } 71 } 72 73 private boolean isBufferedInputStream() { 74 try { 75 if (lastCallClass.startsWith("[")) return false; 76 return Repository.instanceOf( 77 lastCallClass,"java.io.BufferedInputStream"); 78 } catch (ClassNotFoundException e) { 79 return false; 80 } 81 } 82 @Override 83 public void sawOpcode(int seen) { 84 85 if (seen == INVOKEVIRTUAL || seen == INVOKEINTERFACE) { 86 lastCallClass = getDottedClassConstantOperand(); 87 lastCallMethod = getNameConstantOperand(); 88 lastCallSig = getSigConstantOperand(); 89 } 90 91 if (seen == INVOKEVIRTUAL || seen == INVOKEINTERFACE) 92 if (getNameConstantOperand().equals("available") 93 && getSigConstantOperand().equals("()I") 94 || getNameConstantOperand().startsWith("get") 95 && getNameConstantOperand().endsWith("Length") 96 && getSigConstantOperand().equals("()I") 97 || getClassConstantOperand().equals("java/io/File") 98 && getNameConstantOperand().equals("length") 99 && getSigConstantOperand().equals("()J")) { 100 sawAvailable = 70; 101 return; 102 } 103 sawAvailable--; 104 if ((seen == INVOKEVIRTUAL || seen == INVOKEINTERFACE) 105 && getNameConstantOperand().equals("read") 106 107 && (getSigConstantOperand().equals("([B)I") 108 || getSigConstantOperand().equals("([BII)I") 109 || getSigConstantOperand().equals("([C)I") || getSigConstantOperand() 110 .equals("([CII)I")) && isInputStream()) { 111 sawRead = true; 112 recentCallToAvailable = sawAvailable > 0; 113 readPC = getPC(); 114 return; 115 } 116 if ((seen == INVOKEVIRTUAL || seen == INVOKEINTERFACE) 117 && getNameConstantOperand().equals("skip") 118 && getSigConstantOperand().equals("(J)J") 119 && isInputStream() ) { 120 124 wasBufferedInputStream = isBufferedInputStream(); 125 sawSkip = true; 126 recentCallToAvailable = sawAvailable > 0 && !wasBufferedInputStream; 127 skipPC = getPC(); 128 return; 129 130 } 131 132 if ((seen == POP) || (seen == POP2)) { 133 134 if (sawRead) { 135 bugReporter.reportBug(new BugInstance(this, "RR_NOT_CHECKED", 136 recentCallToAvailable ? LOW_PRIORITY : NORMAL_PRIORITY) 137 .addClassAndMethod(this).addCalledMethod(lastCallClass, 138 lastCallMethod, lastCallSig, false) 139 .addSourceLine(this, readPC)); 140 } else if (sawSkip) { 141 142 bugReporter.reportBug(new BugInstance(this, "SR_NOT_CHECKED", 143 (wasBufferedInputStream ? HIGH_PRIORITY 144 : recentCallToAvailable ? LOW_PRIORITY 145 : NORMAL_PRIORITY)).addClassAndMethod( 146 this).addCalledMethod(lastCallClass, lastCallMethod, 147 lastCallSig, false).addSourceLine(this, skipPC)); 148 } 149 } 150 sawRead = false; 151 sawSkip = false; 152 } 153 } 154 | Popular Tags |