j findbug1 pdf

10
© Copyright IBM Corporation 2004 Trademarks FindBugs, Part 1: Improve the quality of your code Page 1 of 10 FindBugs, Part 1: Improve the quality of your code Why and how to use FindBugs Chris Grindstaff ([email protected]) Software Engineer IBM 25 May 2004 Static analysis tools promise to find existing bugs in your code without requiring much effort on the part of the developer. Of course, if you've been programming for long, you know those promises don't always pan out. Even so, good static analysis tools are a valuable addition to your toolbox. In this first of a two-part series, Senior Software Engineer Chris Grindstaff looks at how FindBugs can help improve the quality of your code and eliminate bugs lying in wait. Don't miss Part 2 of this series to get the final part of the story. One of the problems with code quality tools is that they tend to overwhelm developers with problems that aren't really problems -- that is, false positives. When false positives occur, developers learn to ignore the output of the tool or abandon it altogether. The creators of FindBugs, David Hovemeyer and William Pugh, were sensitive to this issue and strove to reduce the number of false positives they report. Unlike other static analysis tools, FindBugs doesn't focus on style or formatting; it specifically tries to find real bugs or potential performance problems. What is FindBugs? FindBugs is a static analysis tool that examines your class or JAR files looking for potential problems by matching your bytecodes against a list of bug patterns. With static analysis tools, you can analyze software without actually running the program. Instead the form or structure of the class files are analyzed to determine the program's intent, often using the Visitor pattern (see Resources). Figure 1 shows the results of analyzing an anonymous project (its name has been withheld in order to protect the horribly guilty):

Upload: doanson44

Post on 06-May-2017

216 views

Category:

Documents


2 download

TRANSCRIPT

Page 1: j Findbug1 PDF

© Copyright IBM Corporation 2004 TrademarksFindBugs, Part 1: Improve the quality of your code Page 1 of 10

FindBugs, Part 1: Improve the quality of your codeWhy and how to use FindBugs

Chris Grindstaff ([email protected])Software EngineerIBM

25 May 2004

Static analysis tools promise to find existing bugs in your code without requiring much efforton the part of the developer. Of course, if you've been programming for long, you know thosepromises don't always pan out. Even so, good static analysis tools are a valuable addition toyour toolbox. In this first of a two-part series, Senior Software Engineer Chris Grindstaff looks athow FindBugs can help improve the quality of your code and eliminate bugs lying in wait. Don'tmiss Part 2 of this series to get the final part of the story.

One of the problems with code quality tools is that they tend to overwhelm developers withproblems that aren't really problems -- that is, false positives. When false positives occur,developers learn to ignore the output of the tool or abandon it altogether. The creators ofFindBugs, David Hovemeyer and William Pugh, were sensitive to this issue and strove to reducethe number of false positives they report. Unlike other static analysis tools, FindBugs doesn't focuson style or formatting; it specifically tries to find real bugs or potential performance problems.

What is FindBugs?

FindBugs is a static analysis tool that examines your class or JAR files looking for potentialproblems by matching your bytecodes against a list of bug patterns. With static analysis tools,you can analyze software without actually running the program. Instead the form or structure ofthe class files are analyzed to determine the program's intent, often using the Visitor pattern (seeResources). Figure 1 shows the results of analyzing an anonymous project (its name has beenwithheld in order to protect the horribly guilty):

Page 2: j Findbug1 PDF

developerWorks® ibm.com/developerWorks/

FindBugs, Part 1: Improve the quality of your code Page 2 of 10

Figure 1. FindBugs UI

Let's take a look at some of the problems that FindBugs can detect.

Examples of problems foundThe following list doesn't include all the problems FindBug might find. Instead, I've focused onsome of the more interesting ones.

Detector: Find hash equals mismatchThis detector finds several related problems, all centered around the implementation of equals()and hashCode(). These two methods are very important because they're called by nearly all of theCollections-based classes -- List, Maps, Sets, and so on. Generally, this detector finds two differenttypes of problems -- when a class:

