How to Write a Checker in 24 Hours



Similar documents
MPI-Checker Static Analysis for MPI

Applying Clang Static Analyzer to Linux Kernel

Address Taken FIAlias, which is equivalent to Steensgaard. CS553 Lecture Alias Analysis II 2

A Memory Model for Static Analysis of C Programs

Specific Simple Network Management Tools

Fully Automated Static Analysis of Fedora Packages

Common Errors in C/C++ Code and Static Analysis

Using Eclipse CDT/PTP for Static Analysis

Illustration 1: Diagram of program function and data flow

First Java Programs. V. Paúl Pauca. CSC 111D Fall, Department of Computer Science Wake Forest University. Introduction to Computer Science

For the next three questions, consider the class declaration: Member function implementations put inline to save space.

Static Analysis. Find the Bug! : Analysis of Software Artifacts. Jonathan Aldrich. disable interrupts. ERROR: returning with interrupts disabled

Binary storage of graphs and related data

Intel EP80579 Software for Security Applications on Intel QuickAssist Technology Cryptographic API Reference

Coding Rules. Encoding the type of a function into the name (so-called Hungarian notation) is forbidden - it only confuses the programmer.

Automated Validation & Verification of Software Paper Presentation

1 Abstract Data Types Information Hiding

MPLAB Harmony System Service Libraries Help

Tutorial on C Language Programming

Variable Base Interface

Visualizing Information Flow through C Programs

Towards practical reactive security audit using extended static checkers 1

N3458: Simple Database Integration in C++11

1 Posix API vs Windows API

A binary search tree or BST is a binary tree that is either empty or in which the data element of each node has a key, and:

C++FA 5.1 PRACTICE MID-TERM EXAM

Abstract Data Type. EECS 281: Data Structures and Algorithms. The Foundation: Data Structures and Abstract Data Types

ECE 122. Engineering Problem Solving with Java

OpenGL Insights. Edited by. Patrick Cozzi and Christophe Riccio

Stacks. Linear data structures

CPLEX Tutorial Handout

Module 10. Coding and Testing. Version 2 CSE IIT, Kharagpur

Introduction to Data-flow analysis

Automated Detection of Non-Termination and NullPointerExceptions for Java Bytecode

vector vec double # in # cl in ude <s ude tdexcept> tdexcept> // std::ou std t_of ::ou _range t_of class class V Vector { ector {

Generating Test Cases With High Branch Coverage for Web Applications

Phys4051: C Lecture 2 & 3. Comment Statements. C Data Types. Functions (Review) Comment Statements Variables & Operators Branching Instructions

Dynamic programming formulation

CS 111 Classes I 1. Software Organization View to this point:

Xcode Project Management Guide. (Legacy)

Virtuozzo Virtualization SDK

Software Testing & Analysis (F22ST3): Static Analysis Techniques 2. Andrew Ireland

Efficiency of algorithms. Algorithms. Efficiency of algorithms. Binary search and linear search. Best, worst and average case.

CS 241 Data Organization Coding Standards

Advanced compiler construction. General course information. Teacher & assistant. Course goals. Evaluation. Grading scheme. Michel Schinz

Boolean Expressions, Conditions, Loops, and Enumerations. Precedence Rules (from highest to lowest priority)

Know or Go Practical Quest for Reliable Software

Optimizing Generation of Object Graphs in Java PathFinder

Static Code Analysis Procedures in the Development Cycle

MASSACHUSETTS INSTITUTE OF TECHNOLOGY Computer Systems Engineering: Spring Quiz I Solutions

CSE 504: Compiler Design. Data Flow Analysis

Affdex SDK for Windows!

The software model checker BLAST

CS506 Web Design and Development Solved Online Quiz No. 01

KITES TECHNOLOGY COURSE MODULE (C, C++, DS)

The Software Model Checker BLAST: Applications to Software Engineering

Output: struct treenode{ int data; struct treenode *left, *right; } struct treenode *tree_ptr;

Glossary of Object Oriented Terms

