Untitled diff

Creado El diff nunca expira
147 eliminaciones
271 líneas
121 adiciones
255 líneas
//===-- SimpleStreamChecker.cpp -----------------------------------------*- C++ -*--//
//===-- SimpleStreamChecker.cpp -----------------------------------------*- C++ -*--//
//
//
// The LLVM Compiler Infrastructure
// The LLVM Compiler Infrastructure
//
//
// This file is distributed under the University of Illinois Open Source
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
// License. See LICENSE.TXT for details.
//
//
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
//
//
// Defines a checker for proper use of fopen/fclose APIs.
// Defines a checker for proper use of fopen/fclose APIs.
// - If a file has been closed with fclose, it should not be accessed again.
// - If a file has been closed with fclose, it should not be accessed again.
// Accessing a closed file results in undefined behavior.
// Accessing a closed file results in undefined behavior.
// - If a file was opened with fopen, it must be closed with fclose before
// - If a file was opened with fopen, it must be closed with fclose before
// the execution ends. Failing to do so results in a resource leak.
// the execution ends. Failing to do so results in a resource leak.
//
//
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//


#include "ClangSACheckers.h"
#include "ClangSACheckers.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"


using namespace clang;
using namespace clang;
using namespace ento;
using namespace ento;


namespace {
namespace {
enum SimpleStreamState { Closed, Opened };
SmartStateTrait SimpleStreamTrait;
typedef SmallVector<SymbolRef, 2> SymbolVector;
typedef SmallVector<SymbolRef, 2> SymbolVector;


struct StreamState {
class SimpleStreamModel
private:
: public Checker<check::ASTDecl<TranslationUnitDecl>, check::PostCall,
enum Kind { Opened, Closed } K;
check::PointerEscape> {
StreamState(Kind InK) : K(InK) { }
CallDescription OpenFn, CloseFn;
bool guaranteedNotToCloseFile(const CallEvent &Call) const;


public:
public:
bool isOpened() const { return K == Opened; }
SimpleStreamModel() : OpenFn("fopen"), CloseFn("fclose") {}
bool isClosed() const { return K == Closed; }


static StreamState getOpened() { return StreamState(Opened); }
void checkASTDecl(const TranslationUnitDecl *D, AnalysisManager &AMgr,
static StreamState getClosed() { return StreamState(Closed); }
BugReporter &BR) const;
void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
Text moved with changes from lines 79-83 (99.5% similarity)
ProgramStateRef checkPointerEscape(ProgramStateRef State,
const InvalidatedSymbols &Escaped,
const CallEvent *Call,
PointerEscapeKind Kind) const;
};
} // end of anonymous namespace


bool operator==(const StreamState &X) const {
bool SimpleStreamModel::guaranteedNotToCloseFile(
return K == X.K;
const CallEvent &Call) const {
Text moved from lines 230-239
// If it's not in a system header, assume it might close a file.
if (!Call.isInSystemHeader())
return false;

// Handle cases where we know a buffer's /address/ can escape.
if (Call.argumentsMayEscape())
return false;

// Note, even though fclose closes the file, we do not list it here
// since the checker is modeling the call.
Text moved from lines 241-243
return true;
}

void SimpleStreamModel::checkASTDecl(const TranslationUnitDecl *D,
AnalysisManager &AMgr,
BugReporter &BR) const {
// Once the AST context is available, we can express the fact that our trait
// has type 'int'.
// FIXME: This is ugly. Maybe make a separate callback, or delay registering
// checkers until AST is constructed?
SimpleStreamTrait.initialize("SimpleStream", AMgr.getASTContext().IntTy);
}

Text moved with changes from lines 117-122 (97.8% similarity)
void SimpleStreamModel::checkPostCall(const CallEvent &Call,
CheckerContext &C) const {
if (!Call.isGlobalCFunction())
return;

if (Call.isCalled(OpenFn)) {
Text moved with changes from lines 124-133 (94.9% similarity)

// 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->bindLoc(SimpleStreamTrait, FileDesc, Opened);
C.addTransition(State);

} else if (Call.isCalled(CloseFn)) {

// Get the symbolic value corresponding to the file handle.
SymbolRef FileDesc = Call.getArgSVal(0).getAsSymbol();
if (!FileDesc)
return;