• Overrides Object's equals() method, but not its hashCode or vice-versa.• Defines a co-variant version of the equals() or compareTo() method. For example, the Bob

class defines its equals() method as boolean equals(Bob), which overloads the equals()method defined in Object. Because of the way the Java code resolves overloaded methodsat compile-time, the version of the method defined in Object will almost always be the oneused at runtime, not the one you defined in Bob (unless you explicitly cast the argument toyour equals() method to type Bob). As a result, when one of the instances of this class is put

Page 3: j Findbug1 PDF

ibm.com/developerWorks/ developerWorks®

FindBugs, Part 1: Improve the quality of your code Page 3 of 10

into any of the collection classes, the Object.equals() version of the method will be used, notthe version defined in Bob. In this case, the Bob class should define an equals() method thataccepts an argument of type Object.

Detector: Return value of method ignoredThis detector looks for places in your code where the return value of a method is ignored when itshouldn't be. One of the more common instances of this scenario is found when invoking Stringmethods, such as in Listing 1:

Listing 1. Example of ignored return value1 String aString = "bob";2 b.replace('b', 'p');3 if(b.equals("pop"))

This mistake is pretty common. At line 2, the programmer thought he'd replaced all of the b's in thestring with p's. He did, but he forgot that strings are immutable. All of these types of methods returna new string, never changing the receiver of the message.

Detector: Null pointer dereference and redundant comparisons to nullThis detector looks for two types of problems. It looks for cases where a code path will orcould cause a null pointer exception, and it also looks for cases in which there is a redundantcomparison to null. For example, if both of the compared values are definitely null, they'reredundant and may indicate a coding mistake. FindBugs detects a similar problem when it's able todetermine that one of the values is null and the other one isn't, as shown in Listing 2:

Listing 2. Null pointer examples1 Person person = aMap.get("bob");2 if (person != null) {3 person.updateAccessTime();4 }5 String name = person.getName();

In this example, if the Map on line 1 does not contain the person named "bob," a null pointerexception will result on line 5 when the person is asked for his name. Because FindBugs doesn'tknow if the map contains "bob" or not, it will flag line 5 as a possible null pointer exception.

Detector: Field read before being initializedThis detector finds fields that are read in constructors before they're initialized. This error is oftencaused by mistakenly using a field's name instead of a constructor argument -- although notalways, as Listing 3 shows:

Listing 3. Reading a field in a constructor before it's initialized1 public class Thing {2 private List actions;3 public Thing(String startingActions) {4 StringTokenizer tokenizer = new StringTokenizer(startingActions);5 while (tokenizer.hasMoreTokens()) {6 actions.add(tokenizer.nextToken());7 }8 }9 }

Page 4: j Findbug1 PDF

developerWorks® ibm.com/developerWorks/

FindBugs, Part 1: Improve the quality of your code Page 4 of 10

In this example, line 6 will cause a null pointer exception because the variable actions has notbeen initialized.

These examples are only a small sampling of the types of problems that FindBugs detects (seeResources for more). At the time of this writing, FindBugs comes with a total of 35 detectors.

Getting started with FindBugsTo run FindBugs, you will need a Java Development Kit (JDK), version 1.4 or higher, althoughit can analyze the class files created by older JDKs. The first thing to do is download and installthe latest release of FindBugs -- currently 0.7.1 (see Resources). Fortunately, the download andinstallation is pretty straightforward. After downloading the zip or tar, unzip it into a directory of yourchoosing. That's it -- the install is finished.

Now that it's installed, let's run it on a sample class. As is often the case with articles, I will speakto the Windows users and assume that those of the Unix persuasion can deftly translate and followalong. Open a command prompt and go to the directory in which you installed FindBugs. For me,that's C:\apps\FindBugs-0.7.3.

In the FindBugs home directory, there are a couple of directories of interest. The documentation islocated in the doc directory, but more important for us, the bin directory contains the batch file torun FindBugs, which leads me to the next section.