CpSc212 Goddard Notes Chapter 6. Yet More on Classes. We discuss the problems of comparing, copying, passing, outputting, and destructing

How to create/avoid memory leak in Java and.net? Venkat Subramaniam

Scoping (Readings 7.1,7.4,7.6) Parameter passing methods (7.5) Building symbol tables (7.6)

The CompCert verified C compiler

Static Analysis of Virtualization- Obfuscated Binaries

Scanning and parsing. Topics. Announcements Pick a partner by Monday Makeup lecture will be on Monday August 29th at 3pm


Open-source Versus Commercial Software: A Quantitative Comparison

Program Analysis for JavaScript Challenges and Techniques

Kodo - Cross-platform Network Coding Software Library. Morten V. Pedersen - Aalborg University / Steinwurf ApS mvp@es.aau.dk

C++ INTERVIEW QUESTIONS

Object Oriented Software Design

B AB 5 C AC 3 D ABGED 9 E ABGE 7 F ABGEF 8 G ABG 6 A BEDA 3 C BC 1 D BCD 2 E BE 1 F BEF 2 G BG 1

Coding Standard for Java

State of the World - Statically Verifying API Usage Rule

Register File, Finite State Machines & Hardware Control Language

Jonathan Worthington Scarborough Linux User Group

An Hybrid MPI/Stream Programming Model for Heterogeneous High Performance Systems

How To Port A Program To Dynamic C (C) (C-Based) (Program) (For A Non Portable Program) (Un Portable) (Permanent) (Non Portable) C-Based (Programs) (Powerpoint)

Help on the Embedded Software Block

Keywords are identifiers having predefined meanings in C programming language. The list of keywords used in standard C are : unsigned void

CLAPP: Characterizing Loops in Android Applications

Practical Memory Leak Detection using Guarded Value-Flow Analysis

GTask Developing asynchronous applications for multi-core efficiency

DEVELOPING DATA PROVIDERS FOR NEEDFORTRADE STUDIO PLATFORM DATA PROVIDER TYPES

A Study of Android Application Security

Questions 1 through 25 are worth 2 points each. Choose one best answer for each.

JAVA Program For Processing SMS Messages

A Plan for the Continued Development of the DNS Statistics Collector

Using Power to Improve C Programming Education

Freescale MQX USB Device User Guide

Software Reliability Estimation Based on Static Error Detection

Operator Overloading. Lecture 8. Operator Overloading. Running Example: Complex Numbers. Syntax. What can be overloaded. Syntax -- First Example

CS 141: Introduction to (Java) Programming: Exam 1 Jenny Orr Willamette University Fall 2013

Automating Mimicry Attacks Using Static Binary Analysis

sqlpp11 - An SQL Library Worthy of Modern C++

Detecting Critical Defects on the Developer s Desktop

Obfuscation: know your enemy

Using XACML Policies as OAuth Scope

A TOOL FOR DATA STRUCTURE VISUALIZATION AND USER-DEFINED ALGORITHM ANIMATION

Lecture 2 Introduction to Data Flow Analysis

6.088 Intro to C/C++ Day 4: Object-oriented programming in C++ Eunsuk Kang and Jean Yang

Transcription:

How to Write a Checker in 24 Hours Clang Static Analyzer Anna Zaks and Jordan Rose Apple Inc.

What is this talk about? The Clang Static Analyzer is a bug finding tool It can be extended with custom checkers We ll teach you how to write your own checker

Warnings are great! Provide free and fast code review Catch errors early in the development cycle

Compiler Warnings are Limited

Static Analyzer to the Rescue

Static Analyzer to the Rescue

Why Static Analysis? Explores each path through the program Path-sensitive, context-sensitive analysis Algorithm is exponential (but bounded) Produces very precise results Able to find more bugs use-after-free resource leaks...

Check that a File is Closed on each Path

Check that a File is Closed on each Path

Check that a File is Closed on each Path

Symbolic Execution Performs a path-sensitive walk of Clang s CFG Similar to program execution but Explores every possible path through the program Uses symbolic values Collects the constraints on symbolic values along each path Uses constraints to determine feasibility of paths

