Designing Bug Detection Rules for Fewer False Alarms
The short Paper for the ICSE2018 poster session [PDF] [LINK to ACM]
Jaechang Nam, Song Wang, Yuan Xi, and Lin Tan. 2018. Designing bug detection rules for fewer false alarms. In Proceedings of the 40th International Conference on Software Engineering: Companion Proceeedings (ICSE '18). ACM, New York, NY, USA, 315-316. DOI: https://doi.org/10.1145/3183440.3194987
FeeFin Detection Results on Open-source Projects
[https://goo.gl/2qgwse]
FeeFin Patterns and Detection Rules
CompareSameValue
CompareSameValue compares the same values from a getter and a field.
The example always returns true as the getter, getVersion, actually returns the field, VERISON.
public static final byte VERSION = 1;
public void readFields(DataInput in) throws IOException {
byte version = in.readByte();
...
- } else if (getVersion() == VERSION) {
+ } else if (getVersion() == version) {
...
public byte getVersion() {
return VERSION;
}
Detection Question and Rule
- Q1. Does a conditional expression compare a field with a getter method that actually returns the same field?
- Q2. Does the getter method have no arguments?
- Q3. Is the field value not updated in the getter method?
- Q4. Is the getter method not overridden by other classes?
- Q5. Is the getter method not a default method in an interface?
Detection Rule = (Q1: Yes, Q2: Yes, Q3: Yes, Q4: Yes, Q5: Yes)
EqualToSameExpression
EqualToSameExpression compares the same expression with ’==’.
The example always returns true and a redundant part is removed in a fix.
- if(replicaInfo.getStamp() == replicaInfo.getStamp()) {
+ if(block.getStamp() == replicaInfo.getStamp()) {
Detection Question and Rule
- Q1. Does a conditional statement compare the same expressions using ‘==’?
- Q2. Is x == x not used for checking if x is NaN when its type is float or double?
- Q3. Are developers not intentionally making always true condition with the same number literals such as 1 == 1?
Detection Rule = (Q1: Yes, Q2: Yes, Q3: Yes)
IllogicalCondition
IllogicalCondition loads a known null object in conditional expressions that can cause a null pointer exception (NPE) because of an illogical condition.
In the example, when the left operand of ‘||’ in the deleted line is false, prefix is null and will cause an NPE in the right operand. The ‘||’ is replaced into ‘&&’ in the added line of the patch for avoiding NPE when calling prefix.value().
- if(prefix != null || prefix.value()!=null)
+ if(prefix != null && prefix.value()!=null)
Detection Question and Rule
- Q1. Is a conditional expression that check if an object is not null followed by ||?
- Q2. Does an additional condition after || contain any method call of the object or a method call that uses the object as an argument?
Detection Rule = (Q1: Yes, Q2: Yes)
IncorrectDirectoySlash
IncorrectDirectorySlash causes an inconsistent path by an optional slash.
In the example, depending on whether args[1] is ended with a slash or not, mDir could have an inconsistent path. This is fixed by calling getAbsolutePath() that always returns a path not ending with a slash.
- File mDir = new File(args[1] + "-tmp");
+ File mDir = new File(args[1]);
+ mDir = new File(mDir.getAbsolutePath() + "-tmp");
Detection Question and Rule
- Q1. Is there a String variable from args[x] and concatenated with a string value as an argument when initiating File class?
Detection Rule = (Q1: Yes)
IncorrectMapIterator
IncorrectMapIterator is a wrong iteration of a map by values instead of an entry set.
In the example, developers incorrectly used values of a map to iterate the map.
Map m = this.getMap();
- for(Iterator i=m.values().iterator();i.hasNext();){
+ for (Iterator i=m.entrySet().iterator();i.hasNext();){ Map.Entry e = (Map.Entry) i.next();
String uri = (String) e.getKey();
Detection Question and Rule
- Q1. Is a Map iterator initialized by calling Map.values()?
- Q2. Is an object from the iterator casted to Map.Entry in a loop
Detection Rule = (Q1: Yes, Q2: Yes)
MissingLForLong
MissingLForLong causes an integer overflow while defining a long integer with the multiplication of actual values.
The example shows its fix by adding a suffix, L, for a long type on the largest value.
- final long DEFAULT_MAX_FILE_SIZE = 10*1024*1024*1024;
+ final long DEFAULT_MAX_FILE_SIZE = 10*1024*1024*1024L;
Detection Question and Rule
- Q1: Is a long type constant value computed with several integer values greater than the maximum value of the int type?
Detection Rule = (Q1: Yes)
RedundantException
RedundantException handles the same exception in both a try-catch-finally block and a method declaration with ‘throws’. This may miss intended catch or finally blocks.
In the example, the finally block is not executed when there is an IOException from initializing os or is before the try block as the method copy() throws the same exception. This bug leads to memory leak and is fixed by moving the statements causing IOException into the try block.
public void copy() throws IOException {
- IndexOutput os = createOutput(dest);
- IndexInput is = openInput(src);
+ IndexOutput os = null;
+ IndexInput is = null;
try {
+ os = createOutput(dest);
+ is = openInput(src);
...
} catch (IOException ioe) {
...
} finally {
IOUtils.closeSafely(pExp, os, is);
Detection Question and Rule
- Q1: Does a method declare to throw the same exception with a catch block in the method?
- Q2: Are there at least two variables defined out of a try block used in a finally block of the method?
- Q3: Are the variables initialized by method calls?
- Q4: Are there at least two variables defined out of a try block used in a finally block of the method?
- Q5: Are the variables not primitive types?
- Q6: Are the variables not arrays?
Detection Rule = (Q1: Yes, Q2: Yes, Q3: Yes, Q4: Yes, Q5: Yes, Q6: Yes )
RedundantInstantiation
RedundantInstantiation initializes an object redundantly that can cause a performance issue.
The example shows redundant object instantiations of conn, one of which is removed in a patch.
- Connection conn = getConnection();
- conn = new Connection(url,user);
+ Connection conn = new Connection(url,user);
Detection Question and Rule
- Q1: Is an object initialized and then instantiated without using it?
Detection Rule = (Q1: Yes)
SameObjEquals
SameObjEquals compares the same object, method, variable, etc., with equals().
The comparison in the example always returns true and a redundant part is removed in a fix.
- return other.getUUID().equals(other.getUUID());
+ return getUUID().equals(other.getUUID());
Detection Question and Rule
- Q1: Is the same object compared by using equals()?
- Q2: Is an equals() method call used in if statement or for block?
- Q3: Is the conditional expression that compares the same objects by using equals() not existing in a method defined with a @test annotation?
- Q4: Is equals() not used in Assert or System.out.print()?
Detection Rule = (Q1: Yes, Q2: Yes, Q3: Yes, Q4: Yes)
WrongIncrementer
WrongIncrementer is the misuse of an outer incrementer in an inner loop.
In the example, developers incorrectly used the incrementer, i. If the sizes of a
and b are not the same, there will be an index-out-of-bounds exception.
for(int i=0; i < a.length; i++){
for(int j=0; j < b.length; j++){
- a[i] = b[i];
+ a[i] = b[j];
Detection Question and Rule
- Q1: Are outer and/or inner loops based on size() or length() of arrays or collections?
- Q2: Aren't there other outer loops of the outer loop or other inner loops of the inner loop?
- Q3: Is the initialization of a for loop not containing more than one loop control variables?
- Q4: Is an array and collection not same in both outer and inner loops?
Detection Rule = (Q1: Yes, Q2: Yes, Q3: Yes, Q4: Yes)