Running FindBugsLike most tools these days, you can run FindBugs in multiple ways -- from a GUI, from a commandline, using Ant, as an Eclipse plug-in, and using Maven. I'll briefly mention running FindBugs fromthe GUI, but I'll primarily focus on running it from Ant and the command line. Partly that's becausethe GUI hasn't caught up with all of the command line options. For example, currently you can'tspecify filters to include or exclude particular classes in the UI. But the more important reason isbecause I think FindBugs is best used as an integrated part of your build, and UIs don't belong inautomated builds.

Using the FindBugs UIUsing the FindBugs UI is straightforward, but a couple of points deserve some elaboration. AsFigure 1 demonstrates, one of the advantages of using the FindBugs UI is the description providedfor each type of detected problem. Figure 1 shows the description for the bug Naked notify inmethod. Similar descriptions are provided for each bug pattern, which is extremely useful whenyou're first becoming acquainted with the tool. Equally useful is the Source code tab in the lowerpane of the window. If you tell FindBugs where to find your source, it will highlight the offending lineof code when you switch to the appropriate tab.

It's also important to mention that if you choose xml as your output option when running FindBugsas an Ant task or from the command line, you can load the results of a previous run into the UI.Doing so is a great way to leverage the advantages of the command-line-based tooling and the UItooling at the same time.

Page 5: j Findbug1 PDF

ibm.com/developerWorks/ developerWorks®

FindBugs, Part 1: Improve the quality of your code Page 5 of 10

Running FindBugs as an Ant task

Let's take a look at how to use FindBugs from an Ant build script. First copy the FindBugs Anttask to Ant's lib directory so that Ant is made aware of the new task. Copy FIND_BUGS_HOME\lib\FindBugs-ant.jar to ANT_HOME\lib.

Now take a look at what you need to add to your build script to use the FindBugs task. BecauseFindBugs is a custom task, you'll need to use the taskdef task so that Ant knows which classes toload. Do that by adding the following line to your build file:

<taskdef name="FindBugs" classname="edu.umd.cs.FindBugs.anttask.FindBugsTask"/>

After defining taskdef, you can refer to it by its name, FindBugs. Next you'll add a target to thebuild that uses the new task, as shown in Listing 4:

Listing 4. Creating a FindBugs target

1 <target name="FindBugs" depends="compile">2 <FindBugs home="${FindBugs.home}" output="xml" outputFile="jedit-output.xml">3 <class location="c:\apps\JEdit4.1\jedit.jar" />4 <auxClasspath path="${basedir}/lib/Regex.jar" />5 <sourcePath path="c:\tempcbg\jedit" />6 </FindBugs>7 </target>

Let's take a closer look at what's going on in this code.

Line 1: Notice that the target depends on the compile. It's important to remember that FindBugsworks on class files, not source files, so making the target depend on the compile target ensuresthat FindBugs will be running across the up-to-date class files. FindBugs is flexible about what itwill accept as input, including a set of class files, JAR files, or a list of directories.

Line 2: You must specify the directory that contains FindBugs, which I did using an Ant propertylike this:

<property name="FindBugs.home" value="C:\apps\FindBugs-0.7.3" />

The optional attribute output specifies the output format that FindBugs will use for its results.The possible values are xml, text, or emacs. If no outputFile is specified, then FindBugs printsto standard out. As mentioned previously, the XML format has the added advantage of beingviewable within the UI.

Line 3: The class element is used to specify which set of JARs, class files, or directories you wantFindBugs to analyze. To analyze multiple JARs or class files, specify a separate class elementfor each. The class element is required unless the projectFile element is included. See theFindBugs manual for more details.

Line 4: You list your application's dependencies by using the nested element auxClasspath. Theseare classes that your application needs, but you don't want FindBugs to analyze. If you don't list

Page 6: j Findbug1 PDF

developerWorks® ibm.com/developerWorks/

FindBugs, Part 1: Improve the quality of your code Page 6 of 10

your application's dependencies, FindBugs will still analyze your classes as well as it can, but itwill complain when it is unable to find one of the missing classes. as with the class element, youcan specify multiple auxClasspath elements in the FindBugs element. The auxClasspath elementis optional.