Builds a Graph of Reachable Program States Data = $D File = $F false File = fopen File!= NULL true $F == 0 $F!= 0!Data return false true $F == 0 fputc $F!= 0 $D!= 0 $F!= 0 $D!= 0 $F!= 0 $D == 0 $F!= 0 $D == 0 return return $F!= 0 $D!= 0

Builds a Graph of Reachable Program States Data = $D File = $F false File = fopen File!= NULL true $F == 0 $F!= 0!Data return false true $F == 0 fputc $F!= 0 $D!= 0 $F!= 0 $D!= 0 $F!= 0 $D == 0 $F!= 0 $D == 0 return return Denotes that the file is open $F!= 0 $D!= 0

Finding a Bug ~ Graph Reachability Data = $D File = $F false File = fopen File!= NULL true $F == 0 $F!= 0!Data return false true $F == 0 fputc $F!= 0 $D!= 0 $F!= 0 $D!= 0 $F!= 0 $D == 0 $F!= 0 $D == 0 return return Denotes that the file is open $F!= 0 $D!= 0

What s in a Node? Execution location pre-statement post-statement entering a call... Stack frame Program Point Program State Environment: Expr -> values Store: memory location -> values Constraints on symbolic values Generic Data Map (GDM)

Extending with Checkers Checkers participate in the graph construction Analyzer Core Checker 1 Checker 2

Extending with Checkers Checkers participate in the graph construction Checkers can stop path exploration by creating sink nodes Analyzer Core Checker 1 Checker 2 BUG

Checkers are Visitors checkprestmt (const ReturnStmt *S, CheckerContext &C) const Before return statement is processed checkpostcall (const CallEvent &Call, CheckerContext &C) const After a call has been processed checkbind (SVal L, SVal R, const Stmt *S, CheckerContext &C) const On binding of a value to a location as a result of processing the statement See the checker writer page for more details: http://clang-analyzer.llvm.org/checker_dev_manual.html

Let s Write a Unix Stream API Checker

Stream State Transitions File handle state changes are driven by the API calls fopen Opened Untracked Closed

Stream State Transitions File handle state changes are driven by the API calls Error States: If a file has been closed, it should not be accessed again. fopen Opened Untracked Closed Double Close

Stream State Transitions File handle state changes are driven by the API calls Error States: If a file has been closed, it should not be accessed again. If a file was opened with fopen, it must be closed with fopen Opened lose reference to symbol Leaked Untracked Closed Double Close

Stream Checker Recipe Define the state of a file descriptor Add state transition corresponding to fopen Add transitions driven by Report error on double close Report error on leak fopen Opened lose reference to symbol Leaked Untracked Closed Double Close

