finding bugs that matter with findbugs
TRANSCRIPT
1
FindBugs™ - Find Bugs in Java Programs
Defective Java Code
Learning from mistakes
Carol McDonald
2
What is FindBugs?
• Static analysis tool
• Looks for defects based on bug patterns
• Bug patterns come from real bugs
• bug patterns are grouped into categories:
• correctness, bad practice, performance…
• assigned a priority: high, medium or low.
• High-Medium priority have low false positive rates
• http://findbugs.sourceforge.net/
3© Availity, LLC | All rights reserved. 3
Bug Patterns
• broad and common patterns:• a read or write on a null pointer• typos• Methods whose return value should not be
ignored• Also specific bug patterns:
• Every Programming Puzzler• Eclipse documented bug fixes• Every chapter in Effective Java• Many postings to http://thedailywtf.com/
4© Availity, LLC | All rights reserved. 4
Bug Patterns: http://thedailywtf.com/
5© Availity, LLC | All rights reserved.
CN Cloneable Not Implemented Correctly
DC Double Checked Locking
DE Dropped Exception
EC Suspicious Equals Comparison
Eq Bad Covariant Definition of Equals
HE Equal objects must have equal hashcodes
IS2 Inconsistent Synchronization
MS Static Field Modifiable By Untrusted Code
NP Null Pointer Dereference
NS Non-Short-Circuit Boolean Operator
OS Open Stream
RCN Redundant Comparison to Null
RR Read Return Should Be Checked
RV Return Value Should Be Checked
Se Non-serializable Serializable Class
UR Uninitialized Read In Constructor
UW Unconditional Wait
Wa Wait Not In Loop
SomebugPatterns:
6© Availity, LLC | All rights reserved.
SomebugPatterns:
7
Misconceptions about Bugs
• Programmers are smart
• Smart people don’t make dumb mistakes
• WRONG!
• Smart people make dumb mistakes
• Common errors:
• wrong boolean operator, forgetting parentheses, etc.
• Misunderstood class or method !
8
Can you find the Bug?
if (listeners == null)
listeners.remove(listener);
JDK1.6.0, b105, sun.awt.x11.XMSelection
9
Who uses FindBugs?
• Developed from Research at University of Maryland
• Google, Ebay, Sun, Wells Fargo…
• Bill Pugh spent a year sabbatical at Google working Findbugs into their development process
• Google runs FindBugs over all Java code
• 1800s issues identified, > 600 fixed.
• Ebay found 2 developers reviewing Findbugs was 10 times more effective than 2 testers
10
Some Bug Categories
• Correctness - the code is doing something wrong, you should look at it
• Bad practice - the code violates good practice
• Dodgy Code
• Concurrency
• Performance
• Security defect
11
Can you find the Bug?
public String sendMessage (User user, String body, Date time) {
return sendMessage(user, body, null);
}
public String sendMessage (User user, String body, Date time, List attachments) {
String xml = buildXML (body, attachments);
String response = sendMessage(user, xml);
return response;
}
12
Infinite recursive loopHigh priority correctness
public String sendMessage (User user, String body, Date time) {
return sendMessage(user, body, null);
}
public String sendMessage (User user, String body, Date time, List attachments) {
String xml = buildXML (body, attachments);
String response = sendMessage(user, xml);
return response;
}
13
Can you find the Bug?
public String foundType() { return this.foundType();}
14
Infinite recursive loop
public String foundType() { return this.foundType();}// should be public String foundType() { return this.foundType;}
• Findbugs found 5 infinite recursive loops in JDK1.6.0-b13
• Including this one written by Joshua Bloch• Smart people make dumb mistakes
• 27 across all versions of JDK, 31 in Google’s Java code
• Embrace and fix your dumb mistakes
15
Can you find the Bug?
if (name != null || name.length > 0)
16
Can you find the Bug?
if (name != null || name.length > 0)
if (name != null && name.length > 0)
Found in //com.sun.corba.se.impl.naming.cosnaming.NamingContextImpl
17
Can you find the Bug?
if (part == null | part.equals(""))
18
Can you find the Bug?
if (part == null | part.equals(""))
if (part == null || part.equals(""))
Found in //com.sun.xml.internal.ws.wsdl.parser.RuntimeWSDLParser
19
Null Pointer Bugs found in com.sun….
if (name != null || name.length > 0)
if (part == null | part.equals(""))
// sun.awt.x11.ScrollPanePeerif (g != null)
paintScrollBars(g,colors);g.dispose();
20© Availity, LLC | All rights reserved.
//BoundedThreadPool
private final String _lock = "LOCK";...synchronized(_lock){...}
Can you find the Bug?
21© Availity, LLC | All rights reserved.
//BoundedThreadPool private final String _lock = "LOCK";...synchronized(_lock){...}
Constant Strings are shared across all other classes loaded by the JVM. Could lead to unexpected deadlocks in conjunction with other code
found in Jetty….
22
Problem?
public final WritableRaster filter( Raster src, WritableRaster dst) { int dstLength = dst.getNumBands(); // Create a new destination Raster,if needed if (dst == null) dst = createCompatibleDestRaster(src);
23
Redundant Check for Null
public final WritableRaster filter( Raster src, WritableRaster dst) { int dstLength = dst.getNumBands(); // Create a new destination Raster,if needed if (dst == null) dst = createCompatibleDestRaster(src);
can't be null because there would have been a NPE ifit were null
Is it a bug or a redundant check?
24
Can you find the Bug?
if (adapters == null && adapters.length == 0)return;
Eclipse, 3.5RC3
• in Eclipse since 3.2•in this case adapters is probably never null
• Impact:• null pointer exception usually gets noticed• Won’t return if length is 0, error harder to
find
25
Problem?
try { ... }catch (IOException e) { new SAXException("Server side Exception:" + e);}
// com.sun.xml.internal.txw2.output.XMLWriter
26
Bad Method Call
try { ... }catch (IOException e) { new SAXException("Server side Exception:" + e);}
// com.sun.xml.internal.txw2.output.XMLWriter
Exception created and dropped rather than thrown
try { ... }catch (IOException e) { throw new SAXException("Server side Exception:" + e);}
27
Problem?
public static String getNameById(String userId) { String str = userId; ... str.replace(' ', '_');
return str; }
28
Method Ignores return valueCorrectness
public static String getNameById(String userId) { String str = userId; ... str= str.replace(' ', '_');
return str; }
Methods whose return value shouldn't be ignored• Strings are immutable, so functions like trim() and replace() return new String
29
What does it Print?
Integer one = 1;Long addressTypeCode = 1L;
if (addressTypeCode.equals(one)) {System.out.println("equals");
} else {System.out.println("not equals");
}
30
Comparing Different Types
Integer one = 1;Long addressTypeCode = 1L;
if (addressTypeCode.equals(one)) {System.out.println("equals");
} else {System.out.println("not equals");
}
According to the contract of equals(), objects of different classes should always compare as unequal;
31
Incomparable equality
• Using .equals to compare incompatible types• Using .equals to compare arrays
• only checks if the same array
• Checking to see if a Set<Long> contains an Integer • never found, even if the same integral value is contained in the map
• Calling get(String) on a Map<Integer,String>• Returns false , not an error
Silent Bugs hard to find on your own• Types not always explicit• May be introduced by refactoring
• Google refactoring that changed a method to return byte[ ] rather than String
© Availity, LLC | All rights reserved.
32
Best Way to use Findbugs
•Want to find an effective/profitable way to use static analysis to improve software quality
Static Analysis
Deployment
Testing
MistakesThatDon’t
MistakesThatMatter
33
Best Way to use Findbugs
• Find mistakes detected by static analysis before they are detected using more expensive techniques
• While code is fresh in developers heads• Don’t be too eager to fix old issues
Static Analysis
Deployment
Testing
MistakesThatDon’t
MistakesThatMatter
34
Runtime exceptions can be your friend…
Errors which cause a runtime exception are more easily found
Throwing a runtime exception is often a reasonable way to fail safely and report a failure.
runtime exceptions represent conditions that reflect errors in your program's logic and cannot be reasonably recovered from
IllegalArgumentException, NullPointerException, or IllegalStateException
© Availity, LLC | All rights reserved.
35
Expensive Mistakes…
• Mistakes that fail silently • silently cause the wrong answer to be computed
• Mistakes that cause loss of money when they occur• Mistakes that are hard to fix
© Availity, LLC | All rights reserved.
36
Can you find the (Google) bug ?
// calculate DR amount by aggregating CR amountsBigDecimal drAmount = new BigDecimal(0);
for (JournalEntry je: journalEntries) drAmount.add(je.getCrAmount());
// persist to dbgetTrxnService().saveJournalEntry(id,
drAmount, // aggregated amounttrue, // Debit"USD","Revenue");
37
A Google Bug
//Ignored return value of BigDecimal.add
for (JournalEntry je: journalEntries) drAmount.add(je.getCrAmount());
// should be drAmount= drAmount.add(je.getCrAmount());
Fixed within 30 minutes of being reported
38
Bug ?
int value2;Public boolean equals(Integer value1){ return value1== intValue() ;}
public Integer intValue() { return value2;}
39
Using reference equality rather than .equals
int value2;Public boolean equals(Integer value1){ return value1.equals(intValue() );}
public Integer intValue() { return value2;}
For boxed primitives, == and != are computed usingpointer equality, but <, <=, >, >= are computed bycomparing unboxed primitive values
This can bite you on other classes (e.g., String)• but boxed primitives is where people get bit
40
Bug ?
ConcurrentMap<Long,XmitTimeStat> xmit_time_stats = ...;.....stat = new XmitTimeStat();xmit_time_stats.putIfAbsent(key, stat);stat.xmit_rsps_sent.addAndGet(sent);
41
misusing putIfAbsentorg.jgroups.protocols.pbcast.NAKACK
ConcurrentMap<Long,XmitTimeStat> xmit_time_stats = ...;.....stat = new XmitTimeStat();XmitTimeStat stat2 = xmit_time_stats.putIfAbsent(key, stat);if (stat2 != null) stat = stat2;stat.xmit_rsps_sent.addAndGet(sent);
ConcurrentMap provides putIfAbsent• atomically add key → value mapping• but only if the key isnʼt already in the map• if non-null value is returned, put failed and valuereturned is the value already associated with the key
42
Concurrency Bugs
• Lots of concurrency bugs are found• They don’t cause as many problems as they should• Problems will probably increase with bigger core
systems• Early reports from 768 core systems are that they
have more severe problems
© Availity, LLC | All rights reserved.
43
Concurrency Bugs
• Inconsistent synchronization – • a lock is held sometimes when field accessed
• Problems with wait/notify – • e.g., call to wait() not in loop
• unsafe lazy initialization of static field
© Availity, LLC | All rights reserved.
44
Bug ?
synchronized (object) { if (<condition does not hold>) { object.wait(); } // Proceed when condition holds}
45
call to wait() not in loop
synchronized (object) { while (<condition does not hold>) { object.wait(); } // Proceed when condition holds}
46
Concurrency Bugs
• Java 5 simplified concurrency • In Joshua Blochʼs said: don’t lock on
ConcurrentMaps
• Bill Pugh wrote a detector for FindBugs
© Availity, LLC | All rights reserved.
47
JBoss 5.1.0-GA
• 22 synchonizations on ConcurrentHashMap• 9 synchronizations on CopyOnWriteArrayList• 3 synchronizations on AtomicBoolean
© Availity, LLC | All rights reserved.
48
Security Bugs
• Not exposed by normal test use cases• Need:
• Risk analysis, careful design, static analysis, dynamic testing and analysis
• Findbugs does simple analysis for network security vulnerabilities
© Availity, LLC | All rights reserved.
49
Some security Bugs
• Vulnerability to untrusted, malicious code:• public static non-final fields• Methods that don’t defensively copy mutable arguments before
storing them into fields• Methods that don’t defensively copy mutable values stored in fields
before returning them
• Untrusted input:• Included in SQL• included in HTTP response• Forming a file path
© Availity, LLC | All rights reserved.
50
Running FindBugs
• Eclipse plugin• http://findbugs.sourceforge.net/manual/eclipse.html
• Run with Hudson build
© Availity, LLC | All rights reserved.
51
Findbugs plugin in Eclipse
52
References
• Findbugs home page• http://findbugs.sourceforge.net/
• Bill Pugh Findbugs Devoxx talk• http://www.parleys.com/#id=2106&st=5
• Bill Pugh Oredev talk:• http://oredev.org/2010/sessions/defective-java-mistakes-that-matter
© Availity, LLC | All rights reserved.