Line 5: If the sourcePath element is specified, the path attribute should indicate a directory thatcontains your application's source code. Specifying the directory allows FindBugs to highlight thesource code in error when viewing the XML results in the GUI. This element is optional.

That covers the basics. Let's fast forward several weeks.

Filters

You've introduced FindBugs to your team and have been running it as a part of your hourly/nightlybuild process. As the team has become more acquainted with the tool, you've decided that someof the bugs being detected aren't important to your team, for whatever reason. Perhaps you don'tcare if some of your classes return objects that could be modified maliciously -- or maybe, likeJEdit, you have a real honest-to-goodness, legitimate reason to invoke System.gc().

You always have the option of "turning off" a particular detector. On a more granular level, youcould exclude certain detectors from finding problems within a specified set of classes or evenmethods. FindBugs offers this granular control with exclude and include filters. Exclude andinclude filters are currently supported only in the command-line or Ant versions of FindBugs.As the name implies, you use exclude filters to exclude the reporting of certain bugs. The lesspopular, but still useful, include filters can be used to report targeted bugs only. The filters aredefined in an XML file. They may be specified at the command-line with an exclude or includeswitch or by using the excludeFilter and includeFilter in your Ant build file. In the examplesbelow, assume that the exclude switch was used. Also note in the discussion below that I use"bugcode," "bug," and "detector" somewhat interchangeably.

Filters can be defined in a variety of ways:

• Filters that match one of your classes. These filters could be used to ignore all problemsfound in a particular class.

• Filters that match particular bugcodes in one of your classes. These filters could be used toignore some bugs found in a particular class.

• Filters that match a set of bugs. These filters could be used to ignore a set of bugs across allof the analyzed classes.

• Filters that match particular methods in one of the analyzed classes. These filters could beused to ignore all bugs found in a set of methods for a class.

• Filters that match some bugs found in methods in one of the analyzed classes. You could usethese filters to ignore some of the bugs found in a particularly buggy set of methods.

That's all there is to getting started. See the FindBugs documentation for more details on additionalways the FindBugs task can be customized. Now that we know how to set up a build file, let's takea closer look at integrating FindBugs into your build process.

Page 7: j Findbug1 PDF

ibm.com/developerWorks/ developerWorks®

FindBugs, Part 1: Improve the quality of your code Page 7 of 10

Integrating FindBugs into your build processYou have several options when it comes to integrating FindBugs into your build process. You canalways execute FindBugs from the command line, but more than likely you're already using Ant foryour build, so using the FindBugs Ant task is the most natural. Because we've covered the basicsof using the FindBugs Ant task earlier, I'll cover some of the reasons you should add FindBugs toyour build process and discuss a few of the issues you may run into.

Why should I integrate FindBugs into my build process?One of the first questions that's often asked is why would I want to add FindBugs into my buildprocess? While there are a host of reasons, the most obvious answer is that you want to makesure problems are detected as soon as your build is run. As your team grows and you inevitablyadd more junior developers to the project, FindBugs can act as a safety net, detecting identifiedbug patterns. I want to reiterate some of the sentiment expressed in one of the FindBugs papers.If you put enough developers together, then you're going to have bugs in your code. Tools likeFindBugs certainly won't find all the bugs, but they'll help find some of them. Finding some now isbetter than your customers finding them later -- especially when the cost of incorporating FindBugsinto your build process is so low.

Once you've stabilized which filters and classes to include, there's a negligible cost for runningFindBugs, with the additional benefit that it detects new bugs. The benefit is probably even greaterif you've written application-specific detectors.

Generate meaningful resultsIt's important to recognize that this cost/benefit analysis is only valid so long as you don't generatea lot of false positives. In other words, the tool's value is diminished if, from build to build, it is nolonger simple to determine whether new bugs have been introduced. The more automated youranalysis can be, the better. If fixing bugs means having to wade through a lot of irrelevant detectedbugs, then you'll likely not use the tool very often, or at least not make good use of it.