Defining the State of a File Descriptor struct StreamState { enum Kind { Opened, Closed K; StreamState(Kind InK) : K(InK) { ;

Defining the State of a File Descriptor struct StreamState { enum Kind { Opened, Closed K; StreamState(Kind InK) : K(InK) { bool operator==(const StreamState &X) const { return K == X.K; void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(K); ;

Defining the State of a File Descriptor struct StreamState { enum Kind { Opened, Closed K; StreamState(Kind InK) : K(InK) { bool operator==(const StreamState &X) const { return K == X.K; void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(K); bool isopened() const { return K == Opened; bool isclosed() const { return K == Closed; static StreamState getopened() { return StreamState(Opened); static StreamState getclosed() { return StreamState(Closed); ;

Checker State is Part of ProgramState We need to store a map from file handles to StreamState

Checker State is Part of ProgramState We need to store a map from file handles to StreamState When we change states, we ll need to update the map State = State->set<StreamMap>(FileDesc, StreamState::getOpened());

Checker State is Part of ProgramState We need to store a map from file handles to StreamState When we change states, we ll need to update the map State = State->set<StreamMap>(FileDesc, StreamState::getOpened()); Later, we can retrieve the state from the map const StreamState *SS = State->get<StreamMap>(FileDesc);

Checker State is Part of ProgramState We need to store a map from file handles to StreamState When we change states, we ll need to update the map State = State->set<StreamMap>(FileDesc, StreamState::getOpened()); Later, we can retrieve the state from the map const StreamState *SS = State->get<StreamMap>(FileDesc); The map itself must be registered in advance /// Register a map from tracked stream symbols to their state. REGISTER_MAP_WITH_PROGRAMSTATE(StreamMap, SymbolRef, StreamState)

Stream Checker Recipe Define the state of a file descriptor Add state transition corresponding to fopen Add transitions driven by Report error on double close Report error on leak fopen Opened lose reference to symbol Leaked Untracked Closed Double Close

Stream Checker Recipe Define the state of a file descriptor Add state transition corresponding to fopen Add transitions driven by Report error on double close Report error on leak fopen Opened lose reference to symbol Leaked Untracked Closed Double Close

Register for fopen class SimpleStreamChecker : public Checker<check::PostCall> { public: /// Process fopen. void checkpostcall(const CallEvent &Call, CheckerContext &C) const; ; Visitor callbacks are implemented using templates A PostCall visit means the checker is called after processing a call Checkers are stateless! State belongs in ProgramState

Process fopen void SimpleStreamChecker::checkPostCall(const CallEvent &Call, CheckerContext &C) const { if (!Call.isGlobalCFunction("fopen")) return;

Process fopen void SimpleStreamChecker::checkPostCall(const CallEvent &Call, CheckerContext &C) const { if (!Call.isGlobalCFunction("fopen")) return; // Get the symbolic value corresponding to the file handle. SymbolRef FileDesc = Call.getReturnValue().getAsSymbol(); if (!FileDesc) return; Call.getReturnValue() SVals are symbolic execution values Transient, like values in a real program!

Process fopen void SimpleStreamChecker::checkPostCall(const CallEvent &Call, CheckerContext &C) const { if (!Call.isGlobalCFunction("fopen")) return; // Get the symbolic value corresponding to the file handle. SymbolRef FileDesc = Call.getReturnValue().getAsSymbol(); if (!FileDesc) return; SVals are symbolic execution values Transient, like values in a real program! Symbols are a persistent representation of opaque values

Process fopen void SimpleStreamChecker::checkPostCall(const CallEvent &Call, CheckerContext &C) const { if (!Call.isGlobalCFunction("fopen")) return; // Get the symbolic value corresponding to the file handle. SymbolRef FileDesc = Call.getReturnValue().getAsSymbol(); if (!FileDesc) return; // Generate the next transition (an edge in the exploded graph). ProgramStateRef State = C.getState(); State = State->set<StreamMap>(FileDesc, StreamState::getOpened()); C.addTransition(State); SVals are symbolic execution values Transient, like values in a real program! Symbols are a persistent representation of opaque values Checkers add new nodes to the graph with addtransition

Stream Checker Recipe Define the state of a file descriptor Add state transition corresponding to fopen Add transitions driven by Report error on double close Report error on leak fopen Opened lose reference to symbol Leaked Untracked Closed Double Close

Stream Checker Recipe Define the state of a file descriptor Add state transition corresponding to fopen Add transitions driven by Report error on double close Report error on leak fopen Opened lose reference to symbol Leaked Untracked Closed Double Close

Register for class SimpleStreamChecker : public Checker <check::postcall, check::precall > { public: /// Process fopen. void checkpostcall(const CallEvent &Call, CheckerContext &C) const; /// Process. void checkprecall(const CallEvent &Call, CheckerContext &C) const; ; PreCall allows us to check the parameters before the call is processed

Process void SimpleStreamChecker::checkPreCall(const CallEvent &Call, CheckerContext &C) const { // Prototype for is // int (FILE *FileDesc); if (!Call.isGlobalCFunction("") Call.getNumArgs()!= 1) return;

Process void SimpleStreamChecker::checkPreCall(const CallEvent &Call, CheckerContext &C) const { // Prototype for is // int (FILE *FileDesc); if (!Call.isGlobalCFunction("") Call.getNumArgs()!= 1) return; // Get the symbolic value corresponding to the file handle. SymbolRef FileDesc = Call.getArgSVal(0).getAsSymbol(); if (!FileDesc) return;

Process void SimpleStreamChecker::checkPreCall(const CallEvent &Call, CheckerContext &C) const { // Prototype for is // int (FILE *FileDesc); if (!Call.isGlobalCFunction("") Call.getNumArgs()!= 1) return; // Get the symbolic value corresponding to the file handle. SymbolRef FileDesc = Call.getArgSVal(0).getAsSymbol(); if (!FileDesc) return; // Generate the next transition, in which the stream is closed. ProgramStateRef State = C.getState(); State = State->set<StreamMap>(FileDesc, StreamState::getClosed()); C.addTransition(State);

Stream Checker Recipe Define the state of a file descriptor Add state transition corresponding to fopen Add transitions driven by Report error on double close Report error on leak fopen Opened lose reference to symbol Leaked Untracked Closed Double Close

Stream Checker Recipe Define the state of a file descriptor Add state transition corresponding to fopen Add transitions driven by Report error on double close Report error on leak fopen Opened lose reference to symbol Leaked Untracked Closed Double Close

Report Double Close void SimpleStreamChecker::checkPreCall(const CallEvent &Call, CheckerContext &C) const { // Prototype... for is // int (FILE *FileDesc); if (!Call.isGlobalCFunction("") Call.getNumArgs()!= 1) return; // Get the symbolic value corresponding to the file handle. SymbolRef FileDesc = Call.getArgSVal(0).getAsSymbol(); if (!FileDesc) return; // Generate the next transition, in which the stream is closed. ProgramStateRef State = C.getState(); State = State->set<StreamMap>(FileDesc, StreamState::getClosed()); C.addTransition(State);

Report Double Close void SimpleStreamChecker::checkPreCall(const CallEvent &Call, CheckerContext &C) const { //... // Check if the stream has already been closed. const StreamState *SS = C.getState()->get<StreamMap>(FileDesc); if (SS && SS->isClosed()) { reportdoubleclose(filedesc, Call, C); return; // Generate the next transition, in which the stream is closed. ProgramStateRef State = C.getState(); State = State->set<StreamMap>(FileDesc, StreamState::getClosed()); C.addTransition(State);

Generating a BugReport void SimpleStreamChecker::reportDoubleClose(SymbolRef FileDescSym, const CallEvent &Call, CheckerContext &C) const { // We reached a bug, stop exploring the path here by generating a sink. ExplodedNode *ErrNode = C.generateSink();

Generating a BugReport void SimpleStreamChecker::reportDoubleClose(SymbolRef FileDescSym, const CallEvent &Call, CheckerContext &C) const { // We reached a bug, stop exploring the path here by generating a sink. ExplodedNode *ErrNode = C.generateSink(); // If we've already reached this node on another path, return. if (!ErrNode) return;

Generating a BugReport void SimpleStreamChecker::reportDoubleClose(SymbolRef FileDescSym, const CallEvent &Call, CheckerContext &C) const { // We reached a bug, stop exploring the path here by generating a sink. ExplodedNode *ErrNode = C.generateSink(); // If we've already reached this node on another path, return. if (!ErrNode) return; // Generate the report. BugReport *R = new BugReport(*DoubleCloseBugType, "Closing a previously closed file stream", ErrNode); R->addRange(Call.getSourceRange()); R->markInteresting(FileDescSym); C.emitReport(R);

Test Double Close

Test Double Close

Test Double Close

Stream Checker Recipe Define the state of a file descriptor Add state transition corresponding to fopen Add transitions driven by Report error on double close Report error on leak fopen Opened lose reference to symbol Leaked Untracked Closed Double Close

Stream Checker Recipe Define the state of a file descriptor Add state transition corresponding to fopen Add transitions driven by Report error on double close Report error on leak fopen Opened lose reference to symbol Leaked Untracked Closed Double Close

Register for Dead Symbols A dead symbol can never be referenced again along this path Checkers can be notified when symbols die class SimpleStreamChecker : public Checker<check::PostCall, check::precall, check::deadsymbols > {... void checkdeadsymbols(symbolreaper &SymReaper, CheckerContext &C) const; ;

Collect and Report Leaks void SimpleStreamChecker::checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const { ProgramStateRef State = C.getState(); SymbolVector LeakedStreams;

Collect and Report Leaks void SimpleStreamChecker::checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const { ProgramStateRef State = C.getState(); SymbolVector LeakedStreams; StreamMapTy TrackedStreams = State->get<StreamMap>(); for (StreamMapTy::iterator I = TrackedStreams.begin(), E = TrackedStreams.end(); I!= E; ++I) { SymbolRef Sym = I->first;

Collect and Report Leaks void SimpleStreamChecker::checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const { ProgramStateRef State = C.getState(); SymbolVector LeakedStreams; StreamMapTy TrackedStreams = State->get<StreamMap>(); for (StreamMapTy::iterator I = TrackedStreams.begin(), E = TrackedStreams.end(); I!= E; ++I) { SymbolRef Sym = I->first; bool IsSymDead = SymReaper.isDead(Sym);

Collect and Report Leaks void SimpleStreamChecker::checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const { ProgramStateRef State = C.getState(); SymbolVector LeakedStreams; StreamMapTy TrackedStreams = State->get<StreamMap>(); for (StreamMapTy::iterator I = TrackedStreams.begin(), E = TrackedStreams.end(); I!= E; ++I) { SymbolRef Sym = I->first; bool IsSymDead = SymReaper.isDead(Sym); if (isleaked(sym, I->second, IsSymDead)) LeakedStreams.push_back(Sym);

Collect and Report Leaks static bool isleaked(symbolref Sym, const StreamState &SS, bool IsSymDead) { if (IsSymDead && SS.isOpened()) { return true; return false; Future expressions cannot refer to a dead symbol If a dead stream is still open, it s a leak!

Collect and Report Leaks void SimpleStreamChecker::checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const { ProgramStateRef State = C.getState(); SymbolVector LeakedStreams; StreamMapTy TrackedStreams = State->get<StreamMap>(); for (StreamMapTy::iterator I = TrackedStreams.begin(), E = TrackedStreams.end(); I!= E; ++I) { SymbolRef Sym = I->first; bool IsSymDead = SymReaper.isDead(Sym); if (isleaked(sym, I->second, IsSymDead)) LeakedStreams.push_back(Sym);

Collect and Report Leaks void SimpleStreamChecker::checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const { ProgramStateRef State = C.getState(); SymbolVector LeakedStreams; StreamMapTy TrackedStreams = State->get<StreamMap>(); for (StreamMapTy::iterator I = TrackedStreams.begin(), E = TrackedStreams.end(); I!= E; ++I) { SymbolRef Sym = I->first; bool IsSymDead = SymReaper.isDead(Sym); if (isleaked(sym, I->second, IsSymDead)) LeakedStreams.push_back(Sym); ExplodedNode *N = C.addTransition(State); reportleaks(leakedstreams, C, N); Don t create a sink node to keep exploring the given path

Don t Forget to Clean Out the State void SimpleStreamChecker::checkDeadSymbols(SymbolReaper &SymReaper, CheckerContext &C) const { ProgramStateRef State = C.getState(); SymbolVector LeakedStreams; StreamMapTy TrackedStreams = State->get<StreamMap>(); for (StreamMapTy::iterator I = TrackedStreams.begin(), E = TrackedStreams.end(); I!= E; ++I) { SymbolRef Sym = I->first; bool IsSymDead = SymReaper.isDead(Sym); if (isleaked(sym, I->second, IsSymDead)) LeakedStreams.push_back(Sym); if (IsSymDead) State = State->remove<StreamMap>(Sym); ExplodedNode *N = C.addTransition(State); reportleaks(leakedstreams, C, N); Don t create a sink node to keep exploring the given path Will never refer to these symbols again, so keep ProgramState lean

Test Leak

Test Leak

Test Leak

Stream Checker Recipe Define the state of a file descriptor Add state transition corresponding to fopen Add transitions driven by Report error on double close Report error on leak lose reference to symbol fopen Opened Leaked Untracked Closed Double Close

Let s Use the Intro Testcase

Ooops...

Moral: Test Well!

Stream Checker Recipe Define the state of a file descriptor Add state transition corresponding to fopen Add transitions driven by Report error on double close Report error on leak lose reference to symbol fopen Opened Leaked Untracked Closed Double Close

Stream Checker Recipe Define the state of a file descriptor Add state transition corresponding to fopen Add transitions driven by Report error on double close Report error on leak lose reference to symbol fopen Opened if fopen succeeded Leaked Untracked Closed Double Close

Don t Warn If fopen Fails Why don t we just register for PreStmt<IfStmt>? if (F!= 0) { (F); if (F == 0) { ; else { (F); while (F!= 0) { (F); break; FILE *C = F; if (C!= 0) { (F); Need to know if the file handle is constrained to NULL

Let s Refine the Leak Definition static bool isleaked(symbolref Sym, const StreamState &SS, bool IsSymDead) { if (IsSymDead && SS.isOpened()) { return true; return false;

Let s Refine the Leak Definition static bool isleaked(symbolref Sym, const StreamState &SS, bool IsSymDead, ProgramStateRef State) { if (IsSymDead && SS.isOpened()) { // If a symbol is NULL, assume that fopen failed on this path. // A symbol should only be considered leaked if it is non-null. ConstraintManager &CMgr = State->getConstraintManager(); return false;

Let s Refine the Leak Definition static bool isleaked(symbolref Sym, const StreamState &SS, bool IsSymDead, ProgramStateRef State) { if (IsSymDead && SS.isOpened()) { // If a symbol is NULL, assume that fopen failed on this path. // A symbol should only be considered leaked if it is non-null. ConstraintManager &CMgr = State->getConstraintManager(); ConditionTruthVal OpenFailed = CMgr.isNull(State, Sym); return false;

Let s Refine the Leak Definition static bool isleaked(symbolref Sym, const StreamState &SS, bool IsSymDead, ProgramStateRef State) { if (IsSymDead && SS.isOpened()) { // If a symbol is NULL, assume that fopen failed on this path. // A symbol should only be considered leaked if it is non-null. ConstraintManager &CMgr = State->getConstraintManager(); ConditionTruthVal OpenFailed = CMgr.isNull(State, Sym); return false; ConditionTruthVal is a tri-state: True False Unknown fopen failed user did not check fopen succeeded

Let s Refine the Leak Definition static bool isleaked(symbolref Sym, const StreamState &SS, bool IsSymDead, ProgramStateRef State) { if (IsSymDead && SS.isOpened()) { // If a symbol is NULL, assume that fopen failed on this path. // A symbol should only be considered leaked if it is non-null. ConstraintManager &CMgr = State->getConstraintManager(); ConditionTruthVal OpenFailed = CMgr.isNull(State, Sym); return!openfailed.isconstrainedtrue(); return false; ConditionTruthVal is a tri-state: True False Unknown fopen failed user did not check fopen succeeded

Let s See if the False Positive is Gone

We did it!

Homework Checker registration Improving diagnostics Relinquishing ownership Writing more regression tests The checker we wrote today is available at clang/lib/staticanalyzer/checkers/simplestreamchecker.cpp The tests for the checker can be found at clang/tests/analysis/simple-stream-checker.c

Current Limitations Constraint solver is limited Bitwise operations ($F & 0x10) Constraints involving multiple symbols ($X > $Y) Analysis is inter-procedural, but not (yet) cross-translation-unit The analyzer is only as good as its checkers! http://clang-analyzer.llvm.org/potential_checkers.html Patches welcome :-)

Summary The analyzer performs a symbolic, path-sensitive execution of a program Extendable with custom checks Provides comprehensive diagnostics Both plist (Xcode) and HTML output formats are available It is possible to write syntactic (AST-based) checkers as well For more info go to http://clang-analyzer.llvm.org/ Send your questions to cfe-dev mailing list

Clang Static Analyzer Hackathon