Decide which set of problems you don't care about and exclude them from the build. Otherwise,pick a small set of detectors that you do care about and run just those. Another option would be toexclude sets of detectors from individual classes, but not others. FindBugs offers a lot of flexibilitywith its use of filtering, which should help you generate results that are meaningful to your team,which leads us to the next section.

Determine what you will do with the results of FindBugsIt may seem obvious, but I've worked with more teams than you might imagine who apparentlyadd FindBugs-like tools to their builds for the pure joy of it. Let's explore this question in a bitmore detail -- what should you do with your results? It's a difficult question to answer specificallybecause it has a lot to do with how your team is organized, how you deal with code ownershipissues, and so on. However, here are some guidelines:

• You may want to consider adding the FindBugs results to your source code management(SCM) system. The general rule of thumb is don't put build artifacts into your SCM system.

Page 8: j Findbug1 PDF

developerWorks® ibm.com/developerWorks/

FindBugs, Part 1: Improve the quality of your code Page 8 of 10

However, in this particular case, breaking the rule may be the right thing to do because itallows you to monitor the quality of the code over time.

• You may choose to convert the XML results file into an HTML report that you post on yourteam's Web site. The conversion can be carried out with an XSL stylesheet or script. Checkthe FindBugs Web site or mailing list for examples (see Resources).

• Tools like FindBugs can often turn into political weapons used to bludgeon teams orindividuals. Try not to encourage that or let it happen -- remember, it's just a tool that's meantto help you improve the quality of your code. With that inspirational aside, in next month'sinstallment I'll show you how to write custom bug detectors.

Summary

I encourage you to try some form of static analysis tool on your code, whether it's FindBugs, PMD,or something else. They're valuable tools that can find real problems, and FindBugs is one ofthe better ones for eliminating false positives. In addition, its pluggable architecture provides aninteresting test bed for writing invaluable application-specific detectors. In Part 2 of this series, I'llshow you how to write custom detectors to find application-specific problems.

Page 9: j Findbug1 PDF

ibm.com/developerWorks/ developerWorks®

FindBugs, Part 1: Improve the quality of your code Page 9 of 10

Resources

• Download the latest version of FindBugs.• The FindBugs site provides a full list of bugs with descriptions.• Read more information about the Visitor pattern.• Here's more information on the Byte Code Engineering Library.• PMD is another powerful open-source static code analysis tool that lets you write custom

rules. It's not quite as powerful as FindBugs because it analyzes the Java files instead ofclass files, but well worth checking out.

• Two authors have tried to outline a set of best practices for avoiding the type of problemsthat FindBugs can detect: Joshua Bloch's Effective Java: Programming Language Guide(Addison-Wesley, 2001) and Peter Haggar's Practical Java: Programming Language Guide(Addison-Wesley, 2000) .

• In "The future of software development" (developerWorks, June 2003), Eric Allen discussessome of the current trends in software development and predicts what they may lead to in thecoming years. Check out the rest of Eric's Diagnosing Java code columns for common bugpatterns.

• Find hundreds more Java technology resources on the developerWorks Java technologyzone.

• Browse for books on these and other technical topics.

Page 10: j Findbug1 PDF

developerWorks® ibm.com/developerWorks/

FindBugs, Part 1: Improve the quality of your code Page 10 of 10

About the author

Chris Grindstaff

Chris Grindstaff is a Senior Software Engineer at IBM in Research Triangle Park,North Carolina. Chris wrote his first program at the age of 7, when he convinced hisgrade school teacher that "typing" sentences would be just as onerous a punishmentas writing them by hand. Chris is currently interested in a variety of open-sourceprojects. He has worked extensively with Eclipse and authored several popularEclipse plug-ins, which may be found on his Web site. You can contact Chris [email protected] or [email protected].

© Copyright IBM Corporation 2004(www.ibm.com/legal/copytrade.shtml)Trademarks(www.ibm.com/developerworks/ibm/trademarks/)