summaryrefslogtreecommitdiffstats
path: root/clang/lib/StaticAnalyzer/EntoSA/Checkers
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/StaticAnalyzer/EntoSA/Checkers')
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/AdjustedReturnValueChecker.cpp96
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/AnalysisConsumer.cpp610
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/ArrayBoundChecker.cpp91
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/ArrayBoundCheckerV2.cpp277
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/AttrNonNullChecker.cpp136
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/BasicObjCFoundationChecks.cpp521
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/BasicObjCFoundationChecks.h36
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/BuiltinFunctionChecker.cpp83
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/CMakeLists.txt53
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/CStringChecker.cpp1048
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/CallAndMessageChecker.cpp350
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/CastSizeChecker.cpp91
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/CastToStructChecker.cpp79
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/CheckDeadStores.cpp290
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/CheckObjCDealloc.cpp262
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/CheckObjCInstMethSignature.cpp120
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/CheckSecuritySyntaxOnly.cpp503
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/CheckSizeofPointer.cpp72
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/ChrootChecker.cpp162
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/DereferenceChecker.cpp204
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/DivZeroChecker.cpp86
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/ExprEngine.cpp3513
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/ExprEngineExperimentalChecks.cpp46
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/ExprEngineExperimentalChecks.h37
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/ExprEngineInternalChecks.h59
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/FixedAddressChecker.cpp72
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/FrontendActions.cpp22
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/IdempotentOperationChecker.cpp834
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/LLVMConventionsChecker.cpp313
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/MacOSXAPIChecker.cpp142
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/Makefile17
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/MallocChecker.cpp733
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/NSAutoreleasePoolChecker.cpp87
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/NSErrorChecker.cpp238
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/NoReturnFunctionChecker.cpp80
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/OSAtomicChecker.cpp203
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/ObjCAtSyncChecker.cpp95
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/ObjCUnusedIVarsChecker.cpp164
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/PointerArithChecker.cpp72
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/PointerSubChecker.cpp79
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/PthreadLockChecker.cpp147
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/ReturnPointerRangeChecker.cpp95
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/ReturnUndefChecker.cpp69
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/StackAddrLeakChecker.cpp205
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/StreamChecker.cpp466
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/UndefBranchChecker.cpp120
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/UndefCapturedBlockVarChecker.cpp102
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/UndefResultChecker.cpp87
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/UndefinedArraySubscriptChecker.cpp57
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/UndefinedAssignmentChecker.cpp94
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/UnixAPIChecker.cpp277
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/UnreachableCodeChecker.cpp223
-rw-r--r--clang/lib/StaticAnalyzer/EntoSA/Checkers/VLASizeChecker.cpp138
53 files changed, 0 insertions, 14056 deletions
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/AdjustedReturnValueChecker.cpp b/clang/lib/StaticAnalyzer/EntoSA/Checkers/AdjustedReturnValueChecker.cpp
deleted file mode 100644
index 46e2de5c26d..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/AdjustedReturnValueChecker.cpp
+++ /dev/null
@@ -1,96 +0,0 @@
-//== AdjustedReturnValueChecker.cpp -----------------------------*- C++ -*--==//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines AdjustedReturnValueChecker, a simple check to see if the
-// return value of a function call is different than the one the caller thinks
-// it is.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ExprEngineInternalChecks.h"
-#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
-#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
-#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
-
-using namespace clang;
-using namespace ento;
-
-namespace {
-class AdjustedReturnValueChecker :
- public CheckerVisitor<AdjustedReturnValueChecker> {
-public:
- AdjustedReturnValueChecker() {}
-
- void PostVisitCallExpr(CheckerContext &C, const CallExpr *CE);
-
- static void *getTag() {
- static int x = 0; return &x;
- }
-};
-}
-
-void ento::RegisterAdjustedReturnValueChecker(ExprEngine &Eng) {
- Eng.registerCheck(new AdjustedReturnValueChecker());
-}
-
-void AdjustedReturnValueChecker::PostVisitCallExpr(CheckerContext &C,
- const CallExpr *CE) {
-
- // Get the result type of the call.
- QualType expectedResultTy = CE->getType();
-
- // Fetch the signature of the called function.
- const GRState *state = C.getState();
-
- SVal V = state->getSVal(CE);
-
- if (V.isUnknown())
- return;
-
- // Casting to void? Discard the value.
- if (expectedResultTy->isVoidType()) {
- C.generateNode(state->BindExpr(CE, UnknownVal()));
- return;
- }
-
- const MemRegion *callee = state->getSVal(CE->getCallee()).getAsRegion();
- if (!callee)
- return;
-
- QualType actualResultTy;
-
- if (const FunctionTextRegion *FT = dyn_cast<FunctionTextRegion>(callee)) {
- const FunctionDecl *FD = FT->getDecl();
- actualResultTy = FD->getResultType();
- }
- else if (const BlockDataRegion *BD = dyn_cast<BlockDataRegion>(callee)) {
- const BlockTextRegion *BR = BD->getCodeRegion();
- const BlockPointerType *BT=BR->getLocationType()->getAs<BlockPointerType>();
- const FunctionType *FT = BT->getPointeeType()->getAs<FunctionType>();
- actualResultTy = FT->getResultType();
- }
-
- // Can this happen?
- if (actualResultTy.isNull())
- return;
-
- // For now, ignore references.
- if (actualResultTy->getAs<ReferenceType>())
- return;
-
-
- // Are they the same?
- if (expectedResultTy != actualResultTy) {
- // FIXME: Do more checking and actual emit an error. At least performing
- // the cast avoids some assertion failures elsewhere.
- SValBuilder &svalBuilder = C.getSValBuilder();
- V = svalBuilder.evalCast(V, expectedResultTy, actualResultTy);
- C.generateNode(state->BindExpr(CE, V));
- }
-}
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/AnalysisConsumer.cpp b/clang/lib/StaticAnalyzer/EntoSA/Checkers/AnalysisConsumer.cpp
deleted file mode 100644
index ee4eae2ebfa..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/AnalysisConsumer.cpp
+++ /dev/null
@@ -1,610 +0,0 @@
-//===--- AnalysisConsumer.cpp - ASTConsumer for running Analyses ----------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// "Meta" ASTConsumer for running different source analyses.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/StaticAnalyzer/AnalysisConsumer.h"
-#include "clang/AST/ASTConsumer.h"
-#include "clang/AST/Decl.h"
-#include "clang/AST/DeclCXX.h"
-#include "clang/AST/DeclObjC.h"
-#include "clang/AST/ParentMap.h"
-#include "clang/Analysis/Analyses/LiveVariables.h"
-#include "clang/Analysis/Analyses/UninitializedValues.h"
-#include "clang/Analysis/CFG.h"
-#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
-#include "clang/StaticAnalyzer/ManagerRegistry.h"
-#include "clang/StaticAnalyzer/BugReporter/PathDiagnostic.h"
-#include "clang/StaticAnalyzer/PathSensitive/AnalysisManager.h"
-#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
-#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
-#include "clang/StaticAnalyzer/PathSensitive/TransferFuncs.h"
-#include "clang/StaticAnalyzer/PathDiagnosticClients.h"
-
-// FIXME: Restructure checker registration.
-#include "ExprEngineExperimentalChecks.h"
-#include "ExprEngineInternalChecks.h"
-
-#include "clang/Basic/FileManager.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/Frontend/AnalyzerOptions.h"
-#include "clang/Lex/Preprocessor.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/Program.h"
-#include "llvm/ADT/OwningPtr.h"
-
-using namespace clang;
-using namespace ento;
-
-static ExplodedNode::Auditor* CreateUbiViz();
-
-//===----------------------------------------------------------------------===//
-// Special PathDiagnosticClients.
-//===----------------------------------------------------------------------===//
-
-static PathDiagnosticClient*
-createPlistHTMLDiagnosticClient(const std::string& prefix,
- const Preprocessor &PP) {
- PathDiagnosticClient *PD =
- createHTMLDiagnosticClient(llvm::sys::path::parent_path(prefix), PP);
- return createPlistDiagnosticClient(prefix, PP, PD);
-}
-
-//===----------------------------------------------------------------------===//
-// AnalysisConsumer declaration.
-//===----------------------------------------------------------------------===//
-
-namespace {
-
-class AnalysisConsumer : public ASTConsumer {
-public:
- typedef void (*CodeAction)(AnalysisConsumer &C, AnalysisManager &M, Decl *D);
- typedef void (*TUAction)(AnalysisConsumer &C, AnalysisManager &M,
- TranslationUnitDecl &TU);
-
-private:
- typedef std::vector<CodeAction> Actions;
- typedef std::vector<TUAction> TUActions;
-
- Actions FunctionActions;
- Actions ObjCMethodActions;
- Actions ObjCImplementationActions;
- Actions CXXMethodActions;
- TUActions TranslationUnitActions; // Remove this.
-
-public:
- ASTContext* Ctx;
- const Preprocessor &PP;
- const std::string OutDir;
- AnalyzerOptions Opts;
-
- // PD is owned by AnalysisManager.
- PathDiagnosticClient *PD;
-
- StoreManagerCreator CreateStoreMgr;
- ConstraintManagerCreator CreateConstraintMgr;
-
- llvm::OwningPtr<AnalysisManager> Mgr;
-
- AnalysisConsumer(const Preprocessor& pp,
- const std::string& outdir,
- const AnalyzerOptions& opts)
- : Ctx(0), PP(pp), OutDir(outdir),
- Opts(opts), PD(0) {
- DigestAnalyzerOptions();
- }
-
- void DigestAnalyzerOptions() {
- // Create the PathDiagnosticClient.
- if (!OutDir.empty()) {
- switch (Opts.AnalysisDiagOpt) {
- default:
-#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN, AUTOCREATE) \
- case PD_##NAME: PD = CREATEFN(OutDir, PP); break;
-#include "clang/Frontend/Analyses.def"
- }
- } else if (Opts.AnalysisDiagOpt == PD_TEXT) {
- // Create the text client even without a specified output file since
- // it just uses diagnostic notes.
- PD = createTextPathDiagnosticClient("", PP);
- }
-
- // Create the analyzer component creators.
- if (ManagerRegistry::StoreMgrCreator != 0) {
- CreateStoreMgr = ManagerRegistry::StoreMgrCreator;
- }
- else {
- switch (Opts.AnalysisStoreOpt) {
- default:
- assert(0 && "Unknown store manager.");
-#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATEFN) \
- case NAME##Model: CreateStoreMgr = CREATEFN; break;
-#include "clang/Frontend/Analyses.def"
- }
- }
-
- if (ManagerRegistry::ConstraintMgrCreator != 0)
- CreateConstraintMgr = ManagerRegistry::ConstraintMgrCreator;
- else {
- switch (Opts.AnalysisConstraintsOpt) {
- default:
- assert(0 && "Unknown store manager.");
-#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATEFN) \
- case NAME##Model: CreateConstraintMgr = CREATEFN; break;
-#include "clang/Frontend/Analyses.def"
- }
- }
- }
-
- void DisplayFunction(const Decl *D) {
- if (!Opts.AnalyzerDisplayProgress)
- return;
-
- SourceManager &SM = Mgr->getASTContext().getSourceManager();
- PresumedLoc Loc = SM.getPresumedLoc(D->getLocation());
- if (Loc.isValid()) {
- llvm::errs() << "ANALYZE: " << Loc.getFilename();
-
- if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) {
- const NamedDecl *ND = cast<NamedDecl>(D);
- llvm::errs() << ' ' << ND << '\n';
- }
- else if (isa<BlockDecl>(D)) {
- llvm::errs() << ' ' << "block(line:" << Loc.getLine() << ",col:"
- << Loc.getColumn() << '\n';
- }
- else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
- Selector S = MD->getSelector();
- llvm::errs() << ' ' << S.getAsString();
- }
- }
- }
-
- void addCodeAction(CodeAction action) {
- FunctionActions.push_back(action);
- ObjCMethodActions.push_back(action);
- CXXMethodActions.push_back(action);
- }
-
- void addTranslationUnitAction(TUAction action) {
- TranslationUnitActions.push_back(action);
- }
-
- void addObjCImplementationAction(CodeAction action) {
- ObjCImplementationActions.push_back(action);
- }
-
- virtual void Initialize(ASTContext &Context) {
- Ctx = &Context;
- Mgr.reset(new AnalysisManager(*Ctx, PP.getDiagnostics(),
- PP.getLangOptions(), PD,
- CreateStoreMgr, CreateConstraintMgr,
- /* Indexer */ 0,
- Opts.MaxNodes, Opts.MaxLoop,
- Opts.VisualizeEGDot, Opts.VisualizeEGUbi,
- Opts.PurgeDead, Opts.EagerlyAssume,
- Opts.TrimGraph, Opts.InlineCall,
- Opts.UnoptimizedCFG, Opts.CFGAddImplicitDtors,
- Opts.CFGAddInitializers));
- }
-
- virtual void HandleTranslationUnit(ASTContext &C);
- void HandleCode(Decl *D, Actions& actions);
-};
-} // end anonymous namespace
-
-//===----------------------------------------------------------------------===//
-// AnalysisConsumer implementation.
-//===----------------------------------------------------------------------===//
-
-void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {
-
- TranslationUnitDecl *TU = C.getTranslationUnitDecl();
-
- for (DeclContext::decl_iterator I = TU->decls_begin(), E = TU->decls_end();
- I != E; ++I) {
- Decl *D = *I;
-
- switch (D->getKind()) {
- case Decl::CXXConstructor:
- case Decl::CXXDestructor:
- case Decl::CXXConversion:
- case Decl::CXXMethod:
- case Decl::Function: {
- FunctionDecl* FD = cast<FunctionDecl>(D);
- // We skip function template definitions, as their semantics is
- // only determined when they are instantiated.
- if (FD->isThisDeclarationADefinition() &&
- !FD->isDependentContext()) {
- if (!Opts.AnalyzeSpecificFunction.empty() &&
- FD->getDeclName().getAsString() != Opts.AnalyzeSpecificFunction)
- break;
- DisplayFunction(FD);
- HandleCode(FD, FunctionActions);
- }
- break;
- }
-
- case Decl::ObjCImplementation: {
- ObjCImplementationDecl* ID = cast<ObjCImplementationDecl>(*I);
- HandleCode(ID, ObjCImplementationActions);
-
- for (ObjCImplementationDecl::method_iterator MI = ID->meth_begin(),
- ME = ID->meth_end(); MI != ME; ++MI) {
- if ((*MI)->isThisDeclarationADefinition()) {
- if (!Opts.AnalyzeSpecificFunction.empty() &&
- Opts.AnalyzeSpecificFunction != (*MI)->getSelector().getAsString())
- break;
- DisplayFunction(*MI);
- HandleCode(*MI, ObjCMethodActions);
- }
- }
- break;
- }
-
- default:
- break;
- }
- }
-
- for (TUActions::iterator I = TranslationUnitActions.begin(),
- E = TranslationUnitActions.end(); I != E; ++I) {
- (*I)(*this, *Mgr, *TU);
- }
-
- // Explicitly destroy the PathDiagnosticClient. This will flush its output.
- // FIXME: This should be replaced with something that doesn't rely on
- // side-effects in PathDiagnosticClient's destructor. This is required when
- // used with option -disable-free.
- Mgr.reset(NULL);
-}
-
-static void FindBlocks(DeclContext *D, llvm::SmallVectorImpl<Decl*> &WL) {
- if (BlockDecl *BD = dyn_cast<BlockDecl>(D))
- WL.push_back(BD);
-
- for (DeclContext::decl_iterator I = D->decls_begin(), E = D->decls_end();
- I!=E; ++I)
- if (DeclContext *DC = dyn_cast<DeclContext>(*I))
- FindBlocks(DC, WL);
-}
-
-void AnalysisConsumer::HandleCode(Decl *D, Actions& actions) {
-
- // Don't run the actions if an error has occured with parsing the file.
- Diagnostic &Diags = PP.getDiagnostics();
- if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred())
- return;
-
- // Don't run the actions on declarations in header files unless
- // otherwise specified.
- SourceManager &SM = Ctx->getSourceManager();
- SourceLocation SL = SM.getInstantiationLoc(D->getLocation());
- if (!Opts.AnalyzeAll && !SM.isFromMainFile(SL))
- return;
-
- // Clear the AnalysisManager of old AnalysisContexts.
- Mgr->ClearContexts();
-
- // Dispatch on the actions.
- llvm::SmallVector<Decl*, 10> WL;
- WL.push_back(D);
-
- if (D->hasBody() && Opts.AnalyzeNestedBlocks)
- FindBlocks(cast<DeclContext>(D), WL);
-
- for (Actions::iterator I = actions.begin(), E = actions.end(); I != E; ++I)
- for (llvm::SmallVectorImpl<Decl*>::iterator WI=WL.begin(), WE=WL.end();
- WI != WE; ++WI)
- (*I)(*this, *Mgr, *WI);
-}
-
-//===----------------------------------------------------------------------===//
-// Analyses
-//===----------------------------------------------------------------------===//
-
-static void ActionWarnDeadStores(AnalysisConsumer &C, AnalysisManager& mgr,
- Decl *D) {
- if (LiveVariables *L = mgr.getLiveVariables(D)) {
- BugReporter BR(mgr);
- CheckDeadStores(*mgr.getCFG(D), *L, mgr.getParentMap(D), BR);
- }
-}
-
-static void ActionWarnUninitVals(AnalysisConsumer &C, AnalysisManager& mgr,
- Decl *D) {
- if (CFG* c = mgr.getCFG(D)) {
- CheckUninitializedValues(*c, mgr.getASTContext(), mgr.getDiagnostic());
- }
-}
-
-
-static void ActionExprEngine(AnalysisConsumer &C, AnalysisManager& mgr,
- Decl *D,
- TransferFuncs* tf) {
-
- llvm::OwningPtr<TransferFuncs> TF(tf);
-
- // Construct the analysis engine. We first query for the LiveVariables
- // information to see if the CFG is valid.
- // FIXME: Inter-procedural analysis will need to handle invalid CFGs.
- if (!mgr.getLiveVariables(D))
- return;
- ExprEngine Eng(mgr, TF.take());
-
- if (C.Opts.EnableExperimentalInternalChecks)
- RegisterExperimentalInternalChecks(Eng);
-
- RegisterAppleChecks(Eng, *D);
-
- if (C.Opts.EnableExperimentalChecks)
- RegisterExperimentalChecks(Eng);
-
- // Enable idempotent operation checking if it was explicitly turned on, or if
- // we are running experimental checks (i.e. everything)
- if (C.Opts.IdempotentOps || C.Opts.EnableExperimentalChecks
- || C.Opts.EnableExperimentalInternalChecks)
- RegisterIdempotentOperationChecker(Eng);
-
- if (C.Opts.BufferOverflows)
- RegisterArrayBoundCheckerV2(Eng);
-
- // Enable AnalyzerStatsChecker if it was given as an argument
- if (C.Opts.AnalyzerStats)
- RegisterAnalyzerStatsChecker(Eng);
-
- // Set the graph auditor.
- llvm::OwningPtr<ExplodedNode::Auditor> Auditor;
- if (mgr.shouldVisualizeUbigraph()) {
- Auditor.reset(CreateUbiViz());
- ExplodedNode::SetAuditor(Auditor.get());
- }
-
- // Execute the worklist algorithm.
- Eng.ExecuteWorkList(mgr.getStackFrame(D, 0), mgr.getMaxNodes());
-
- // Release the auditor (if any) so that it doesn't monitor the graph
- // created BugReporter.
- ExplodedNode::SetAuditor(0);
-
- // Visualize the exploded graph.
- if (mgr.shouldVisualizeGraphviz())
- Eng.ViewGraph(mgr.shouldTrimGraph());
-
- // Display warnings.
- Eng.getBugReporter().FlushReports();
-}
-
-static void ActionObjCMemCheckerAux(AnalysisConsumer &C, AnalysisManager& mgr,
- Decl *D, bool GCEnabled) {
-
- TransferFuncs* TF = MakeCFRefCountTF(mgr.getASTContext(),
- GCEnabled,
- mgr.getLangOptions());
-
- ActionExprEngine(C, mgr, D, TF);
-}
-
-static void ActionObjCMemChecker(AnalysisConsumer &C, AnalysisManager& mgr,
- Decl *D) {
-
- switch (mgr.getLangOptions().getGCMode()) {
- default:
- assert (false && "Invalid GC mode.");
- case LangOptions::NonGC:
- ActionObjCMemCheckerAux(C, mgr, D, false);
- break;
-
- case LangOptions::GCOnly:
- ActionObjCMemCheckerAux(C, mgr, D, true);
- break;
-
- case LangOptions::HybridGC:
- ActionObjCMemCheckerAux(C, mgr, D, false);
- ActionObjCMemCheckerAux(C, mgr, D, true);
- break;
- }
-}
-
-static void ActionDisplayLiveVariables(AnalysisConsumer &C,
- AnalysisManager& mgr, Decl *D) {
- if (LiveVariables* L = mgr.getLiveVariables(D)) {
- L->dumpBlockLiveness(mgr.getSourceManager());
- }
-}
-
-static void ActionCFGDump(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D) {
- if (CFG *cfg = mgr.getCFG(D)) {
- cfg->dump(mgr.getLangOptions());
- }
-}
-
-static void ActionCFGView(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D) {
- if (CFG *cfg = mgr.getCFG(D)) {
- cfg->viewCFG(mgr.getLangOptions());
- }
-}
-
-static void ActionSecuritySyntacticChecks(AnalysisConsumer &C,
- AnalysisManager &mgr, Decl *D) {
- BugReporter BR(mgr);
- CheckSecuritySyntaxOnly(D, BR);
-}
-
-static void ActionLLVMConventionChecker(AnalysisConsumer &C,
- AnalysisManager &mgr,
- TranslationUnitDecl &TU) {
- BugReporter BR(mgr);
- CheckLLVMConventions(TU, BR);
-}
-
-static void ActionWarnObjCDealloc(AnalysisConsumer &C, AnalysisManager& mgr,
- Decl *D) {
- if (mgr.getLangOptions().getGCMode() == LangOptions::GCOnly)
- return;
- BugReporter BR(mgr);
- CheckObjCDealloc(cast<ObjCImplementationDecl>(D), mgr.getLangOptions(), BR);
-}
-
-static void ActionWarnObjCUnusedIvars(AnalysisConsumer &C, AnalysisManager& mgr,
- Decl *D) {
- BugReporter BR(mgr);
- CheckObjCUnusedIvar(cast<ObjCImplementationDecl>(D), BR);
-}
-
-static void ActionWarnObjCMethSigs(AnalysisConsumer &C, AnalysisManager& mgr,
- Decl *D) {
- BugReporter BR(mgr);
- CheckObjCInstMethSignature(cast<ObjCImplementationDecl>(D), BR);
-}
-
-static void ActionWarnSizeofPointer(AnalysisConsumer &C, AnalysisManager &mgr,
- Decl *D) {
- BugReporter BR(mgr);
- CheckSizeofPointer(D, BR);
-}
-
-//===----------------------------------------------------------------------===//
-// AnalysisConsumer creation.
-//===----------------------------------------------------------------------===//
-
-ASTConsumer* ento::CreateAnalysisConsumer(const Preprocessor& pp,
- const std::string& OutDir,
- const AnalyzerOptions& Opts) {
- llvm::OwningPtr<AnalysisConsumer> C(new AnalysisConsumer(pp, OutDir, Opts));
-
- for (unsigned i = 0; i < Opts.AnalysisList.size(); ++i)
- switch (Opts.AnalysisList[i]) {
-#define ANALYSIS(NAME, CMD, DESC, SCOPE)\
- case NAME:\
- C->add ## SCOPE ## Action(&Action ## NAME);\
- break;
-#include "clang/Frontend/Analyses.def"
- default: break;
- }
-
- // Last, disable the effects of '-Werror' when using the AnalysisConsumer.
- pp.getDiagnostics().setWarningsAsErrors(false);
-
- return C.take();
-}
-
-//===----------------------------------------------------------------------===//
-// Ubigraph Visualization. FIXME: Move to separate file.
-//===----------------------------------------------------------------------===//
-
-namespace {
-
-class UbigraphViz : public ExplodedNode::Auditor {
- llvm::OwningPtr<llvm::raw_ostream> Out;
- llvm::sys::Path Dir, Filename;
- unsigned Cntr;
-
- typedef llvm::DenseMap<void*,unsigned> VMap;
- VMap M;
-
-public:
- UbigraphViz(llvm::raw_ostream* out, llvm::sys::Path& dir,
- llvm::sys::Path& filename);
-
- ~UbigraphViz();
-
- virtual void AddEdge(ExplodedNode* Src, ExplodedNode* Dst);
-};
-
-} // end anonymous namespace
-
-static ExplodedNode::Auditor* CreateUbiViz() {
- std::string ErrMsg;
-
- llvm::sys::Path Dir = llvm::sys::Path::GetTemporaryDirectory(&ErrMsg);
- if (!ErrMsg.empty())
- return 0;
-
- llvm::sys::Path Filename = Dir;
- Filename.appendComponent("llvm_ubi");
- Filename.makeUnique(true,&ErrMsg);
-
- if (!ErrMsg.empty())
- return 0;
-
- llvm::errs() << "Writing '" << Filename.str() << "'.\n";
-
- llvm::OwningPtr<llvm::raw_fd_ostream> Stream;
- Stream.reset(new llvm::raw_fd_ostream(Filename.c_str(), ErrMsg));
-
- if (!ErrMsg.empty())
- return 0;
-
- return new UbigraphViz(Stream.take(), Dir, Filename);
-}
-
-void UbigraphViz::AddEdge(ExplodedNode* Src, ExplodedNode* Dst) {
-
- assert (Src != Dst && "Self-edges are not allowed.");
-
- // Lookup the Src. If it is a new node, it's a root.
- VMap::iterator SrcI= M.find(Src);
- unsigned SrcID;
-
- if (SrcI == M.end()) {
- M[Src] = SrcID = Cntr++;
- *Out << "('vertex', " << SrcID << ", ('color','#00ff00'))\n";
- }
- else
- SrcID = SrcI->second;
-
- // Lookup the Dst.
- VMap::iterator DstI= M.find(Dst);
- unsigned DstID;
-
- if (DstI == M.end()) {
- M[Dst] = DstID = Cntr++;
- *Out << "('vertex', " << DstID << ")\n";
- }
- else {
- // We have hit DstID before. Change its style to reflect a cache hit.
- DstID = DstI->second;
- *Out << "('change_vertex_style', " << DstID << ", 1)\n";
- }
-
- // Add the edge.
- *Out << "('edge', " << SrcID << ", " << DstID
- << ", ('arrow','true'), ('oriented', 'true'))\n";
-}
-
-UbigraphViz::UbigraphViz(llvm::raw_ostream* out, llvm::sys::Path& dir,
- llvm::sys::Path& filename)
- : Out(out), Dir(dir), Filename(filename), Cntr(0) {
-
- *Out << "('vertex_style_attribute', 0, ('shape', 'icosahedron'))\n";
- *Out << "('vertex_style', 1, 0, ('shape', 'sphere'), ('color', '#ffcc66'),"
- " ('size', '1.5'))\n";
-}
-
-UbigraphViz::~UbigraphViz() {
- Out.reset(0);
- llvm::errs() << "Running 'ubiviz' program... ";
- std::string ErrMsg;
- llvm::sys::Path Ubiviz = llvm::sys::Program::FindProgramByName("ubiviz");
- std::vector<const char*> args;
- args.push_back(Ubiviz.c_str());
- args.push_back(Filename.c_str());
- args.push_back(0);
-
- if (llvm::sys::Program::ExecuteAndWait(Ubiviz, &args[0],0,0,0,0,&ErrMsg)) {
- llvm::errs() << "Error viewing graph: " << ErrMsg << "\n";
- }
-
- // Delete the directory.
- Dir.eraseFromDisk(true);
-}
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/ArrayBoundChecker.cpp b/clang/lib/StaticAnalyzer/EntoSA/Checkers/ArrayBoundChecker.cpp
deleted file mode 100644
index 13e628bcb1a..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/ArrayBoundChecker.cpp
+++ /dev/null
@@ -1,91 +0,0 @@
-//== ArrayBoundChecker.cpp ------------------------------*- C++ -*--==//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines ArrayBoundChecker, which is a path-sensitive check
-// which looks for an out-of-bound array element access.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ExprEngineInternalChecks.h"
-#include "clang/StaticAnalyzer/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
-#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
-
-using namespace clang;
-using namespace ento;
-
-namespace {
-class ArrayBoundChecker :
- public CheckerVisitor<ArrayBoundChecker> {
- BuiltinBug *BT;
-public:
- ArrayBoundChecker() : BT(0) {}
- static void *getTag() { static int x = 0; return &x; }
- void visitLocation(CheckerContext &C, const Stmt *S, SVal l);
-};
-}
-
-void ento::RegisterArrayBoundChecker(ExprEngine &Eng) {
- Eng.registerCheck(new ArrayBoundChecker());
-}
-
-void ArrayBoundChecker::visitLocation(CheckerContext &C, const Stmt *S, SVal l){
- // Check for out of bound array element access.
- const MemRegion *R = l.getAsRegion();
- if (!R)
- return;
-
- const ElementRegion *ER = dyn_cast<ElementRegion>(R);
- if (!ER)
- return;
-
- // Get the index of the accessed element.
- DefinedOrUnknownSVal Idx = cast<DefinedOrUnknownSVal>(ER->getIndex());
-
- // Zero index is always in bound, this also passes ElementRegions created for
- // pointer casts.
- if (Idx.isZeroConstant())
- return;
-
- const GRState *state = C.getState();
-
- // Get the size of the array.
- DefinedOrUnknownSVal NumElements
- = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion(),
- ER->getValueType());
-
- const GRState *StInBound = state->assumeInBound(Idx, NumElements, true);
- const GRState *StOutBound = state->assumeInBound(Idx, NumElements, false);
- if (StOutBound && !StInBound) {
- ExplodedNode *N = C.generateSink(StOutBound);
- if (!N)
- return;
-
- if (!BT)
- BT = new BuiltinBug("Out-of-bound array access",
- "Access out-of-bound array element (buffer overflow)");
-
- // FIXME: It would be nice to eventually make this diagnostic more clear,
- // e.g., by referencing the original declaration or by saying *why* this
- // reference is outside the range.
-
- // Generate a report for this bug.
- RangedBugReport *report =
- new RangedBugReport(*BT, BT->getDescription(), N);
-
- report->addRange(S->getSourceRange());
- C.EmitReport(report);
- return;
- }
-
- // Array bound check succeeded. From this point forward the array bound
- // should always succeed.
- assert(StInBound);
- C.addTransition(StInBound);
-}
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/ArrayBoundCheckerV2.cpp b/clang/lib/StaticAnalyzer/EntoSA/Checkers/ArrayBoundCheckerV2.cpp
deleted file mode 100644
index b55fadebf87..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/ArrayBoundCheckerV2.cpp
+++ /dev/null
@@ -1,277 +0,0 @@
-//== ArrayBoundCheckerV2.cpp ------------------------------------*- C++ -*--==//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines ArrayBoundCheckerV2, which is a path-sensitive check
-// which looks for an out-of-bound array element access.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ExprEngineInternalChecks.h"
-#include "clang/StaticAnalyzer/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
-#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
-#include "clang/AST/CharUnits.h"
-
-using namespace clang;
-using namespace ento;
-
-namespace {
-class ArrayBoundCheckerV2 :
- public CheckerVisitor<ArrayBoundCheckerV2> {
- BuiltinBug *BT;
-
- enum OOB_Kind { OOB_Precedes, OOB_Excedes };
-
- void reportOOB(CheckerContext &C, const GRState *errorState,
- OOB_Kind kind);
-
-public:
- ArrayBoundCheckerV2() : BT(0) {}
- static void *getTag() { static int x = 0; return &x; }
- void visitLocation(CheckerContext &C, const Stmt *S, SVal l);
-};
-
-// FIXME: Eventually replace RegionRawOffset with this class.
-class RegionRawOffsetV2 {
-private:
- const SubRegion *baseRegion;
- SVal byteOffset;
-
- RegionRawOffsetV2()
- : baseRegion(0), byteOffset(UnknownVal()) {}
-
-public:
- RegionRawOffsetV2(const SubRegion* base, SVal offset)
- : baseRegion(base), byteOffset(offset) {}
-
- NonLoc getByteOffset() const { return cast<NonLoc>(byteOffset); }
- const SubRegion *getRegion() const { return baseRegion; }
-
- static RegionRawOffsetV2 computeOffset(const GRState *state,
- SValBuilder &svalBuilder,
- SVal location);
-
- void dump() const;
- void dumpToStream(llvm::raw_ostream& os) const;
-};
-}
-
-void ento::RegisterArrayBoundCheckerV2(ExprEngine &Eng) {
- Eng.registerCheck(new ArrayBoundCheckerV2());
-}
-
-void ArrayBoundCheckerV2::visitLocation(CheckerContext &checkerContext,
- const Stmt *S,
- SVal location) {
-
- // NOTE: Instead of using GRState::assumeInBound(), we are prototyping
- // some new logic here that reasons directly about memory region extents.
- // Once that logic is more mature, we can bring it back to assumeInBound()
- // for all clients to use.
- //
- // The algorithm we are using here for bounds checking is to see if the
- // memory access is within the extent of the base region. Since we
- // have some flexibility in defining the base region, we can achieve
- // various levels of conservatism in our buffer overflow checking.
- const GRState *state = checkerContext.getState();
- const GRState *originalState = state;
-
- SValBuilder &svalBuilder = checkerContext.getSValBuilder();
- const RegionRawOffsetV2 &rawOffset =
- RegionRawOffsetV2::computeOffset(state, svalBuilder, location);
-
- if (!rawOffset.getRegion())
- return;
-
- // CHECK LOWER BOUND: Is byteOffset < 0? If so, we are doing a load/store
- // before the first valid offset in the memory region.
-
- SVal lowerBound
- = svalBuilder.evalBinOpNN(state, BO_LT, rawOffset.getByteOffset(),
- svalBuilder.makeZeroArrayIndex(),
- svalBuilder.getConditionType());
-
- NonLoc *lowerBoundToCheck = dyn_cast<NonLoc>(&lowerBound);
- if (!lowerBoundToCheck)
- return;
-
- const GRState *state_precedesLowerBound, *state_withinLowerBound;
- llvm::tie(state_precedesLowerBound, state_withinLowerBound) =
- state->assume(*lowerBoundToCheck);
-
- // Are we constrained enough to definitely precede the lower bound?
- if (state_precedesLowerBound && !state_withinLowerBound) {
- reportOOB(checkerContext, state_precedesLowerBound, OOB_Precedes);
- return;
- }
-
- // Otherwise, assume the constraint of the lower bound.
- assert(state_withinLowerBound);
- state = state_withinLowerBound;
-
- do {
- // CHECK UPPER BOUND: Is byteOffset >= extent(baseRegion)? If so,
- // we are doing a load/store after the last valid offset.
- DefinedOrUnknownSVal extentVal =
- rawOffset.getRegion()->getExtent(svalBuilder);
- if (!isa<NonLoc>(extentVal))
- break;
-
- SVal upperbound
- = svalBuilder.evalBinOpNN(state, BO_GE, rawOffset.getByteOffset(),
- cast<NonLoc>(extentVal),
- svalBuilder.getConditionType());
-
- NonLoc *upperboundToCheck = dyn_cast<NonLoc>(&upperbound);
- if (!upperboundToCheck)
- break;
-
- const GRState *state_exceedsUpperBound, *state_withinUpperBound;
- llvm::tie(state_exceedsUpperBound, state_withinUpperBound) =
- state->assume(*upperboundToCheck);
-
- // Are we constrained enough to definitely exceed the upper bound?
- if (state_exceedsUpperBound && !state_withinUpperBound) {
- reportOOB(checkerContext, state_exceedsUpperBound, OOB_Excedes);
- return;
- }
-
- assert(state_withinUpperBound);
- state = state_withinUpperBound;
- }
- while (false);
-
- if (state != originalState)
- checkerContext.generateNode(state);
-}
-
-void ArrayBoundCheckerV2::reportOOB(CheckerContext &checkerContext,
- const GRState *errorState,
- OOB_Kind kind) {
-
- ExplodedNode *errorNode = checkerContext.generateSink(errorState);
- if (!errorNode)
- return;
-
- if (!BT)
- BT = new BuiltinBug("Out-of-bound access");
-
- // FIXME: This diagnostics are preliminary. We should get far better
- // diagnostics for explaining buffer overruns.
-
- llvm::SmallString<256> buf;
- llvm::raw_svector_ostream os(buf);
- os << "Out of bound memory access "
- << (kind == OOB_Precedes ? "(accessed memory precedes memory block)"
- : "(access exceeds upper limit of memory block)");
-
- checkerContext.EmitReport(new RangedBugReport(*BT, os.str(), errorNode));
-}
-
-void RegionRawOffsetV2::dump() const {
- dumpToStream(llvm::errs());
-}
-
-void RegionRawOffsetV2::dumpToStream(llvm::raw_ostream& os) const {
- os << "raw_offset_v2{" << getRegion() << ',' << getByteOffset() << '}';
-}
-
-// FIXME: Merge with the implementation of the same method in Store.cpp
-static bool IsCompleteType(ASTContext &Ctx, QualType Ty) {
- if (const RecordType *RT = Ty->getAs<RecordType>()) {
- const RecordDecl *D = RT->getDecl();
- if (!D->getDefinition())
- return false;
- }
-
- return true;
-}
-
-
-// Lazily computes a value to be used by 'computeOffset'. If 'val'
-// is unknown or undefined, we lazily substitute '0'. Otherwise,
-// return 'val'.
-static inline SVal getValue(SVal val, SValBuilder &svalBuilder) {
- return isa<UndefinedVal>(val) ? svalBuilder.makeArrayIndex(0) : val;
-}
-
-// Scale a base value by a scaling factor, and return the scaled
-// value as an SVal. Used by 'computeOffset'.
-static inline SVal scaleValue(const GRState *state,
- NonLoc baseVal, CharUnits scaling,
- SValBuilder &sb) {
- return sb.evalBinOpNN(state, BO_Mul, baseVal,
- sb.makeArrayIndex(scaling.getQuantity()),
- sb.getArrayIndexType());
-}
-
-// Add an SVal to another, treating unknown and undefined values as
-// summing to UnknownVal. Used by 'computeOffset'.
-static SVal addValue(const GRState *state, SVal x, SVal y,
- SValBuilder &svalBuilder) {
- // We treat UnknownVals and UndefinedVals the same here because we
- // only care about computing offsets.
- if (x.isUnknownOrUndef() || y.isUnknownOrUndef())
- return UnknownVal();
-
- return svalBuilder.evalBinOpNN(state, BO_Add,
- cast<NonLoc>(x), cast<NonLoc>(y),
- svalBuilder.getArrayIndexType());
-}
-
-/// Compute a raw byte offset from a base region. Used for array bounds
-/// checking.
-RegionRawOffsetV2 RegionRawOffsetV2::computeOffset(const GRState *state,
- SValBuilder &svalBuilder,
- SVal location)
-{
- const MemRegion *region = location.getAsRegion();
- SVal offset = UndefinedVal();
-
- while (region) {
- switch (region->getKind()) {
- default: {
- if (const SubRegion *subReg = dyn_cast<SubRegion>(region))
- if (!offset.isUnknownOrUndef())
- return RegionRawOffsetV2(subReg, offset);
- return RegionRawOffsetV2();
- }
- case MemRegion::ElementRegionKind: {
- const ElementRegion *elemReg = cast<ElementRegion>(region);
- SVal index = elemReg->getIndex();
- if (!isa<NonLoc>(index))
- return RegionRawOffsetV2();
- QualType elemType = elemReg->getElementType();
- // If the element is an incomplete type, go no further.
- ASTContext &astContext = svalBuilder.getContext();
- if (!IsCompleteType(astContext, elemType))
- return RegionRawOffsetV2();
-
- // Update the offset.
- offset = addValue(state,
- getValue(offset, svalBuilder),
- scaleValue(state,
- cast<NonLoc>(index),
- astContext.getTypeSizeInChars(elemType),
- svalBuilder),
- svalBuilder);
-
- if (offset.isUnknownOrUndef())
- return RegionRawOffsetV2();
-
- region = elemReg->getSuperRegion();
- continue;
- }
- }
- }
- return RegionRawOffsetV2();
-}
-
-
-
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/AttrNonNullChecker.cpp b/clang/lib/StaticAnalyzer/EntoSA/Checkers/AttrNonNullChecker.cpp
deleted file mode 100644
index 646b30bc315..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/AttrNonNullChecker.cpp
+++ /dev/null
@@ -1,136 +0,0 @@
-//===--- AttrNonNullChecker.h - Undefined arguments checker ----*- C++ -*--===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This defines AttrNonNullChecker, a builtin check in ExprEngine that
-// performs checks for arguments declared to have nonnull attribute.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ExprEngineInternalChecks.h"
-#include "clang/StaticAnalyzer/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
-
-using namespace clang;
-using namespace ento;
-
-namespace {
-class AttrNonNullChecker
- : public CheckerVisitor<AttrNonNullChecker> {
- BugType *BT;
-public:
- AttrNonNullChecker() : BT(0) {}
- static void *getTag() {
- static int x = 0;
- return &x;
- }
- void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
-};
-} // end anonymous namespace
-
-void ento::RegisterAttrNonNullChecker(ExprEngine &Eng) {
- Eng.registerCheck(new AttrNonNullChecker());
-}
-
-void AttrNonNullChecker::PreVisitCallExpr(CheckerContext &C,
- const CallExpr *CE) {
- const GRState *state = C.getState();
-
- // Check if the callee has a 'nonnull' attribute.
- SVal X = state->getSVal(CE->getCallee());
-
- const FunctionDecl* FD = X.getAsFunctionDecl();
- if (!FD)
- return;
-
- const NonNullAttr* Att = FD->getAttr<NonNullAttr>();
- if (!Att)
- return;
-
- // Iterate through the arguments of CE and check them for null.
- unsigned idx = 0;
-
- for (CallExpr::const_arg_iterator I=CE->arg_begin(), E=CE->arg_end(); I!=E;
- ++I, ++idx) {
-
- if (!Att->isNonNull(idx))
- continue;
-
- SVal V = state->getSVal(*I);
- DefinedSVal *DV = dyn_cast<DefinedSVal>(&V);
-
- // If the value is unknown or undefined, we can't perform this check.
- if (!DV)
- continue;
-
- if (!isa<Loc>(*DV)) {
- // If the argument is a union type, we want to handle a potential
- // transparent_unoin GCC extension.
- QualType T = (*I)->getType();
- const RecordType *UT = T->getAsUnionType();
- if (!UT || !UT->getDecl()->hasAttr<TransparentUnionAttr>())
- continue;
- if (nonloc::CompoundVal *CSV = dyn_cast<nonloc::CompoundVal>(DV)) {
- nonloc::CompoundVal::iterator CSV_I = CSV->begin();
- assert(CSV_I != CSV->end());
- V = *CSV_I;
- DV = dyn_cast<DefinedSVal>(&V);
- assert(++CSV_I == CSV->end());
- if (!DV)
- continue;
- }
- else {
- // FIXME: Handle LazyCompoundVals?
- continue;
- }
- }
-
- ConstraintManager &CM = C.getConstraintManager();
- const GRState *stateNotNull, *stateNull;
- llvm::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV);
-
- if (stateNull && !stateNotNull) {
- // Generate an error node. Check for a null node in case
- // we cache out.
- if (ExplodedNode *errorNode = C.generateSink(stateNull)) {
-
- // Lazily allocate the BugType object if it hasn't already been
- // created. Ownership is transferred to the BugReporter object once
- // the BugReport is passed to 'EmitWarning'.
- if (!BT)
- BT = new BugType("Argument with 'nonnull' attribute passed null",
- "API");
-
- EnhancedBugReport *R =
- new EnhancedBugReport(*BT,
- "Null pointer passed as an argument to a "
- "'nonnull' parameter", errorNode);
-
- // Highlight the range of the argument that was null.
- const Expr *arg = *I;
- R->addRange(arg->getSourceRange());
- R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, arg);
-
- // Emit the bug report.
- C.EmitReport(R);
- }
-
- // Always return. Either we cached out or we just emitted an error.
- return;
- }
-
- // If a pointer value passed the check we should assume that it is
- // indeed not null from this point forward.
- assert(stateNotNull);
- state = stateNotNull;
- }
-
- // If we reach here all of the arguments passed the nonnull check.
- // If 'state' has been updated generated a new node.
- C.addTransition(state);
-}
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/BasicObjCFoundationChecks.cpp b/clang/lib/StaticAnalyzer/EntoSA/Checkers/BasicObjCFoundationChecks.cpp
deleted file mode 100644
index b4e2959150f..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/BasicObjCFoundationChecks.cpp
+++ /dev/null
@@ -1,521 +0,0 @@
-//== BasicObjCFoundationChecks.cpp - Simple Apple-Foundation checks -*- C++ -*--
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines BasicObjCFoundationChecks, a class that encapsulates
-// a set of simple checks to run on Objective-C code using Apple's Foundation
-// classes.
-//
-//===----------------------------------------------------------------------===//
-
-#include "BasicObjCFoundationChecks.h"
-
-#include "clang/StaticAnalyzer/PathSensitive/ExplodedGraph.h"
-#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
-#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
-#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
-#include "clang/StaticAnalyzer/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/PathSensitive/MemRegion.h"
-#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
-#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
-#include "clang/AST/DeclObjC.h"
-#include "clang/AST/Expr.h"
-#include "clang/AST/ExprObjC.h"
-#include "clang/AST/ASTContext.h"
-
-using namespace clang;
-using namespace ento;
-
-namespace {
-class APIMisuse : public BugType {
-public:
- APIMisuse(const char* name) : BugType(name, "API Misuse (Apple)") {}
-};
-} // end anonymous namespace
-
-//===----------------------------------------------------------------------===//
-// Utility functions.
-//===----------------------------------------------------------------------===//
-
-static const ObjCInterfaceType* GetReceiverType(const ObjCMessageExpr* ME) {
- QualType T;
- switch (ME->getReceiverKind()) {
- case ObjCMessageExpr::Instance:
- T = ME->getInstanceReceiver()->getType();
- break;
-
- case ObjCMessageExpr::SuperInstance:
- T = ME->getSuperType();
- break;
-
- case ObjCMessageExpr::Class:
- case ObjCMessageExpr::SuperClass:
- return 0;
- }
-
- if (const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>())
- return PT->getInterfaceType();
-
- return NULL;
-}
-
-static const char* GetReceiverNameType(const ObjCMessageExpr* ME) {
- if (const ObjCInterfaceType *ReceiverType = GetReceiverType(ME))
- return ReceiverType->getDecl()->getIdentifier()->getNameStart();
- return NULL;
-}
-
-static bool isNSString(llvm::StringRef ClassName) {
- return ClassName == "NSString" || ClassName == "NSMutableString";
-}
-
-static inline bool isNil(SVal X) {
- return isa<loc::ConcreteInt>(X);
-}
-
-//===----------------------------------------------------------------------===//
-// NilArgChecker - Check for prohibited nil arguments to ObjC method calls.
-//===----------------------------------------------------------------------===//
-
-namespace {
- class NilArgChecker : public CheckerVisitor<NilArgChecker> {
- APIMisuse *BT;
- void WarnNilArg(CheckerContext &C, const ObjCMessageExpr* ME, unsigned Arg);
- public:
- NilArgChecker() : BT(0) {}
- static void *getTag() { static int x = 0; return &x; }
- void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME);
- };
-}
-
-void NilArgChecker::WarnNilArg(CheckerContext &C,
- const clang::ObjCMessageExpr *ME,
- unsigned int Arg)
-{
- if (!BT)
- BT = new APIMisuse("nil argument");
-
- if (ExplodedNode *N = C.generateSink()) {
- llvm::SmallString<128> sbuf;
- llvm::raw_svector_ostream os(sbuf);
- os << "Argument to '" << GetReceiverNameType(ME) << "' method '"
- << ME->getSelector().getAsString() << "' cannot be nil";
-
- RangedBugReport *R = new RangedBugReport(*BT, os.str(), N);
- R->addRange(ME->getArg(Arg)->getSourceRange());
- C.EmitReport(R);
- }
-}
-
-void NilArgChecker::PreVisitObjCMessageExpr(CheckerContext &C,
- const ObjCMessageExpr *ME)
-{
- const ObjCInterfaceType *ReceiverType = GetReceiverType(ME);
- if (!ReceiverType)
- return;
-
- if (isNSString(ReceiverType->getDecl()->getIdentifier()->getName())) {
- Selector S = ME->getSelector();
-
- if (S.isUnarySelector())
- return;
-
- // FIXME: This is going to be really slow doing these checks with
- // lexical comparisons.
-
- std::string NameStr = S.getAsString();
- llvm::StringRef Name(NameStr);
- assert(!Name.empty());
-
- // FIXME: Checking for initWithFormat: will not work in most cases
- // yet because [NSString alloc] returns id, not NSString*. We will
- // need support for tracking expected-type information in the analyzer
- // to find these errors.
- if (Name == "caseInsensitiveCompare:" ||
- Name == "compare:" ||
- Name == "compare:options:" ||
- Name == "compare:options:range:" ||
- Name == "compare:options:range:locale:" ||
- Name == "componentsSeparatedByCharactersInSet:" ||
- Name == "initWithFormat:") {
- if (isNil(C.getState()->getSVal(ME->getArg(0))))
- WarnNilArg(C, ME, 0);
- }
- }
-}
-
-//===----------------------------------------------------------------------===//
-// Error reporting.
-//===----------------------------------------------------------------------===//
-
-namespace {
-class CFNumberCreateChecker : public CheckerVisitor<CFNumberCreateChecker> {
- APIMisuse* BT;
- IdentifierInfo* II;
-public:
- CFNumberCreateChecker() : BT(0), II(0) {}
- ~CFNumberCreateChecker() {}
- static void *getTag() { static int x = 0; return &x; }
- void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
-private:
- void EmitError(const TypedRegion* R, const Expr* Ex,
- uint64_t SourceSize, uint64_t TargetSize, uint64_t NumberKind);
-};
-} // end anonymous namespace
-
-enum CFNumberType {
- kCFNumberSInt8Type = 1,
- kCFNumberSInt16Type = 2,
- kCFNumberSInt32Type = 3,
- kCFNumberSInt64Type = 4,
- kCFNumberFloat32Type = 5,
- kCFNumberFloat64Type = 6,
- kCFNumberCharType = 7,
- kCFNumberShortType = 8,
- kCFNumberIntType = 9,
- kCFNumberLongType = 10,
- kCFNumberLongLongType = 11,
- kCFNumberFloatType = 12,
- kCFNumberDoubleType = 13,
- kCFNumberCFIndexType = 14,
- kCFNumberNSIntegerType = 15,
- kCFNumberCGFloatType = 16
-};
-
-namespace {
- template<typename T>
- class Optional {
- bool IsKnown;
- T Val;
- public:
- Optional() : IsKnown(false), Val(0) {}
- Optional(const T& val) : IsKnown(true), Val(val) {}
-
- bool isKnown() const { return IsKnown; }
-
- const T& getValue() const {
- assert (isKnown());
- return Val;
- }
-
- operator const T&() const {
- return getValue();
- }
- };
-}
-
-static Optional<uint64_t> GetCFNumberSize(ASTContext& Ctx, uint64_t i) {
- static const unsigned char FixedSize[] = { 8, 16, 32, 64, 32, 64 };
-
- if (i < kCFNumberCharType)
- return FixedSize[i-1];
-
- QualType T;
-
- switch (i) {
- case kCFNumberCharType: T = Ctx.CharTy; break;
- case kCFNumberShortType: T = Ctx.ShortTy; break;
- case kCFNumberIntType: T = Ctx.IntTy; break;
- case kCFNumberLongType: T = Ctx.LongTy; break;
- case kCFNumberLongLongType: T = Ctx.LongLongTy; break;
- case kCFNumberFloatType: T = Ctx.FloatTy; break;
- case kCFNumberDoubleType: T = Ctx.DoubleTy; break;
- case kCFNumberCFIndexType:
- case kCFNumberNSIntegerType:
- case kCFNumberCGFloatType:
- // FIXME: We need a way to map from names to Type*.
- default:
- return Optional<uint64_t>();
- }
-
- return Ctx.getTypeSize(T);
-}
-
-#if 0
-static const char* GetCFNumberTypeStr(uint64_t i) {
- static const char* Names[] = {
- "kCFNumberSInt8Type",
- "kCFNumberSInt16Type",
- "kCFNumberSInt32Type",
- "kCFNumberSInt64Type",
- "kCFNumberFloat32Type",
- "kCFNumberFloat64Type",
- "kCFNumberCharType",
- "kCFNumberShortType",
- "kCFNumberIntType",
- "kCFNumberLongType",
- "kCFNumberLongLongType",
- "kCFNumberFloatType",
- "kCFNumberDoubleType",
- "kCFNumberCFIndexType",
- "kCFNumberNSIntegerType",
- "kCFNumberCGFloatType"
- };
-
- return i <= kCFNumberCGFloatType ? Names[i-1] : "Invalid CFNumberType";
-}
-#endif
-
-void CFNumberCreateChecker::PreVisitCallExpr(CheckerContext &C,
- const CallExpr *CE)
-{
- const Expr* Callee = CE->getCallee();
- const GRState *state = C.getState();
- SVal CallV = state->getSVal(Callee);
- const FunctionDecl* FD = CallV.getAsFunctionDecl();
-
- if (!FD)
- return;
-
- ASTContext &Ctx = C.getASTContext();
- if (!II)
- II = &Ctx.Idents.get("CFNumberCreate");
-
- if (FD->getIdentifier() != II || CE->getNumArgs() != 3)
- return;
-
- // Get the value of the "theType" argument.
- SVal TheTypeVal = state->getSVal(CE->getArg(1));
-
- // FIXME: We really should allow ranges of valid theType values, and
- // bifurcate the state appropriately.
- nonloc::ConcreteInt* V = dyn_cast<nonloc::ConcreteInt>(&TheTypeVal);
- if (!V)
- return;
-
- uint64_t NumberKind = V->getValue().getLimitedValue();
- Optional<uint64_t> TargetSize = GetCFNumberSize(Ctx, NumberKind);
-
- // FIXME: In some cases we can emit an error.
- if (!TargetSize.isKnown())
- return;
-
- // Look at the value of the integer being passed by reference. Essentially
- // we want to catch cases where the value passed in is not equal to the
- // size of the type being created.
- SVal TheValueExpr = state->getSVal(CE->getArg(2));
-
- // FIXME: Eventually we should handle arbitrary locations. We can do this
- // by having an enhanced memory model that does low-level typing.
- loc::MemRegionVal* LV = dyn_cast<loc::MemRegionVal>(&TheValueExpr);
- if (!LV)
- return;
-
- const TypedRegion* R = dyn_cast<TypedRegion>(LV->StripCasts());
- if (!R)
- return;
-
- QualType T = Ctx.getCanonicalType(R->getValueType());
-
- // FIXME: If the pointee isn't an integer type, should we flag a warning?
- // People can do weird stuff with pointers.
-
- if (!T->isIntegerType())
- return;
-
- uint64_t SourceSize = Ctx.getTypeSize(T);
-
- // CHECK: is SourceSize == TargetSize
- if (SourceSize == TargetSize)
- return;
-
- // Generate an error. Only generate a sink if 'SourceSize < TargetSize';
- // otherwise generate a regular node.
- //
- // FIXME: We can actually create an abstract "CFNumber" object that has
- // the bits initialized to the provided values.
- //
- if (ExplodedNode *N = SourceSize < TargetSize ? C.generateSink()
- : C.generateNode()) {
- llvm::SmallString<128> sbuf;
- llvm::raw_svector_ostream os(sbuf);
-
- os << (SourceSize == 8 ? "An " : "A ")
- << SourceSize << " bit integer is used to initialize a CFNumber "
- "object that represents "
- << (TargetSize == 8 ? "an " : "a ")
- << TargetSize << " bit integer. ";
-
- if (SourceSize < TargetSize)
- os << (TargetSize - SourceSize)
- << " bits of the CFNumber value will be garbage." ;
- else
- os << (SourceSize - TargetSize)
- << " bits of the input integer will be lost.";
-
- if (!BT)
- BT = new APIMisuse("Bad use of CFNumberCreate");
-
- RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
- report->addRange(CE->getArg(2)->getSourceRange());
- C.EmitReport(report);
- }
-}
-
-//===----------------------------------------------------------------------===//
-// CFRetain/CFRelease checking for null arguments.
-//===----------------------------------------------------------------------===//
-
-namespace {
-class CFRetainReleaseChecker : public CheckerVisitor<CFRetainReleaseChecker> {
- APIMisuse *BT;
- IdentifierInfo *Retain, *Release;
-public:
- CFRetainReleaseChecker(): BT(0), Retain(0), Release(0) {}
- static void *getTag() { static int x = 0; return &x; }
- void PreVisitCallExpr(CheckerContext& C, const CallExpr* CE);
-};
-} // end anonymous namespace
-
-
-void CFRetainReleaseChecker::PreVisitCallExpr(CheckerContext& C,
- const CallExpr* CE) {
- // If the CallExpr doesn't have exactly 1 argument just give up checking.
- if (CE->getNumArgs() != 1)
- return;
-
- // Get the function declaration of the callee.
- const GRState* state = C.getState();
- SVal X = state->getSVal(CE->getCallee());
- const FunctionDecl* FD = X.getAsFunctionDecl();
-
- if (!FD)
- return;
-
- if (!BT) {
- ASTContext &Ctx = C.getASTContext();
- Retain = &Ctx.Idents.get("CFRetain");
- Release = &Ctx.Idents.get("CFRelease");
- BT = new APIMisuse("null passed to CFRetain/CFRelease");
- }
-
- // Check if we called CFRetain/CFRelease.
- const IdentifierInfo *FuncII = FD->getIdentifier();
- if (!(FuncII == Retain || FuncII == Release))
- return;
-
- // FIXME: The rest of this just checks that the argument is non-null.
- // It should probably be refactored and combined with AttrNonNullChecker.
-
- // Get the argument's value.
- const Expr *Arg = CE->getArg(0);
- SVal ArgVal = state->getSVal(Arg);
- DefinedSVal *DefArgVal = dyn_cast<DefinedSVal>(&ArgVal);
- if (!DefArgVal)
- return;
-
- // Get a NULL value.
- SValBuilder &svalBuilder = C.getSValBuilder();
- DefinedSVal zero = cast<DefinedSVal>(svalBuilder.makeZeroVal(Arg->getType()));
-
- // Make an expression asserting that they're equal.
- DefinedOrUnknownSVal ArgIsNull = svalBuilder.evalEQ(state, zero, *DefArgVal);
-
- // Are they equal?
- const GRState *stateTrue, *stateFalse;
- llvm::tie(stateTrue, stateFalse) = state->assume(ArgIsNull);
-
- if (stateTrue && !stateFalse) {
- ExplodedNode *N = C.generateSink(stateTrue);
- if (!N)
- return;
-
- const char *description = (FuncII == Retain)
- ? "Null pointer argument in call to CFRetain"
- : "Null pointer argument in call to CFRelease";
-
- EnhancedBugReport *report = new EnhancedBugReport(*BT, description, N);
- report->addRange(Arg->getSourceRange());
- report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Arg);
- C.EmitReport(report);
- return;
- }
-
- // From here on, we know the argument is non-null.
- C.addTransition(stateFalse);
-}
-
-//===----------------------------------------------------------------------===//
-// Check for sending 'retain', 'release', or 'autorelease' directly to a Class.
-//===----------------------------------------------------------------------===//
-
-namespace {
-class ClassReleaseChecker : public CheckerVisitor<ClassReleaseChecker> {
- Selector releaseS;
- Selector retainS;
- Selector autoreleaseS;
- Selector drainS;
- BugType *BT;
-public:
- ClassReleaseChecker()
- : BT(0) {}
-
- static void *getTag() { static int x = 0; return &x; }
-
- void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME);
-};
-}
-
-void ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C,
- const ObjCMessageExpr *ME) {
-
- if (!BT) {
- BT = new APIMisuse("message incorrectly sent to class instead of class "
- "instance");
-
- ASTContext &Ctx = C.getASTContext();
- releaseS = GetNullarySelector("release", Ctx);
- retainS = GetNullarySelector("retain", Ctx);
- autoreleaseS = GetNullarySelector("autorelease", Ctx);
- drainS = GetNullarySelector("drain", Ctx);
- }
-
- ObjCInterfaceDecl *Class = 0;
-
- switch (ME->getReceiverKind()) {
- case ObjCMessageExpr::Class:
- Class = ME->getClassReceiver()->getAs<ObjCObjectType>()->getInterface();
- break;
- case ObjCMessageExpr::SuperClass:
- Class = ME->getSuperType()->getAs<ObjCObjectType>()->getInterface();
- break;
- case ObjCMessageExpr::Instance:
- case ObjCMessageExpr::SuperInstance:
- return;
- }
-
- Selector S = ME->getSelector();
- if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
- return;
-
- if (ExplodedNode *N = C.generateNode()) {
- llvm::SmallString<200> buf;
- llvm::raw_svector_ostream os(buf);
-
- os << "The '" << S.getAsString() << "' message should be sent to instances "
- "of class '" << Class->getName()
- << "' and not the class directly";
-
- RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
- report->addRange(ME->getSourceRange());
- C.EmitReport(report);
- }
-}
-
-//===----------------------------------------------------------------------===//
-// Check registration.
-//===----------------------------------------------------------------------===//
-
-void ento::RegisterAppleChecks(ExprEngine& Eng, const Decl &D) {
- Eng.registerCheck(new NilArgChecker());
- Eng.registerCheck(new CFNumberCreateChecker());
- RegisterNSErrorChecks(Eng.getBugReporter(), Eng, D);
- RegisterNSAutoreleasePoolChecks(Eng);
- Eng.registerCheck(new CFRetainReleaseChecker());
- Eng.registerCheck(new ClassReleaseChecker());
-}
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/BasicObjCFoundationChecks.h b/clang/lib/StaticAnalyzer/EntoSA/Checkers/BasicObjCFoundationChecks.h
deleted file mode 100644
index f4966e8ae83..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/BasicObjCFoundationChecks.h
+++ /dev/null
@@ -1,36 +0,0 @@
-//== BasicObjCFoundationChecks.h - Simple Apple-Foundation checks -*- C++ -*--//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines BasicObjCFoundationChecks, a class that encapsulates
-// a set of simple checks to run on Objective-C code using Apple's Foundation
-// classes.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_GR_BASICOBJCFOUNDATIONCHECKS
-#define LLVM_CLANG_GR_BASICOBJCFOUNDATIONCHECKS
-
-namespace clang {
-
-class ASTContext;
-class Decl;
-
-namespace ento {
-
-class BugReporter;
-class ExprEngine;
-
-void RegisterNSErrorChecks(BugReporter& BR, ExprEngine &Eng, const Decl &D);
-void RegisterNSAutoreleasePoolChecks(ExprEngine &Eng);
-
-} // end GR namespace
-
-} // end clang namespace
-
-#endif
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/BuiltinFunctionChecker.cpp b/clang/lib/StaticAnalyzer/EntoSA/Checkers/BuiltinFunctionChecker.cpp
deleted file mode 100644
index 2e6f1b90e11..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/BuiltinFunctionChecker.cpp
+++ /dev/null
@@ -1,83 +0,0 @@
-//=== BuiltinFunctionChecker.cpp --------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This checker evaluates clang builtin functions.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ExprEngineInternalChecks.h"
-#include "clang/StaticAnalyzer/PathSensitive/Checker.h"
-#include "clang/Basic/Builtins.h"
-
-using namespace clang;
-using namespace ento;
-
-namespace {
-
-class BuiltinFunctionChecker : public Checker {
-public:
- static void *getTag() { static int tag = 0; return &tag; }
- virtual bool evalCallExpr(CheckerContext &C, const CallExpr *CE);
-};
-
-}
-
-void ento::RegisterBuiltinFunctionChecker(ExprEngine &Eng) {
- Eng.registerCheck(new BuiltinFunctionChecker());
-}
-
-bool BuiltinFunctionChecker::evalCallExpr(CheckerContext &C,const CallExpr *CE){
- const GRState *state = C.getState();
- const Expr *Callee = CE->getCallee();
- SVal L = state->getSVal(Callee);
- const FunctionDecl *FD = L.getAsFunctionDecl();
-
- if (!FD)
- return false;
-
- unsigned id = FD->getBuiltinID();
-
- if (!id)
- return false;
-
- switch (id) {
- case Builtin::BI__builtin_expect: {
- // For __builtin_expect, just return the value of the subexpression.
- assert (CE->arg_begin() != CE->arg_end());
- SVal X = state->getSVal(*(CE->arg_begin()));
- C.generateNode(state->BindExpr(CE, X));
- return true;
- }
-
- case Builtin::BI__builtin_alloca: {
- // FIXME: Refactor into StoreManager itself?
- MemRegionManager& RM = C.getStoreManager().getRegionManager();
- const AllocaRegion* R =
- RM.getAllocaRegion(CE, C.getNodeBuilder().getCurrentBlockCount(),
- C.getPredecessor()->getLocationContext());
-
- // Set the extent of the region in bytes. This enables us to use the
- // SVal of the argument directly. If we save the extent in bits, we
- // cannot represent values like symbol*8.
- DefinedOrUnknownSVal Size =
- cast<DefinedOrUnknownSVal>(state->getSVal(*(CE->arg_begin())));
-
- SValBuilder& svalBuilder = C.getSValBuilder();
- DefinedOrUnknownSVal Extent = R->getExtent(svalBuilder);
- DefinedOrUnknownSVal extentMatchesSizeArg =
- svalBuilder.evalEQ(state, Extent, Size);
- state = state->assume(extentMatchesSizeArg, true);
-
- C.generateNode(state->BindExpr(CE, loc::MemRegionVal(R)));
- return true;
- }
- }
-
- return false;
-}
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/CMakeLists.txt b/clang/lib/StaticAnalyzer/EntoSA/Checkers/CMakeLists.txt
deleted file mode 100644
index e4b9541c237..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/CMakeLists.txt
+++ /dev/null
@@ -1,53 +0,0 @@
-add_clang_library(clangStaticAnalyzerCheckers
- AdjustedReturnValueChecker.cpp
- AnalysisConsumer.cpp
- ArrayBoundChecker.cpp
- ArrayBoundCheckerV2.cpp
- AttrNonNullChecker.cpp
- BasicObjCFoundationChecks.cpp
- BuiltinFunctionChecker.cpp
- CStringChecker.cpp
- CallAndMessageChecker.cpp
- CastSizeChecker.cpp
- CastToStructChecker.cpp
- CheckDeadStores.cpp
- CheckObjCDealloc.cpp
- CheckObjCInstMethSignature.cpp
- CheckSecuritySyntaxOnly.cpp
- CheckSizeofPointer.cpp
- ChrootChecker.cpp
- DereferenceChecker.cpp
- DivZeroChecker.cpp
- ExprEngine.cpp
- ExprEngineExperimentalChecks.cpp
- FixedAddressChecker.cpp
- FrontendActions.cpp
- IdempotentOperationChecker.cpp
- LLVMConventionsChecker.cpp
- MacOSXAPIChecker.cpp
- MallocChecker.cpp
- NSAutoreleasePoolChecker.cpp
- NSErrorChecker.cpp
- NoReturnFunctionChecker.cpp
- OSAtomicChecker.cpp
- ObjCAtSyncChecker.cpp
- ObjCUnusedIVarsChecker.cpp
- PointerArithChecker.cpp
- PointerSubChecker.cpp
- PthreadLockChecker.cpp
- ReturnPointerRangeChecker.cpp
- ReturnUndefChecker.cpp
- StackAddrLeakChecker.cpp
- StreamChecker.cpp
- UndefBranchChecker.cpp
- UndefCapturedBlockVarChecker.cpp
- UndefResultChecker.cpp
- UndefinedArraySubscriptChecker.cpp
- UndefinedAssignmentChecker.cpp
- UnixAPIChecker.cpp
- UnreachableCodeChecker.cpp
- VLASizeChecker.cpp
- )
-
-add_dependencies(clangStaticAnalyzerCore ClangAttrClasses ClangAttrList ClangDeclNodes
- ClangStmtNodes)
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/CStringChecker.cpp b/clang/lib/StaticAnalyzer/EntoSA/Checkers/CStringChecker.cpp
deleted file mode 100644
index b7513c39c13..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/CStringChecker.cpp
+++ /dev/null
@@ -1,1048 +0,0 @@
-//= CStringChecker.h - Checks calls to C string functions ----------*- C++ -*-//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This defines CStringChecker, which is an assortment of checks on calls
-// to functions in <string.h>.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ExprEngineExperimentalChecks.h"
-#include "clang/StaticAnalyzer/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
-#include "clang/StaticAnalyzer/PathSensitive/GRStateTrait.h"
-#include "llvm/ADT/StringSwitch.h"
-
-using namespace clang;
-using namespace ento;
-
-namespace {
-class CStringChecker : public CheckerVisitor<CStringChecker> {
- BugType *BT_Null, *BT_Bounds, *BT_BoundsWrite, *BT_Overlap, *BT_NotCString;
-public:
- CStringChecker()
- : BT_Null(0), BT_Bounds(0), BT_BoundsWrite(0), BT_Overlap(0), BT_NotCString(0)
- {}
- static void *getTag() { static int tag; return &tag; }
-
- bool evalCallExpr(CheckerContext &C, const CallExpr *CE);
- void PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS);
- void MarkLiveSymbols(const GRState *state, SymbolReaper &SR);
- void evalDeadSymbols(CheckerContext &C, SymbolReaper &SR);
- bool WantsRegionChangeUpdate(const GRState *state);
-
- const GRState *EvalRegionChanges(const GRState *state,
- const MemRegion * const *Begin,
- const MemRegion * const *End,
- bool*);
-
- typedef void (CStringChecker::*FnCheck)(CheckerContext &, const CallExpr *);
-
- void evalMemcpy(CheckerContext &C, const CallExpr *CE);
- void evalMemmove(CheckerContext &C, const CallExpr *CE);
- void evalBcopy(CheckerContext &C, const CallExpr *CE);
- void evalCopyCommon(CheckerContext &C, const GRState *state,
- const Expr *Size, const Expr *Source, const Expr *Dest,
- bool Restricted = false);
-
- void evalMemcmp(CheckerContext &C, const CallExpr *CE);
-
- void evalstrLength(CheckerContext &C, const CallExpr *CE);
-
- void evalStrcpy(CheckerContext &C, const CallExpr *CE);
- void evalStpcpy(CheckerContext &C, const CallExpr *CE);
- void evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, bool returnEnd);
-
- // Utility methods
- std::pair<const GRState*, const GRState*>
- assumeZero(CheckerContext &C, const GRState *state, SVal V, QualType Ty);
-
- const GRState *setCStringLength(const GRState *state, const MemRegion *MR,
- SVal strLength);
- SVal getCStringLengthForRegion(CheckerContext &C, const GRState *&state,
- const Expr *Ex, const MemRegion *MR);
- SVal getCStringLength(CheckerContext &C, const GRState *&state,
- const Expr *Ex, SVal Buf);
-
- const GRState *InvalidateBuffer(CheckerContext &C, const GRState *state,
- const Expr *Ex, SVal V);
-
- bool SummarizeRegion(llvm::raw_ostream& os, ASTContext& Ctx,
- const MemRegion *MR);
-
- // Re-usable checks
- const GRState *checkNonNull(CheckerContext &C, const GRState *state,
- const Expr *S, SVal l);
- const GRState *CheckLocation(CheckerContext &C, const GRState *state,
- const Expr *S, SVal l,
- bool IsDestination = false);
- const GRState *CheckBufferAccess(CheckerContext &C, const GRState *state,
- const Expr *Size,
- const Expr *FirstBuf,
- const Expr *SecondBuf = NULL,
- bool FirstIsDestination = false);
- const GRState *CheckOverlap(CheckerContext &C, const GRState *state,
- const Expr *Size, const Expr *First,
- const Expr *Second);
- void emitOverlapBug(CheckerContext &C, const GRState *state,
- const Stmt *First, const Stmt *Second);
-};
-
-class CStringLength {
-public:
- typedef llvm::ImmutableMap<const MemRegion *, SVal> EntryMap;
-};
-} //end anonymous namespace
-
-namespace clang {
-namespace ento {
- template <>
- struct GRStateTrait<CStringLength>
- : public GRStatePartialTrait<CStringLength::EntryMap> {
- static void *GDMIndex() { return CStringChecker::getTag(); }
- };
-}
-}
-
-void ento::RegisterCStringChecker(ExprEngine &Eng) {
- Eng.registerCheck(new CStringChecker());
-}
-
-//===----------------------------------------------------------------------===//
-// Individual checks and utility methods.
-//===----------------------------------------------------------------------===//
-
-std::pair<const GRState*, const GRState*>
-CStringChecker::assumeZero(CheckerContext &C, const GRState *state, SVal V,
- QualType Ty) {
- DefinedSVal *val = dyn_cast<DefinedSVal>(&V);
- if (!val)
- return std::pair<const GRState*, const GRState *>(state, state);
-
- SValBuilder &svalBuilder = C.getSValBuilder();
- DefinedOrUnknownSVal zero = svalBuilder.makeZeroVal(Ty);
- return state->assume(svalBuilder.evalEQ(state, *val, zero));
-}
-
-const GRState *CStringChecker::checkNonNull(CheckerContext &C,
- const GRState *state,
- const Expr *S, SVal l) {
- // If a previous check has failed, propagate the failure.
- if (!state)
- return NULL;
-
- const GRState *stateNull, *stateNonNull;
- llvm::tie(stateNull, stateNonNull) = assumeZero(C, state, l, S->getType());
-
- if (stateNull && !stateNonNull) {
- ExplodedNode *N = C.generateSink(stateNull);
- if (!N)
- return NULL;
-
- if (!BT_Null)
- BT_Null = new BuiltinBug("API",
- "Null pointer argument in call to byte string function");
-
- // Generate a report for this bug.
- BuiltinBug *BT = static_cast<BuiltinBug*>(BT_Null);
- EnhancedBugReport *report = new EnhancedBugReport(*BT,
- BT->getDescription(), N);
-
- report->addRange(S->getSourceRange());
- report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, S);
- C.EmitReport(report);
- return NULL;
- }
-
- // From here on, assume that the value is non-null.
- assert(stateNonNull);
- return stateNonNull;
-}
-
-// FIXME: This was originally copied from ArrayBoundChecker.cpp. Refactor?
-const GRState *CStringChecker::CheckLocation(CheckerContext &C,
- const GRState *state,
- const Expr *S, SVal l,
- bool IsDestination) {
- // If a previous check has failed, propagate the failure.
- if (!state)
- return NULL;
-
- // Check for out of bound array element access.
- const MemRegion *R = l.getAsRegion();
- if (!R)
- return state;
-
- const ElementRegion *ER = dyn_cast<ElementRegion>(R);
- if (!ER)
- return state;
-
- assert(ER->getValueType() == C.getASTContext().CharTy &&
- "CheckLocation should only be called with char* ElementRegions");
-
- // Get the size of the array.
- const SubRegion *superReg = cast<SubRegion>(ER->getSuperRegion());
- SValBuilder &svalBuilder = C.getSValBuilder();
- SVal Extent = svalBuilder.convertToArrayIndex(superReg->getExtent(svalBuilder));
- DefinedOrUnknownSVal Size = cast<DefinedOrUnknownSVal>(Extent);
-
- // Get the index of the accessed element.
- DefinedOrUnknownSVal Idx = cast<DefinedOrUnknownSVal>(ER->getIndex());
-
- const GRState *StInBound = state->assumeInBound(Idx, Size, true);
- const GRState *StOutBound = state->assumeInBound(Idx, Size, false);
- if (StOutBound && !StInBound) {
- ExplodedNode *N = C.generateSink(StOutBound);
- if (!N)
- return NULL;
-
- BuiltinBug *BT;
- if (IsDestination) {
- if (!BT_BoundsWrite) {
- BT_BoundsWrite = new BuiltinBug("Out-of-bound array access",
- "Byte string function overflows destination buffer");
- }
- BT = static_cast<BuiltinBug*>(BT_BoundsWrite);
- } else {
- if (!BT_Bounds) {
- BT_Bounds = new BuiltinBug("Out-of-bound array access",
- "Byte string function accesses out-of-bound array element");
- }
- BT = static_cast<BuiltinBug*>(BT_Bounds);
- }
-
- // FIXME: It would be nice to eventually make this diagnostic more clear,
- // e.g., by referencing the original declaration or by saying *why* this
- // reference is outside the range.
-
- // Generate a report for this bug.
- RangedBugReport *report = new RangedBugReport(*BT, BT->getDescription(), N);
-
- report->addRange(S->getSourceRange());
- C.EmitReport(report);
- return NULL;
- }
-
- // Array bound check succeeded. From this point forward the array bound
- // should always succeed.
- return StInBound;
-}
-
-const GRState *CStringChecker::CheckBufferAccess(CheckerContext &C,
- const GRState *state,
- const Expr *Size,
- const Expr *FirstBuf,
- const Expr *SecondBuf,
- bool FirstIsDestination) {
- // If a previous check has failed, propagate the failure.
- if (!state)
- return NULL;
-
- SValBuilder &svalBuilder = C.getSValBuilder();
- ASTContext &Ctx = C.getASTContext();
-
- QualType sizeTy = Size->getType();
- QualType PtrTy = Ctx.getPointerType(Ctx.CharTy);
-
- // Check that the first buffer is non-null.
- SVal BufVal = state->getSVal(FirstBuf);
- state = checkNonNull(C, state, FirstBuf, BufVal);
- if (!state)
- return NULL;
-
- // Get the access length and make sure it is known.
- SVal LengthVal = state->getSVal(Size);
- NonLoc *Length = dyn_cast<NonLoc>(&LengthVal);
- if (!Length)
- return state;
-
- // Compute the offset of the last element to be accessed: size-1.
- NonLoc One = cast<NonLoc>(svalBuilder.makeIntVal(1, sizeTy));
- NonLoc LastOffset = cast<NonLoc>(svalBuilder.evalBinOpNN(state, BO_Sub,
- *Length, One, sizeTy));
-
- // Check that the first buffer is sufficently long.
- SVal BufStart = svalBuilder.evalCast(BufVal, PtrTy, FirstBuf->getType());
- if (Loc *BufLoc = dyn_cast<Loc>(&BufStart)) {
- SVal BufEnd = svalBuilder.evalBinOpLN(state, BO_Add, *BufLoc,
- LastOffset, PtrTy);
- state = CheckLocation(C, state, FirstBuf, BufEnd, FirstIsDestination);
-
- // If the buffer isn't large enough, abort.
- if (!state)
- return NULL;
- }
-
- // If there's a second buffer, check it as well.
- if (SecondBuf) {
- BufVal = state->getSVal(SecondBuf);
- state = checkNonNull(C, state, SecondBuf, BufVal);
- if (!state)
- return NULL;
-
- BufStart = svalBuilder.evalCast(BufVal, PtrTy, SecondBuf->getType());
- if (Loc *BufLoc = dyn_cast<Loc>(&BufStart)) {
- SVal BufEnd = svalBuilder.evalBinOpLN(state, BO_Add, *BufLoc,
- LastOffset, PtrTy);
- state = CheckLocation(C, state, SecondBuf, BufEnd);
- }
- }
-
- // Large enough or not, return this state!
- return state;
-}
-
-const GRState *CStringChecker::CheckOverlap(CheckerContext &C,
- const GRState *state,
- const Expr *Size,
- const Expr *First,
- const Expr *Second) {
- // Do a simple check for overlap: if the two arguments are from the same
- // buffer, see if the end of the first is greater than the start of the second
- // or vice versa.
-
- // If a previous check has failed, propagate the failure.
- if (!state)
- return NULL;
-
- const GRState *stateTrue, *stateFalse;
-
- // Get the buffer values and make sure they're known locations.
- SVal firstVal = state->getSVal(First);
- SVal secondVal = state->getSVal(Second);
-
- Loc *firstLoc = dyn_cast<Loc>(&firstVal);
- if (!firstLoc)
- return state;
-
- Loc *secondLoc = dyn_cast<Loc>(&secondVal);
- if (!secondLoc)
- return state;
-
- // Are the two values the same?
- SValBuilder &svalBuilder = C.getSValBuilder();
- llvm::tie(stateTrue, stateFalse) =
- state->assume(svalBuilder.evalEQ(state, *firstLoc, *secondLoc));
-
- if (stateTrue && !stateFalse) {
- // If the values are known to be equal, that's automatically an overlap.
- emitOverlapBug(C, stateTrue, First, Second);
- return NULL;
- }
-
- // assume the two expressions are not equal.
- assert(stateFalse);
- state = stateFalse;
-
- // Which value comes first?
- ASTContext &Ctx = svalBuilder.getContext();
- QualType cmpTy = Ctx.IntTy;
- SVal reverse = svalBuilder.evalBinOpLL(state, BO_GT,
- *firstLoc, *secondLoc, cmpTy);
- DefinedOrUnknownSVal *reverseTest = dyn_cast<DefinedOrUnknownSVal>(&reverse);
- if (!reverseTest)
- return state;
-
- llvm::tie(stateTrue, stateFalse) = state->assume(*reverseTest);
- if (stateTrue) {
- if (stateFalse) {
- // If we don't know which one comes first, we can't perform this test.
- return state;
- } else {
- // Switch the values so that firstVal is before secondVal.
- Loc *tmpLoc = firstLoc;
- firstLoc = secondLoc;
- secondLoc = tmpLoc;
-
- // Switch the Exprs as well, so that they still correspond.
- const Expr *tmpExpr = First;
- First = Second;
- Second = tmpExpr;
- }
- }
-
- // Get the length, and make sure it too is known.
- SVal LengthVal = state->getSVal(Size);
- NonLoc *Length = dyn_cast<NonLoc>(&LengthVal);
- if (!Length)
- return state;
-
- // Convert the first buffer's start address to char*.
- // Bail out if the cast fails.
- QualType CharPtrTy = Ctx.getPointerType(Ctx.CharTy);
- SVal FirstStart = svalBuilder.evalCast(*firstLoc, CharPtrTy, First->getType());
- Loc *FirstStartLoc = dyn_cast<Loc>(&FirstStart);
- if (!FirstStartLoc)
- return state;
-
- // Compute the end of the first buffer. Bail out if THAT fails.
- SVal FirstEnd = svalBuilder.evalBinOpLN(state, BO_Add,
- *FirstStartLoc, *Length, CharPtrTy);
- Loc *FirstEndLoc = dyn_cast<Loc>(&FirstEnd);
- if (!FirstEndLoc)
- return state;
-
- // Is the end of the first buffer past the start of the second buffer?
- SVal Overlap = svalBuilder.evalBinOpLL(state, BO_GT,
- *FirstEndLoc, *secondLoc, cmpTy);
- DefinedOrUnknownSVal *OverlapTest = dyn_cast<DefinedOrUnknownSVal>(&Overlap);
- if (!OverlapTest)
- return state;
-
- llvm::tie(stateTrue, stateFalse) = state->assume(*OverlapTest);
-
- if (stateTrue && !stateFalse) {
- // Overlap!
- emitOverlapBug(C, stateTrue, First, Second);
- return NULL;
- }
-
- // assume the two expressions don't overlap.
- assert(stateFalse);
- return stateFalse;
-}
-
-void CStringChecker::emitOverlapBug(CheckerContext &C, const GRState *state,
- const Stmt *First, const Stmt *Second) {
- ExplodedNode *N = C.generateSink(state);
- if (!N)
- return;
-
- if (!BT_Overlap)
- BT_Overlap = new BugType("Unix API", "Improper arguments");
-
- // Generate a report for this bug.
- RangedBugReport *report =
- new RangedBugReport(*BT_Overlap,
- "Arguments must not be overlapping buffers", N);
- report->addRange(First->getSourceRange());
- report->addRange(Second->getSourceRange());
-
- C.EmitReport(report);
-}
-
-const GRState *CStringChecker::setCStringLength(const GRState *state,
- const MemRegion *MR,
- SVal strLength) {
- assert(!strLength.isUndef() && "Attempt to set an undefined string length");
- if (strLength.isUnknown())
- return state;
-
- MR = MR->StripCasts();
-
- switch (MR->getKind()) {
- case MemRegion::StringRegionKind:
- // FIXME: This can happen if we strcpy() into a string region. This is
- // undefined [C99 6.4.5p6], but we should still warn about it.
- return state;
-
- case MemRegion::SymbolicRegionKind:
- case MemRegion::AllocaRegionKind:
- case MemRegion::VarRegionKind:
- case MemRegion::FieldRegionKind:
- case MemRegion::ObjCIvarRegionKind:
- return state->set<CStringLength>(MR, strLength);
-
- case MemRegion::ElementRegionKind:
- // FIXME: Handle element regions by upper-bounding the parent region's
- // string length.
- return state;
-
- default:
- // Other regions (mostly non-data) can't have a reliable C string length.
- // For now, just ignore the change.
- // FIXME: These are rare but not impossible. We should output some kind of
- // warning for things like strcpy((char[]){'a', 0}, "b");
- return state;
- }
-}
-
-SVal CStringChecker::getCStringLengthForRegion(CheckerContext &C,
- const GRState *&state,
- const Expr *Ex,
- const MemRegion *MR) {
- // If there's a recorded length, go ahead and return it.
- const SVal *Recorded = state->get<CStringLength>(MR);
- if (Recorded)
- return *Recorded;
-
- // Otherwise, get a new symbol and update the state.
- unsigned Count = C.getNodeBuilder().getCurrentBlockCount();
- SValBuilder &svalBuilder = C.getSValBuilder();
- QualType sizeTy = svalBuilder.getContext().getSizeType();
- SVal strLength = svalBuilder.getMetadataSymbolVal(getTag(), MR, Ex, sizeTy, Count);
- state = state->set<CStringLength>(MR, strLength);
- return strLength;
-}
-
-SVal CStringChecker::getCStringLength(CheckerContext &C, const GRState *&state,
- const Expr *Ex, SVal Buf) {
- const MemRegion *MR = Buf.getAsRegion();
- if (!MR) {
- // If we can't get a region, see if it's something we /know/ isn't a
- // C string. In the context of locations, the only time we can issue such
- // a warning is for labels.
- if (loc::GotoLabel *Label = dyn_cast<loc::GotoLabel>(&Buf)) {
- if (ExplodedNode *N = C.generateNode(state)) {
- if (!BT_NotCString)
- BT_NotCString = new BuiltinBug("API",
- "Argument is not a null-terminated string.");
-
- llvm::SmallString<120> buf;
- llvm::raw_svector_ostream os(buf);
- os << "Argument to byte string function is the address of the label '"
- << Label->getLabel()->getID()->getName()
- << "', which is not a null-terminated string";
-
- // Generate a report for this bug.
- EnhancedBugReport *report = new EnhancedBugReport(*BT_NotCString,
- os.str(), N);
-
- report->addRange(Ex->getSourceRange());
- C.EmitReport(report);
- }
-
- return UndefinedVal();
- }
-
- // If it's not a region and not a label, give up.
- return UnknownVal();
- }
-
- // If we have a region, strip casts from it and see if we can figure out
- // its length. For anything we can't figure out, just return UnknownVal.
- MR = MR->StripCasts();
-
- switch (MR->getKind()) {
- case MemRegion::StringRegionKind: {
- // Modifying the contents of string regions is undefined [C99 6.4.5p6],
- // so we can assume that the byte length is the correct C string length.
- SValBuilder &svalBuilder = C.getSValBuilder();
- QualType sizeTy = svalBuilder.getContext().getSizeType();
- const StringLiteral *strLit = cast<StringRegion>(MR)->getStringLiteral();
- return svalBuilder.makeIntVal(strLit->getByteLength(), sizeTy);
- }
- case MemRegion::SymbolicRegionKind:
- case MemRegion::AllocaRegionKind:
- case MemRegion::VarRegionKind:
- case MemRegion::FieldRegionKind:
- case MemRegion::ObjCIvarRegionKind:
- return getCStringLengthForRegion(C, state, Ex, MR);
- case MemRegion::CompoundLiteralRegionKind:
- // FIXME: Can we track this? Is it necessary?
- return UnknownVal();
- case MemRegion::ElementRegionKind:
- // FIXME: How can we handle this? It's not good enough to subtract the
- // offset from the base string length; consider "123\x00567" and &a[5].
- return UnknownVal();
- default:
- // Other regions (mostly non-data) can't have a reliable C string length.
- // In this case, an error is emitted and UndefinedVal is returned.
- // The caller should always be prepared to handle this case.
- if (ExplodedNode *N = C.generateNode(state)) {
- if (!BT_NotCString)
- BT_NotCString = new BuiltinBug("API",
- "Argument is not a null-terminated string.");
-
- llvm::SmallString<120> buf;
- llvm::raw_svector_ostream os(buf);
-
- os << "Argument to byte string function is ";
-
- if (SummarizeRegion(os, C.getASTContext(), MR))
- os << ", which is not a null-terminated string";
- else
- os << "not a null-terminated string";
-
- // Generate a report for this bug.
- EnhancedBugReport *report = new EnhancedBugReport(*BT_NotCString,
- os.str(), N);
-
- report->addRange(Ex->getSourceRange());
- C.EmitReport(report);
- }
-
- return UndefinedVal();
- }
-}
-
-const GRState *CStringChecker::InvalidateBuffer(CheckerContext &C,
- const GRState *state,
- const Expr *E, SVal V) {
- Loc *L = dyn_cast<Loc>(&V);
- if (!L)
- return state;
-
- // FIXME: This is a simplified version of what's in CFRefCount.cpp -- it makes
- // some assumptions about the value that CFRefCount can't. Even so, it should
- // probably be refactored.
- if (loc::MemRegionVal* MR = dyn_cast<loc::MemRegionVal>(L)) {
- const MemRegion *R = MR->getRegion()->StripCasts();
-
- // Are we dealing with an ElementRegion? If so, we should be invalidating
- // the super-region.
- if (const ElementRegion *ER = dyn_cast<ElementRegion>(R)) {
- R = ER->getSuperRegion();
- // FIXME: What about layers of ElementRegions?
- }
-
- // Invalidate this region.
- unsigned Count = C.getNodeBuilder().getCurrentBlockCount();
- return state->InvalidateRegion(R, E, Count, NULL);
- }
-
- // If we have a non-region value by chance, just remove the binding.
- // FIXME: is this necessary or correct? This handles the non-Region
- // cases. Is it ever valid to store to these?
- return state->unbindLoc(*L);
-}
-
-bool CStringChecker::SummarizeRegion(llvm::raw_ostream& os, ASTContext& Ctx,
- const MemRegion *MR) {
- const TypedRegion *TR = dyn_cast<TypedRegion>(MR);
- if (!TR)
- return false;
-
- switch (TR->getKind()) {
- case MemRegion::FunctionTextRegionKind: {
- const FunctionDecl *FD = cast<FunctionTextRegion>(TR)->getDecl();
- if (FD)
- os << "the address of the function '" << FD << "'";
- else
- os << "the address of a function";
- return true;
- }
- case MemRegion::BlockTextRegionKind:
- os << "block text";
- return true;
- case MemRegion::BlockDataRegionKind:
- os << "a block";
- return true;
- case MemRegion::CXXThisRegionKind:
- case MemRegion::CXXTempObjectRegionKind:
- os << "a C++ temp object of type " << TR->getValueType().getAsString();
- return true;
- case MemRegion::VarRegionKind:
- os << "a variable of type" << TR->getValueType().getAsString();
- return true;
- case MemRegion::FieldRegionKind:
- os << "a field of type " << TR->getValueType().getAsString();
- return true;
- case MemRegion::ObjCIvarRegionKind:
- os << "an instance variable of type " << TR->getValueType().getAsString();
- return true;
- default:
- return false;
- }
-}
-
-//===----------------------------------------------------------------------===//
-// evaluation of individual function calls.
-//===----------------------------------------------------------------------===//
-
-void CStringChecker::evalCopyCommon(CheckerContext &C, const GRState *state,
- const Expr *Size, const Expr *Dest,
- const Expr *Source, bool Restricted) {
- // See if the size argument is zero.
- SVal sizeVal = state->getSVal(Size);
- QualType sizeTy = Size->getType();
-
- const GRState *stateZeroSize, *stateNonZeroSize;
- llvm::tie(stateZeroSize, stateNonZeroSize) = assumeZero(C, state, sizeVal, sizeTy);
-
- // If the size is zero, there won't be any actual memory access.
- if (stateZeroSize)
- C.addTransition(stateZeroSize);
-
- // If the size can be nonzero, we have to check the other arguments.
- if (stateNonZeroSize) {
- state = stateNonZeroSize;
- state = CheckBufferAccess(C, state, Size, Dest, Source,
- /* FirstIsDst = */ true);
- if (Restricted)
- state = CheckOverlap(C, state, Size, Dest, Source);
-
- if (state) {
- // Invalidate the destination.
- // FIXME: Even if we can't perfectly model the copy, we should see if we
- // can use LazyCompoundVals to copy the source values into the destination.
- // This would probably remove any existing bindings past the end of the
- // copied region, but that's still an improvement over blank invalidation.
- state = InvalidateBuffer(C, state, Dest, state->getSVal(Dest));
- C.addTransition(state);
- }
- }
-}
-
-
-void CStringChecker::evalMemcpy(CheckerContext &C, const CallExpr *CE) {
- // void *memcpy(void *restrict dst, const void *restrict src, size_t n);
- // The return value is the address of the destination buffer.
- const Expr *Dest = CE->getArg(0);
- const GRState *state = C.getState();
- state = state->BindExpr(CE, state->getSVal(Dest));
- evalCopyCommon(C, state, CE->getArg(2), Dest, CE->getArg(1), true);
-}
-
-void CStringChecker::evalMemmove(CheckerContext &C, const CallExpr *CE) {
- // void *memmove(void *dst, const void *src, size_t n);
- // The return value is the address of the destination buffer.
- const Expr *Dest = CE->getArg(0);
- const GRState *state = C.getState();
- state = state->BindExpr(CE, state->getSVal(Dest));
- evalCopyCommon(C, state, CE->getArg(2), Dest, CE->getArg(1));
-}
-
-void CStringChecker::evalBcopy(CheckerContext &C, const CallExpr *CE) {
- // void bcopy(const void *src, void *dst, size_t n);
- evalCopyCommon(C, C.getState(), CE->getArg(2), CE->getArg(1), CE->getArg(0));
-}
-
-void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE) {
- // int memcmp(const void *s1, const void *s2, size_t n);
- const Expr *Left = CE->getArg(0);
- const Expr *Right = CE->getArg(1);
- const Expr *Size = CE->getArg(2);
-
- const GRState *state = C.getState();
- SValBuilder &svalBuilder = C.getSValBuilder();
-
- // See if the size argument is zero.
- SVal sizeVal = state->getSVal(Size);
- QualType sizeTy = Size->getType();
-
- const GRState *stateZeroSize, *stateNonZeroSize;
- llvm::tie(stateZeroSize, stateNonZeroSize) =
- assumeZero(C, state, sizeVal, sizeTy);
-
- // If the size can be zero, the result will be 0 in that case, and we don't
- // have to check either of the buffers.
- if (stateZeroSize) {
- state = stateZeroSize;
- state = state->BindExpr(CE, svalBuilder.makeZeroVal(CE->getType()));
- C.addTransition(state);
- }
-
- // If the size can be nonzero, we have to check the other arguments.
- if (stateNonZeroSize) {
- state = stateNonZeroSize;
- // If we know the two buffers are the same, we know the result is 0.
- // First, get the two buffers' addresses. Another checker will have already
- // made sure they're not undefined.
- DefinedOrUnknownSVal LV = cast<DefinedOrUnknownSVal>(state->getSVal(Left));
- DefinedOrUnknownSVal RV = cast<DefinedOrUnknownSVal>(state->getSVal(Right));
-
- // See if they are the same.
- DefinedOrUnknownSVal SameBuf = svalBuilder.evalEQ(state, LV, RV);
- const GRState *StSameBuf, *StNotSameBuf;
- llvm::tie(StSameBuf, StNotSameBuf) = state->assume(SameBuf);
-
- // If the two arguments might be the same buffer, we know the result is zero,
- // and we only need to check one size.
- if (StSameBuf) {
- state = StSameBuf;
- state = CheckBufferAccess(C, state, Size, Left);
- if (state) {
- state = StSameBuf->BindExpr(CE, svalBuilder.makeZeroVal(CE->getType()));
- C.addTransition(state);
- }
- }
-
- // If the two arguments might be different buffers, we have to check the
- // size of both of them.
- if (StNotSameBuf) {
- state = StNotSameBuf;
- state = CheckBufferAccess(C, state, Size, Left, Right);
- if (state) {
- // The return value is the comparison result, which we don't know.
- unsigned Count = C.getNodeBuilder().getCurrentBlockCount();
- SVal CmpV = svalBuilder.getConjuredSymbolVal(NULL, CE, Count);
- state = state->BindExpr(CE, CmpV);
- C.addTransition(state);
- }
- }
- }
-}
-
-void CStringChecker::evalstrLength(CheckerContext &C, const CallExpr *CE) {
- // size_t strlen(const char *s);
- const GRState *state = C.getState();
- const Expr *Arg = CE->getArg(0);
- SVal ArgVal = state->getSVal(Arg);
-
- // Check that the argument is non-null.
- state = checkNonNull(C, state, Arg, ArgVal);
-
- if (state) {
- SVal strLength = getCStringLength(C, state, Arg, ArgVal);
-
- // If the argument isn't a valid C string, there's no valid state to
- // transition to.
- if (strLength.isUndef())
- return;
-
- // If getCStringLength couldn't figure out the length, conjure a return
- // value, so it can be used in constraints, at least.
- if (strLength.isUnknown()) {
- unsigned Count = C.getNodeBuilder().getCurrentBlockCount();
- strLength = C.getSValBuilder().getConjuredSymbolVal(NULL, CE, Count);
- }
-
- // Bind the return value.
- state = state->BindExpr(CE, strLength);
- C.addTransition(state);
- }
-}
-
-void CStringChecker::evalStrcpy(CheckerContext &C, const CallExpr *CE) {
- // char *strcpy(char *restrict dst, const char *restrict src);
- evalStrcpyCommon(C, CE, /* returnEnd = */ false);
-}
-
-void CStringChecker::evalStpcpy(CheckerContext &C, const CallExpr *CE) {
- // char *stpcpy(char *restrict dst, const char *restrict src);
- evalStrcpyCommon(C, CE, /* returnEnd = */ true);
-}
-
-void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
- bool returnEnd) {
- const GRState *state = C.getState();
-
- // Check that the destination is non-null
- const Expr *Dst = CE->getArg(0);
- SVal DstVal = state->getSVal(Dst);
-
- state = checkNonNull(C, state, Dst, DstVal);
- if (!state)
- return;
-
- // Check that the source is non-null.
- const Expr *srcExpr = CE->getArg(1);
- SVal srcVal = state->getSVal(srcExpr);
- state = checkNonNull(C, state, srcExpr, srcVal);
- if (!state)
- return;
-
- // Get the string length of the source.
- SVal strLength = getCStringLength(C, state, srcExpr, srcVal);
-
- // If the source isn't a valid C string, give up.
- if (strLength.isUndef())
- return;
-
- SVal Result = (returnEnd ? UnknownVal() : DstVal);
-
- // If the destination is a MemRegion, try to check for a buffer overflow and
- // record the new string length.
- if (loc::MemRegionVal *dstRegVal = dyn_cast<loc::MemRegionVal>(&DstVal)) {
- // If the length is known, we can check for an overflow.
- if (NonLoc *knownStrLength = dyn_cast<NonLoc>(&strLength)) {
- SVal lastElement =
- C.getSValBuilder().evalBinOpLN(state, BO_Add, *dstRegVal,
- *knownStrLength, Dst->getType());
-
- state = CheckLocation(C, state, Dst, lastElement, /* IsDst = */ true);
- if (!state)
- return;
-
- // If this is a stpcpy-style copy, the last element is the return value.
- if (returnEnd)
- Result = lastElement;
- }
-
- // Invalidate the destination. This must happen before we set the C string
- // length because invalidation will clear the length.
- // FIXME: Even if we can't perfectly model the copy, we should see if we
- // can use LazyCompoundVals to copy the source values into the destination.
- // This would probably remove any existing bindings past the end of the
- // string, but that's still an improvement over blank invalidation.
- state = InvalidateBuffer(C, state, Dst, *dstRegVal);
-
- // Set the C string length of the destination.
- state = setCStringLength(state, dstRegVal->getRegion(), strLength);
- }
-
- // If this is a stpcpy-style copy, but we were unable to check for a buffer
- // overflow, we still need a result. Conjure a return value.
- if (returnEnd && Result.isUnknown()) {
- SValBuilder &svalBuilder = C.getSValBuilder();
- unsigned Count = C.getNodeBuilder().getCurrentBlockCount();
- strLength = svalBuilder.getConjuredSymbolVal(NULL, CE, Count);
- }
-
- // Set the return value.
- state = state->BindExpr(CE, Result);
- C.addTransition(state);
-}
-
-//===----------------------------------------------------------------------===//
-// The driver method, and other Checker callbacks.
-//===----------------------------------------------------------------------===//
-
-bool CStringChecker::evalCallExpr(CheckerContext &C, const CallExpr *CE) {
- // Get the callee. All the functions we care about are C functions
- // with simple identifiers.
- const GRState *state = C.getState();
- const Expr *Callee = CE->getCallee();
- const FunctionDecl *FD = state->getSVal(Callee).getAsFunctionDecl();
-
- if (!FD)
- return false;
-
- // Get the name of the callee. If it's a builtin, strip off the prefix.
- IdentifierInfo *II = FD->getIdentifier();
- if (!II) // if no identifier, not a simple C function
- return false;
- llvm::StringRef Name = II->getName();
- if (Name.startswith("__builtin_"))
- Name = Name.substr(10);
-
- FnCheck evalFunction = llvm::StringSwitch<FnCheck>(Name)
- .Cases("memcpy", "__memcpy_chk", &CStringChecker::evalMemcpy)
- .Cases("memcmp", "bcmp", &CStringChecker::evalMemcmp)
- .Cases("memmove", "__memmove_chk", &CStringChecker::evalMemmove)
- .Cases("strcpy", "__strcpy_chk", &CStringChecker::evalStrcpy)
- .Cases("stpcpy", "__stpcpy_chk", &CStringChecker::evalStpcpy)
- .Case("strlen", &CStringChecker::evalstrLength)
- .Case("bcopy", &CStringChecker::evalBcopy)
- .Default(NULL);
-
- // If the callee isn't a string function, let another checker handle it.
- if (!evalFunction)
- return false;
-
- // Check and evaluate the call.
- (this->*evalFunction)(C, CE);
- return true;
-}
-
-void CStringChecker::PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS) {
- // Record string length for char a[] = "abc";
- const GRState *state = C.getState();
-
- for (DeclStmt::const_decl_iterator I = DS->decl_begin(), E = DS->decl_end();
- I != E; ++I) {
- const VarDecl *D = dyn_cast<VarDecl>(*I);
- if (!D)
- continue;
-
- // FIXME: Handle array fields of structs.
- if (!D->getType()->isArrayType())
- continue;
-
- const Expr *Init = D->getInit();
- if (!Init)
- continue;
- if (!isa<StringLiteral>(Init))
- continue;
-
- Loc VarLoc = state->getLValue(D, C.getPredecessor()->getLocationContext());
- const MemRegion *MR = VarLoc.getAsRegion();
- if (!MR)
- continue;
-
- SVal StrVal = state->getSVal(Init);
- assert(StrVal.isValid() && "Initializer string is unknown or undefined");
- DefinedOrUnknownSVal strLength
- = cast<DefinedOrUnknownSVal>(getCStringLength(C, state, Init, StrVal));
-
- state = state->set<CStringLength>(MR, strLength);
- }
-
- C.addTransition(state);
-}
-
-bool CStringChecker::WantsRegionChangeUpdate(const GRState *state) {
- CStringLength::EntryMap Entries = state->get<CStringLength>();
- return !Entries.isEmpty();
-}
-
-const GRState *CStringChecker::EvalRegionChanges(const GRState *state,
- const MemRegion * const *Begin,
- const MemRegion * const *End,
- bool *) {
- CStringLength::EntryMap Entries = state->get<CStringLength>();
- if (Entries.isEmpty())
- return state;
-
- llvm::SmallPtrSet<const MemRegion *, 8> Invalidated;
- llvm::SmallPtrSet<const MemRegion *, 32> SuperRegions;
-
- // First build sets for the changed regions and their super-regions.
- for ( ; Begin != End; ++Begin) {
- const MemRegion *MR = *Begin;
- Invalidated.insert(MR);
-
- SuperRegions.insert(MR);
- while (const SubRegion *SR = dyn_cast<SubRegion>(MR)) {
- MR = SR->getSuperRegion();
- SuperRegions.insert(MR);
- }
- }
-
- CStringLength::EntryMap::Factory &F = state->get_context<CStringLength>();
-
- // Then loop over the entries in the current state.
- for (CStringLength::EntryMap::iterator I = Entries.begin(),
- E = Entries.end(); I != E; ++I) {
- const MemRegion *MR = I.getKey();
-
- // Is this entry for a super-region of a changed region?
- if (SuperRegions.count(MR)) {
- Entries = F.remove(Entries, MR);
- continue;
- }
-
- // Is this entry for a sub-region of a changed region?
- const MemRegion *Super = MR;
- while (const SubRegion *SR = dyn_cast<SubRegion>(Super)) {
- Super = SR->getSuperRegion();
- if (Invalidated.count(Super)) {
- Entries = F.remove(Entries, MR);
- break;
- }
- }
- }
-
- return state->set<CStringLength>(Entries);
-}
-
-void CStringChecker::MarkLiveSymbols(const GRState *state, SymbolReaper &SR) {
- // Mark all symbols in our string length map as valid.
- CStringLength::EntryMap Entries = state->get<CStringLength>();
-
- for (CStringLength::EntryMap::iterator I = Entries.begin(), E = Entries.end();
- I != E; ++I) {
- SVal Len = I.getData();
- if (SymbolRef Sym = Len.getAsSymbol())
- SR.markInUse(Sym);
- }
-}
-
-void CStringChecker::evalDeadSymbols(CheckerContext &C, SymbolReaper &SR) {
- if (!SR.hasDeadSymbols())
- return;
-
- const GRState *state = C.getState();
- CStringLength::EntryMap Entries = state->get<CStringLength>();
- if (Entries.isEmpty())
- return;
-
- CStringLength::EntryMap::Factory &F = state->get_context<CStringLength>();
- for (CStringLength::EntryMap::iterator I = Entries.begin(), E = Entries.end();
- I != E; ++I) {
- SVal Len = I.getData();
- if (SymbolRef Sym = Len.getAsSymbol()) {
- if (SR.isDead(Sym))
- Entries = F.remove(Entries, I.getKey());
- }
- }
-
- state = state->set<CStringLength>(Entries);
- C.generateNode(state);
-}
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/CallAndMessageChecker.cpp b/clang/lib/StaticAnalyzer/EntoSA/Checkers/CallAndMessageChecker.cpp
deleted file mode 100644
index 2998406da05..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/CallAndMessageChecker.cpp
+++ /dev/null
@@ -1,350 +0,0 @@
-//===--- CallAndMessageChecker.cpp ------------------------------*- C++ -*--==//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This defines CallAndMessageChecker, a builtin checker that checks for various
-// errors of call and objc message expressions.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ExprEngineInternalChecks.h"
-#include "clang/AST/ParentMap.h"
-#include "clang/Basic/TargetInfo.h"
-#include "clang/StaticAnalyzer/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
-
-using namespace clang;
-using namespace ento;
-
-namespace {
-class CallAndMessageChecker
- : public CheckerVisitor<CallAndMessageChecker> {
- BugType *BT_call_null;
- BugType *BT_call_undef;
- BugType *BT_call_arg;
- BugType *BT_msg_undef;
- BugType *BT_msg_arg;
- BugType *BT_msg_ret;
-public:
- CallAndMessageChecker() :
- BT_call_null(0), BT_call_undef(0), BT_call_arg(0),
- BT_msg_undef(0), BT_msg_arg(0), BT_msg_ret(0) {}
-
- static void *getTag() {
- static int x = 0;
- return &x;
- }
-
- void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
- void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME);
- bool evalNilReceiver(CheckerContext &C, const ObjCMessageExpr *ME);
-
-private:
- bool PreVisitProcessArg(CheckerContext &C, const Expr *Ex,
- const char *BT_desc, BugType *&BT);
-
- void EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE);
- void emitNilReceiverBug(CheckerContext &C, const ObjCMessageExpr *ME,
- ExplodedNode *N);
-
- void HandleNilReceiver(CheckerContext &C, const GRState *state,
- const ObjCMessageExpr *ME);
-
- void LazyInit_BT(const char *desc, BugType *&BT) {
- if (!BT)
- BT = new BuiltinBug(desc);
- }
-};
-} // end anonymous namespace
-
-void ento::RegisterCallAndMessageChecker(ExprEngine &Eng) {
- Eng.registerCheck(new CallAndMessageChecker());
-}
-
-void CallAndMessageChecker::EmitBadCall(BugType *BT, CheckerContext &C,
- const CallExpr *CE) {
- ExplodedNode *N = C.generateSink();
- if (!N)
- return;
-
- EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N);
- R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
- bugreporter::GetCalleeExpr(N));
- C.EmitReport(R);
-}
-
-bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
- const Expr *Ex,
- const char *BT_desc,
- BugType *&BT) {
-
- const SVal &V = C.getState()->getSVal(Ex);
-
- if (V.isUndef()) {
- if (ExplodedNode *N = C.generateSink()) {
- LazyInit_BT(BT_desc, BT);
-
- // Generate a report for this bug.
- EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N);
- R->addRange(Ex->getSourceRange());
- R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Ex);
- C.EmitReport(R);
- }
- return true;
- }
-
- if (const nonloc::LazyCompoundVal *LV =
- dyn_cast<nonloc::LazyCompoundVal>(&V)) {
-
- class FindUninitializedField {
- public:
- llvm::SmallVector<const FieldDecl *, 10> FieldChain;
- private:
- ASTContext &C;
- StoreManager &StoreMgr;
- MemRegionManager &MrMgr;
- Store store;
- public:
- FindUninitializedField(ASTContext &c, StoreManager &storeMgr,
- MemRegionManager &mrMgr, Store s)
- : C(c), StoreMgr(storeMgr), MrMgr(mrMgr), store(s) {}
-
- bool Find(const TypedRegion *R) {
- QualType T = R->getValueType();
- if (const RecordType *RT = T->getAsStructureType()) {
- const RecordDecl *RD = RT->getDecl()->getDefinition();
- assert(RD && "Referred record has no definition");
- for (RecordDecl::field_iterator I =
- RD->field_begin(), E = RD->field_end(); I!=E; ++I) {
- const FieldRegion *FR = MrMgr.getFieldRegion(*I, R);
- FieldChain.push_back(*I);
- T = (*I)->getType();
- if (T->getAsStructureType()) {
- if (Find(FR))
- return true;
- }
- else {
- const SVal &V = StoreMgr.Retrieve(store, loc::MemRegionVal(FR));
- if (V.isUndef())
- return true;
- }
- FieldChain.pop_back();
- }
- }
-
- return false;
- }
- };
-
- const LazyCompoundValData *D = LV->getCVData();
- FindUninitializedField F(C.getASTContext(),
- C.getState()->getStateManager().getStoreManager(),
- C.getSValBuilder().getRegionManager(),
- D->getStore());
-
- if (F.Find(D->getRegion())) {
- if (ExplodedNode *N = C.generateSink()) {
- LazyInit_BT(BT_desc, BT);
- llvm::SmallString<512> Str;
- llvm::raw_svector_ostream os(Str);
- os << "Passed-by-value struct argument contains uninitialized data";
-
- if (F.FieldChain.size() == 1)
- os << " (e.g., field: '" << F.FieldChain[0] << "')";
- else {
- os << " (e.g., via the field chain: '";
- bool first = true;
- for (llvm::SmallVectorImpl<const FieldDecl *>::iterator
- DI = F.FieldChain.begin(), DE = F.FieldChain.end(); DI!=DE;++DI){
- if (first)
- first = false;
- else
- os << '.';
- os << *DI;
- }
- os << "')";
- }
-
- // Generate a report for this bug.
- EnhancedBugReport *R = new EnhancedBugReport(*BT, os.str(), N);
- R->addRange(Ex->getSourceRange());
-
- // FIXME: enhance track back for uninitialized value for arbitrary
- // memregions
- C.EmitReport(R);
- }
- return true;
- }
- }
-
- return false;
-}
-
-void CallAndMessageChecker::PreVisitCallExpr(CheckerContext &C,
- const CallExpr *CE){
-
- const Expr *Callee = CE->getCallee()->IgnoreParens();
- SVal L = C.getState()->getSVal(Callee);
-
- if (L.isUndef()) {
- if (!BT_call_undef)
- BT_call_undef =
- new BuiltinBug("Called function pointer is an uninitalized pointer value");
- EmitBadCall(BT_call_undef, C, CE);
- return;
- }
-
- if (isa<loc::ConcreteInt>(L)) {
- if (!BT_call_null)
- BT_call_null =
- new BuiltinBug("Called function pointer is null (null dereference)");
- EmitBadCall(BT_call_null, C, CE);
- }
-
- for (CallExpr::const_arg_iterator I = CE->arg_begin(), E = CE->arg_end();
- I != E; ++I)
- if (PreVisitProcessArg(C, *I,
- "Function call argument is an uninitialized value",
- BT_call_arg))
- return;
-}
-
-void CallAndMessageChecker::PreVisitObjCMessageExpr(CheckerContext &C,
- const ObjCMessageExpr *ME) {
-
- const GRState *state = C.getState();
-
- // FIXME: Handle 'super'?
- if (const Expr *receiver = ME->getInstanceReceiver())
- if (state->getSVal(receiver).isUndef()) {
- if (ExplodedNode *N = C.generateSink()) {
- if (!BT_msg_undef)
- BT_msg_undef =
- new BuiltinBug("Receiver in message expression is an uninitialized value");
- EnhancedBugReport *R =
- new EnhancedBugReport(*BT_msg_undef, BT_msg_undef->getName(), N);
- R->addRange(receiver->getSourceRange());
- R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
- receiver);
- C.EmitReport(R);
- }
- return;
- }
-
- // Check for any arguments that are uninitialized/undefined.
- for (ObjCMessageExpr::const_arg_iterator I = ME->arg_begin(),
- E = ME->arg_end(); I != E; ++I)
- if (PreVisitProcessArg(C, *I,
- "Argument in message expression "
- "is an uninitialized value", BT_msg_arg))
- return;
-}
-
-bool CallAndMessageChecker::evalNilReceiver(CheckerContext &C,
- const ObjCMessageExpr *ME) {
- HandleNilReceiver(C, C.getState(), ME);
- return true; // Nil receiver is not handled elsewhere.
-}
-
-void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C,
- const ObjCMessageExpr *ME,
- ExplodedNode *N) {
-
- if (!BT_msg_ret)
- BT_msg_ret =
- new BuiltinBug("Receiver in message expression is "
- "'nil' and returns a garbage value");
-
- llvm::SmallString<200> buf;
- llvm::raw_svector_ostream os(buf);
- os << "The receiver of message '" << ME->getSelector().getAsString()
- << "' is nil and returns a value of type '"
- << ME->getType().getAsString() << "' that will be garbage";
-
- EnhancedBugReport *report = new EnhancedBugReport(*BT_msg_ret, os.str(), N);
- if (const Expr *receiver = ME->getInstanceReceiver()) {
- report->addRange(receiver->getSourceRange());
- report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
- receiver);
- }
- C.EmitReport(report);
-}
-
-static bool supportsNilWithFloatRet(const llvm::Triple &triple) {
- return triple.getVendor() == llvm::Triple::Apple &&
- (triple.getDarwinMajorNumber() >= 9 ||
- triple.getArch() == llvm::Triple::arm ||
- triple.getArch() == llvm::Triple::thumb);
-}
-
-void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
- const GRState *state,
- const ObjCMessageExpr *ME) {
-
- // Check the return type of the message expression. A message to nil will
- // return different values depending on the return type and the architecture.
- QualType RetTy = ME->getType();
-
- ASTContext &Ctx = C.getASTContext();
- CanQualType CanRetTy = Ctx.getCanonicalType(RetTy);
-
- if (CanRetTy->isStructureOrClassType()) {
- // FIXME: At some point we shouldn't rely on isConsumedExpr(), but instead
- // have the "use of undefined value" be smarter about where the
- // undefined value came from.
- if (C.getPredecessor()->getParentMap().isConsumedExpr(ME)) {
- if (ExplodedNode* N = C.generateSink(state))
- emitNilReceiverBug(C, ME, N);
- return;
- }
-
- // The result is not consumed by a surrounding expression. Just propagate
- // the current state.
- C.addTransition(state);
- return;
- }
-
- // Other cases: check if the return type is smaller than void*.
- if (CanRetTy != Ctx.VoidTy &&
- C.getPredecessor()->getParentMap().isConsumedExpr(ME)) {
- // Compute: sizeof(void *) and sizeof(return type)
- const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);
- const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy);
-
- if (voidPtrSize < returnTypeSize &&
- !(supportsNilWithFloatRet(Ctx.Target.getTriple()) &&
- (Ctx.FloatTy == CanRetTy ||
- Ctx.DoubleTy == CanRetTy ||
- Ctx.LongDoubleTy == CanRetTy ||
- Ctx.LongLongTy == CanRetTy ||
- Ctx.UnsignedLongLongTy == CanRetTy))) {
- if (ExplodedNode* N = C.generateSink(state))
- emitNilReceiverBug(C, ME, N);
- return;
- }
-
- // Handle the safe cases where the return value is 0 if the
- // receiver is nil.
- //
- // FIXME: For now take the conservative approach that we only
- // return null values if we *know* that the receiver is nil.
- // This is because we can have surprises like:
- //
- // ... = [[NSScreens screens] objectAtIndex:0];
- //
- // What can happen is that [... screens] could return nil, but
- // it most likely isn't nil. We should assume the semantics
- // of this case unless we have *a lot* more knowledge.
- //
- SVal V = C.getSValBuilder().makeZeroVal(ME->getType());
- C.generateNode(state->BindExpr(ME, V));
- return;
- }
-
- C.addTransition(state);
-}
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/CastSizeChecker.cpp b/clang/lib/StaticAnalyzer/EntoSA/Checkers/CastSizeChecker.cpp
deleted file mode 100644
index 9329ea39d45..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/CastSizeChecker.cpp
+++ /dev/null
@@ -1,91 +0,0 @@
-//=== CastSizeChecker.cpp ---------------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// CastSizeChecker checks when casting a malloc'ed symbolic region to type T,
-// whether the size of the symbolic region is a multiple of the size of T.
-//
-//===----------------------------------------------------------------------===//
-#include "clang/AST/CharUnits.h"
-#include "clang/StaticAnalyzer/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
-#include "ExprEngineInternalChecks.h"
-
-using namespace clang;
-using namespace ento;
-
-namespace {
-class CastSizeChecker : public CheckerVisitor<CastSizeChecker> {
- BuiltinBug *BT;
-public:
- CastSizeChecker() : BT(0) {}
- static void *getTag();
- void PreVisitCastExpr(CheckerContext &C, const CastExpr *B);
-};
-}
-
-void *CastSizeChecker::getTag() {
- static int x;
- return &x;
-}
-
-void CastSizeChecker::PreVisitCastExpr(CheckerContext &C, const CastExpr *CE) {
- const Expr *E = CE->getSubExpr();
- ASTContext &Ctx = C.getASTContext();
- QualType ToTy = Ctx.getCanonicalType(CE->getType());
- PointerType *ToPTy = dyn_cast<PointerType>(ToTy.getTypePtr());
-
- if (!ToPTy)
- return;
-
- QualType ToPointeeTy = ToPTy->getPointeeType();
-
- // Only perform the check if 'ToPointeeTy' is a complete type.
- if (ToPointeeTy->isIncompleteType())
- return;
-
- const GRState *state = C.getState();
- const MemRegion *R = state->getSVal(E).getAsRegion();
- if (R == 0)
- return;
-
- const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R);
- if (SR == 0)
- return;
-
- SValBuilder &svalBuilder = C.getSValBuilder();
- SVal extent = SR->getExtent(svalBuilder);
- const llvm::APSInt *extentInt = svalBuilder.getKnownValue(state, extent);
- if (!extentInt)
- return;
-
- CharUnits regionSize = CharUnits::fromQuantity(extentInt->getSExtValue());
- CharUnits typeSize = C.getASTContext().getTypeSizeInChars(ToPointeeTy);
-
- // Ignore void, and a few other un-sizeable types.
- if (typeSize.isZero())
- return;
-
- if (regionSize % typeSize != 0) {
- if (ExplodedNode *errorNode = C.generateSink()) {
- if (!BT)
- BT = new BuiltinBug("Cast region with wrong size.",
- "Cast a region whose size is not a multiple of the"
- " destination type size.");
- RangedBugReport *R = new RangedBugReport(*BT, BT->getDescription(),
- errorNode);
- R->addRange(CE->getSourceRange());
- C.EmitReport(R);
- }
- }
-}
-
-
-void ento::RegisterCastSizeChecker(ExprEngine &Eng) {
- Eng.registerCheck(new CastSizeChecker());
-}
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/CastToStructChecker.cpp b/clang/lib/StaticAnalyzer/EntoSA/Checkers/CastToStructChecker.cpp
deleted file mode 100644
index dd6ac7ea84c..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/CastToStructChecker.cpp
+++ /dev/null
@@ -1,79 +0,0 @@
-//=== CastToStructChecker.cpp - Fixed address usage checker ----*- C++ -*--===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This files defines CastToStructChecker, a builtin checker that checks for
-// cast from non-struct pointer to struct pointer.
-// This check corresponds to CWE-588.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/StaticAnalyzer/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
-#include "ExprEngineInternalChecks.h"
-
-using namespace clang;
-using namespace ento;
-
-namespace {
-class CastToStructChecker
- : public CheckerVisitor<CastToStructChecker> {
- BuiltinBug *BT;
-public:
- CastToStructChecker() : BT(0) {}
- static void *getTag();
- void PreVisitCastExpr(CheckerContext &C, const CastExpr *B);
-};
-}
-
-void *CastToStructChecker::getTag() {
- static int x;
- return &x;
-}
-
-void CastToStructChecker::PreVisitCastExpr(CheckerContext &C,
- const CastExpr *CE) {
- const Expr *E = CE->getSubExpr();
- ASTContext &Ctx = C.getASTContext();
- QualType OrigTy = Ctx.getCanonicalType(E->getType());
- QualType ToTy = Ctx.getCanonicalType(CE->getType());
-
- PointerType *OrigPTy = dyn_cast<PointerType>(OrigTy.getTypePtr());
- PointerType *ToPTy = dyn_cast<PointerType>(ToTy.getTypePtr());
-
- if (!ToPTy || !OrigPTy)
- return;
-
- QualType OrigPointeeTy = OrigPTy->getPointeeType();
- QualType ToPointeeTy = ToPTy->getPointeeType();
-
- if (!ToPointeeTy->isStructureOrClassType())
- return;
-
- // We allow cast from void*.
- if (OrigPointeeTy->isVoidType())
- return;
-
- // Now the cast-to-type is struct pointer, the original type is not void*.
- if (!OrigPointeeTy->isRecordType()) {
- if (ExplodedNode *N = C.generateNode()) {
- if (!BT)
- BT = new BuiltinBug("Cast from non-struct type to struct type",
- "Casting a non-structure type to a structure type "
- "and accessing a field can lead to memory access "
- "errors or data corruption.");
- RangedBugReport *R = new RangedBugReport(*BT,BT->getDescription(), N);
- R->addRange(CE->getSourceRange());
- C.EmitReport(R);
- }
- }
-}
-
-void ento::RegisterCastToStructChecker(ExprEngine &Eng) {
- Eng.registerCheck(new CastToStructChecker());
-}
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/CheckDeadStores.cpp b/clang/lib/StaticAnalyzer/EntoSA/Checkers/CheckDeadStores.cpp
deleted file mode 100644
index 1fe40c56e83..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/CheckDeadStores.cpp
+++ /dev/null
@@ -1,290 +0,0 @@
-//==- DeadStores.cpp - Check for stores to dead variables --------*- C++ -*-==//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines a DeadStores, a flow-sensitive checker that looks for
-// stores to variables that are no longer live.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
-#include "clang/Analysis/Analyses/LiveVariables.h"
-#include "clang/Analysis/Visitors/CFGRecStmtVisitor.h"
-#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
-#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
-#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
-#include "clang/Basic/Diagnostic.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/AST/ParentMap.h"
-#include "llvm/ADT/SmallPtrSet.h"
-
-using namespace clang;
-using namespace ento;
-
-namespace {
-
-class DeadStoreObs : public LiveVariables::ObserverTy {
- ASTContext &Ctx;
- BugReporter& BR;
- ParentMap& Parents;
- llvm::SmallPtrSet<VarDecl*, 20> Escaped;
-
- enum DeadStoreKind { Standard, Enclosing, DeadIncrement, DeadInit };
-
-public:
- DeadStoreObs(ASTContext &ctx, BugReporter& br, ParentMap& parents,
- llvm::SmallPtrSet<VarDecl*, 20> &escaped)
- : Ctx(ctx), BR(br), Parents(parents), Escaped(escaped) {}
-
- virtual ~DeadStoreObs() {}
-
- void Report(VarDecl* V, DeadStoreKind dsk, SourceLocation L, SourceRange R) {
- if (Escaped.count(V))
- return;
-
- std::string name = V->getNameAsString();
-
- const char* BugType = 0;
- std::string msg;
-
- switch (dsk) {
- default:
- assert(false && "Impossible dead store type.");
-
- case DeadInit:
- BugType = "Dead initialization";
- msg = "Value stored to '" + name +
- "' during its initialization is never read";
- break;
-
- case DeadIncrement:
- BugType = "Dead increment";
- case Standard:
- if (!BugType) BugType = "Dead assignment";
- msg = "Value stored to '" + name + "' is never read";
- break;
-
- case Enclosing:
- BugType = "Dead nested assignment";
- msg = "Although the value stored to '" + name +
- "' is used in the enclosing expression, the value is never actually"
- " read from '" + name + "'";
- break;
- }
-
- BR.EmitBasicReport(BugType, "Dead store", msg, L, R);
- }
-
- void CheckVarDecl(VarDecl* VD, Expr* Ex, Expr* Val,
- DeadStoreKind dsk,
- const LiveVariables::AnalysisDataTy& AD,
- const LiveVariables::ValTy& Live) {
-
- if (!VD->hasLocalStorage())
- return;
- // Reference types confuse the dead stores checker. Skip them
- // for now.
- if (VD->getType()->getAs<ReferenceType>())
- return;
-
- if (!Live(VD, AD) &&
- !(VD->getAttr<UnusedAttr>() || VD->getAttr<BlocksAttr>()))
- Report(VD, dsk, Ex->getSourceRange().getBegin(),
- Val->getSourceRange());
- }
-
- void CheckDeclRef(DeclRefExpr* DR, Expr* Val, DeadStoreKind dsk,
- const LiveVariables::AnalysisDataTy& AD,
- const LiveVariables::ValTy& Live) {
- if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl()))
- CheckVarDecl(VD, DR, Val, dsk, AD, Live);
- }
-
- bool isIncrement(VarDecl* VD, BinaryOperator* B) {
- if (B->isCompoundAssignmentOp())
- return true;
-
- Expr* RHS = B->getRHS()->IgnoreParenCasts();
- BinaryOperator* BRHS = dyn_cast<BinaryOperator>(RHS);
-
- if (!BRHS)
- return false;
-
- DeclRefExpr *DR;
-
- if ((DR = dyn_cast<DeclRefExpr>(BRHS->getLHS()->IgnoreParenCasts())))
- if (DR->getDecl() == VD)
- return true;
-
- if ((DR = dyn_cast<DeclRefExpr>(BRHS->getRHS()->IgnoreParenCasts())))
- if (DR->getDecl() == VD)
- return true;
-
- return false;
- }
-
- virtual void ObserveStmt(Stmt* S,
- const LiveVariables::AnalysisDataTy& AD,
- const LiveVariables::ValTy& Live) {
-
- // Skip statements in macros.
- if (S->getLocStart().isMacroID())
- return;
-
- if (BinaryOperator* B = dyn_cast<BinaryOperator>(S)) {
- if (!B->isAssignmentOp()) return; // Skip non-assignments.
-
- if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(B->getLHS()))
- if (VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
- // Special case: check for assigning null to a pointer.
- // This is a common form of defensive programming.
- QualType T = VD->getType();
- if (T->isPointerType() || T->isObjCObjectPointerType()) {
- if (B->getRHS()->isNullPointerConstant(Ctx,
- Expr::NPC_ValueDependentIsNull))
- return;
- }
-
- Expr* RHS = B->getRHS()->IgnoreParenCasts();
- // Special case: self-assignments. These are often used to shut up
- // "unused variable" compiler warnings.
- if (DeclRefExpr* RhsDR = dyn_cast<DeclRefExpr>(RHS))
- if (VD == dyn_cast<VarDecl>(RhsDR->getDecl()))
- return;
-
- // Otherwise, issue a warning.
- DeadStoreKind dsk = Parents.isConsumedExpr(B)
- ? Enclosing
- : (isIncrement(VD,B) ? DeadIncrement : Standard);
-
- CheckVarDecl(VD, DR, B->getRHS(), dsk, AD, Live);
- }
- }
- else if (UnaryOperator* U = dyn_cast<UnaryOperator>(S)) {
- if (!U->isIncrementOp())
- return;
-
- // Handle: ++x within a subexpression. The solution is not warn
- // about preincrements to dead variables when the preincrement occurs
- // as a subexpression. This can lead to false negatives, e.g. "(++x);"
- // A generalized dead code checker should find such issues.
- if (U->isPrefix() && Parents.isConsumedExpr(U))
- return;
-
- Expr *Ex = U->getSubExpr()->IgnoreParenCasts();
-
- if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(Ex))
- CheckDeclRef(DR, U, DeadIncrement, AD, Live);
- }
- else if (DeclStmt* DS = dyn_cast<DeclStmt>(S))
- // Iterate through the decls. Warn if any initializers are complex
- // expressions that are not live (never used).
- for (DeclStmt::decl_iterator DI=DS->decl_begin(), DE=DS->decl_end();
- DI != DE; ++DI) {
-
- VarDecl* V = dyn_cast<VarDecl>(*DI);
-
- if (!V)
- continue;
-
- if (V->hasLocalStorage()) {
- // Reference types confuse the dead stores checker. Skip them
- // for now.
- if (V->getType()->getAs<ReferenceType>())
- return;
-
- if (Expr* E = V->getInit()) {
- // Don't warn on C++ objects (yet) until we can show that their
- // constructors/destructors don't have side effects.
- if (isa<CXXConstructExpr>(E))
- return;
-
- if (isa<ExprWithCleanups>(E))
- return;
-
- // A dead initialization is a variable that is dead after it
- // is initialized. We don't flag warnings for those variables
- // marked 'unused'.
- if (!Live(V, AD) && V->getAttr<UnusedAttr>() == 0) {
- // Special case: check for initializations with constants.
- //
- // e.g. : int x = 0;
- //
- // If x is EVER assigned a new value later, don't issue
- // a warning. This is because such initialization can be
- // due to defensive programming.
- if (E->isConstantInitializer(Ctx, false))
- return;
-
- if (DeclRefExpr *DRE=dyn_cast<DeclRefExpr>(E->IgnoreParenCasts()))
- if (VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
- // Special case: check for initialization from constant
- // variables.
- //
- // e.g. extern const int MyConstant;
- // int x = MyConstant;
- //
- if (VD->hasGlobalStorage() &&
- VD->getType().isConstQualified())
- return;
- // Special case: check for initialization from scalar
- // parameters. This is often a form of defensive
- // programming. Non-scalars are still an error since
- // because it more likely represents an actual algorithmic
- // bug.
- if (isa<ParmVarDecl>(VD) && VD->getType()->isScalarType())
- return;
- }
-
- Report(V, DeadInit, V->getLocation(), E->getSourceRange());
- }
- }
- }
- }
- }
-};
-
-} // end anonymous namespace
-
-//===----------------------------------------------------------------------===//
-// Driver function to invoke the Dead-Stores checker on a CFG.
-//===----------------------------------------------------------------------===//
-
-namespace {
-class FindEscaped : public CFGRecStmtDeclVisitor<FindEscaped>{
- CFG *cfg;
-public:
- FindEscaped(CFG *c) : cfg(c) {}
-
- CFG& getCFG() { return *cfg; }
-
- llvm::SmallPtrSet<VarDecl*, 20> Escaped;
-
- void VisitUnaryOperator(UnaryOperator* U) {
- // Check for '&'. Any VarDecl whose value has its address-taken we
- // treat as escaped.
- Expr* E = U->getSubExpr()->IgnoreParenCasts();
- if (U->getOpcode() == UO_AddrOf)
- if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(E))
- if (VarDecl* VD = dyn_cast<VarDecl>(DR->getDecl())) {
- Escaped.insert(VD);
- return;
- }
- Visit(E);
- }
-};
-} // end anonymous namespace
-
-
-void ento::CheckDeadStores(CFG &cfg, LiveVariables &L, ParentMap &pmap,
- BugReporter& BR) {
- FindEscaped FS(&cfg);
- FS.getCFG().VisitBlockStmts(FS);
- DeadStoreObs A(BR.getContext(), BR, pmap, FS.Escaped);
- L.runOnAllBlocks(cfg, &A);
-}
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/CheckObjCDealloc.cpp b/clang/lib/StaticAnalyzer/EntoSA/Checkers/CheckObjCDealloc.cpp
deleted file mode 100644
index 932a6f5945f..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/CheckObjCDealloc.cpp
+++ /dev/null
@@ -1,262 +0,0 @@
-//==- CheckObjCDealloc.cpp - Check ObjC -dealloc implementation --*- C++ -*-==//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines a CheckObjCDealloc, a checker that
-// analyzes an Objective-C class's implementation to determine if it
-// correctly implements -dealloc.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
-#include "clang/StaticAnalyzer/BugReporter/PathDiagnostic.h"
-#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
-#include "clang/AST/ExprObjC.h"
-#include "clang/AST/Expr.h"
-#include "clang/AST/DeclObjC.h"
-#include "clang/Basic/LangOptions.h"
-#include "llvm/Support/raw_ostream.h"
-
-using namespace clang;
-using namespace ento;
-
-static bool scan_dealloc(Stmt* S, Selector Dealloc) {
-
- if (ObjCMessageExpr* ME = dyn_cast<ObjCMessageExpr>(S))
- if (ME->getSelector() == Dealloc) {
- switch (ME->getReceiverKind()) {
- case ObjCMessageExpr::Instance: return false;
- case ObjCMessageExpr::SuperInstance: return true;
- case ObjCMessageExpr::Class: break;
- case ObjCMessageExpr::SuperClass: break;
- }
- }
-
- // Recurse to children.
-
- for (Stmt::child_iterator I = S->child_begin(), E= S->child_end(); I!=E; ++I)
- if (*I && scan_dealloc(*I, Dealloc))
- return true;
-
- return false;
-}
-
-static bool scan_ivar_release(Stmt* S, ObjCIvarDecl* ID,
- const ObjCPropertyDecl* PD,
- Selector Release,
- IdentifierInfo* SelfII,
- ASTContext& Ctx) {
-
- // [mMyIvar release]
- if (ObjCMessageExpr* ME = dyn_cast<ObjCMessageExpr>(S))
- if (ME->getSelector() == Release)
- if (ME->getInstanceReceiver())
- if (Expr* Receiver = ME->getInstanceReceiver()->IgnoreParenCasts())
- if (ObjCIvarRefExpr* E = dyn_cast<ObjCIvarRefExpr>(Receiver))
- if (E->getDecl() == ID)
- return true;
-
- // [self setMyIvar:nil];
- if (ObjCMessageExpr* ME = dyn_cast<ObjCMessageExpr>(S))
- if (ME->getInstanceReceiver())
- if (Expr* Receiver = ME->getInstanceReceiver()->IgnoreParenCasts())
- if (DeclRefExpr* E = dyn_cast<DeclRefExpr>(Receiver))
- if (E->getDecl()->getIdentifier() == SelfII)
- if (ME->getMethodDecl() == PD->getSetterMethodDecl() &&
- ME->getNumArgs() == 1 &&
- ME->getArg(0)->isNullPointerConstant(Ctx,
- Expr::NPC_ValueDependentIsNull))
- return true;
-
- // self.myIvar = nil;
- if (BinaryOperator* BO = dyn_cast<BinaryOperator>(S))
- if (BO->isAssignmentOp())
- if (ObjCPropertyRefExpr* PRE =
- dyn_cast<ObjCPropertyRefExpr>(BO->getLHS()->IgnoreParenCasts()))
- if (PRE->isExplicitProperty() && PRE->getExplicitProperty() == PD)
- if (BO->getRHS()->isNullPointerConstant(Ctx,
- Expr::NPC_ValueDependentIsNull)) {
- // This is only a 'release' if the property kind is not
- // 'assign'.
- return PD->getSetterKind() != ObjCPropertyDecl::Assign;;
- }
-
- // Recurse to children.
- for (Stmt::child_iterator I = S->child_begin(), E= S->child_end(); I!=E; ++I)
- if (*I && scan_ivar_release(*I, ID, PD, Release, SelfII, Ctx))
- return true;
-
- return false;
-}
-
-void ento::CheckObjCDealloc(const ObjCImplementationDecl* D,
- const LangOptions& LOpts, BugReporter& BR) {
-
- assert (LOpts.getGCMode() != LangOptions::GCOnly);
-
- ASTContext& Ctx = BR.getContext();
- const ObjCInterfaceDecl* ID = D->getClassInterface();
-
- // Does the class contain any ivars that are pointers (or id<...>)?
- // If not, skip the check entirely.
- // NOTE: This is motivated by PR 2517:
- // http://llvm.org/bugs/show_bug.cgi?id=2517
-
- bool containsPointerIvar = false;
-
- for (ObjCInterfaceDecl::ivar_iterator I=ID->ivar_begin(), E=ID->ivar_end();
- I!=E; ++I) {
-
- ObjCIvarDecl* ID = *I;
- QualType T = ID->getType();
-
- if (!T->isObjCObjectPointerType() ||
- ID->getAttr<IBOutletAttr>() || // Skip IBOutlets.
- ID->getAttr<IBOutletCollectionAttr>()) // Skip IBOutletCollections.
- continue;
-
- containsPointerIvar = true;
- break;
- }
-
- if (!containsPointerIvar)
- return;
-
- // Determine if the class subclasses NSObject.
- IdentifierInfo* NSObjectII = &Ctx.Idents.get("NSObject");
- IdentifierInfo* SenTestCaseII = &Ctx.Idents.get("SenTestCase");
-
-
- for ( ; ID ; ID = ID->getSuperClass()) {
- IdentifierInfo *II = ID->getIdentifier();
-
- if (II == NSObjectII)
- break;
-
- // FIXME: For now, ignore classes that subclass SenTestCase, as these don't
- // need to implement -dealloc. They implement tear down in another way,
- // which we should try and catch later.
- // http://llvm.org/bugs/show_bug.cgi?id=3187
- if (II == SenTestCaseII)
- return;
- }
-
- if (!ID)
- return;
-
- // Get the "dealloc" selector.
- IdentifierInfo* II = &Ctx.Idents.get("dealloc");
- Selector S = Ctx.Selectors.getSelector(0, &II);
- ObjCMethodDecl* MD = 0;
-
- // Scan the instance methods for "dealloc".
- for (ObjCImplementationDecl::instmeth_iterator I = D->instmeth_begin(),
- E = D->instmeth_end(); I!=E; ++I) {
-
- if ((*I)->getSelector() == S) {
- MD = *I;
- break;
- }
- }
-
- if (!MD) { // No dealloc found.
-
- const char* name = LOpts.getGCMode() == LangOptions::NonGC
- ? "missing -dealloc"
- : "missing -dealloc (Hybrid MM, non-GC)";
-
- std::string buf;
- llvm::raw_string_ostream os(buf);
- os << "Objective-C class '" << D << "' lacks a 'dealloc' instance method";
-
- BR.EmitBasicReport(name, os.str(), D->getLocStart());
- return;
- }
-
- // dealloc found. Scan for missing [super dealloc].
- if (MD->getBody() && !scan_dealloc(MD->getBody(), S)) {
-
- const char* name = LOpts.getGCMode() == LangOptions::NonGC
- ? "missing [super dealloc]"
- : "missing [super dealloc] (Hybrid MM, non-GC)";
-
- std::string buf;
- llvm::raw_string_ostream os(buf);
- os << "The 'dealloc' instance method in Objective-C class '" << D
- << "' does not send a 'dealloc' message to its super class"
- " (missing [super dealloc])";
-
- BR.EmitBasicReport(name, os.str(), D->getLocStart());
- return;
- }
-
- // Get the "release" selector.
- IdentifierInfo* RII = &Ctx.Idents.get("release");
- Selector RS = Ctx.Selectors.getSelector(0, &RII);
-
- // Get the "self" identifier
- IdentifierInfo* SelfII = &Ctx.Idents.get("self");
-
- // Scan for missing and extra releases of ivars used by implementations
- // of synthesized properties
- for (ObjCImplementationDecl::propimpl_iterator I = D->propimpl_begin(),
- E = D->propimpl_end(); I!=E; ++I) {
-
- // We can only check the synthesized properties
- if ((*I)->getPropertyImplementation() != ObjCPropertyImplDecl::Synthesize)
- continue;
-
- ObjCIvarDecl* ID = (*I)->getPropertyIvarDecl();
- if (!ID)
- continue;
-
- QualType T = ID->getType();
- if (!T->isObjCObjectPointerType()) // Skip non-pointer ivars
- continue;
-
- const ObjCPropertyDecl* PD = (*I)->getPropertyDecl();
- if (!PD)
- continue;
-
- // ivars cannot be set via read-only properties, so we'll skip them
- if (PD->isReadOnly())
- continue;
-
- // ivar must be released if and only if the kind of setter was not 'assign'
- bool requiresRelease = PD->getSetterKind() != ObjCPropertyDecl::Assign;
- if (scan_ivar_release(MD->getBody(), ID, PD, RS, SelfII, Ctx)
- != requiresRelease) {
- const char *name;
- const char* category = "Memory (Core Foundation/Objective-C)";
-
- std::string buf;
- llvm::raw_string_ostream os(buf);
-
- if (requiresRelease) {
- name = LOpts.getGCMode() == LangOptions::NonGC
- ? "missing ivar release (leak)"
- : "missing ivar release (Hybrid MM, non-GC)";
-
- os << "The '" << ID
- << "' instance variable was retained by a synthesized property but "
- "wasn't released in 'dealloc'";
- } else {
- name = LOpts.getGCMode() == LangOptions::NonGC
- ? "extra ivar release (use-after-release)"
- : "extra ivar release (Hybrid MM, non-GC)";
-
- os << "The '" << ID
- << "' instance variable was not retained by a synthesized property "
- "but was released in 'dealloc'";
- }
-
- BR.EmitBasicReport(name, category, os.str(), (*I)->getLocation());
- }
- }
-}
-
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/CheckObjCInstMethSignature.cpp b/clang/lib/StaticAnalyzer/EntoSA/Checkers/CheckObjCInstMethSignature.cpp
deleted file mode 100644
index 57e388f44de..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/CheckObjCInstMethSignature.cpp
+++ /dev/null
@@ -1,120 +0,0 @@
-//=- CheckObjCInstMethodRetTy.cpp - Check ObjC method signatures -*- C++ -*-==//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines a CheckObjCInstMethSignature, a flow-insenstive check
-// that determines if an Objective-C class interface incorrectly redefines
-// the method signature in a subclass.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
-#include "clang/StaticAnalyzer/BugReporter/PathDiagnostic.h"
-#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
-#include "clang/AST/DeclObjC.h"
-#include "clang/AST/Type.h"
-#include "clang/AST/ASTContext.h"
-
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/Support/raw_ostream.h"
-
-using namespace clang;
-using namespace ento;
-
-static bool AreTypesCompatible(QualType Derived, QualType Ancestor,
- ASTContext& C) {
-
- // Right now don't compare the compatibility of pointers. That involves
- // looking at subtyping relationships. FIXME: Future patch.
- if (Derived->isAnyPointerType() && Ancestor->isAnyPointerType())
- return true;
-
- return C.typesAreCompatible(Derived, Ancestor);
-}
-
-static void CompareReturnTypes(const ObjCMethodDecl *MethDerived,
- const ObjCMethodDecl *MethAncestor,
- BugReporter &BR, ASTContext &Ctx,
- const ObjCImplementationDecl *ID) {
-
- QualType ResDerived = MethDerived->getResultType();
- QualType ResAncestor = MethAncestor->getResultType();
-
- if (!AreTypesCompatible(ResDerived, ResAncestor, Ctx)) {
- std::string sbuf;
- llvm::raw_string_ostream os(sbuf);
-
- os << "The Objective-C class '"
- << MethDerived->getClassInterface()
- << "', which is derived from class '"
- << MethAncestor->getClassInterface()
- << "', defines the instance method '"
- << MethDerived->getSelector().getAsString()
- << "' whose return type is '"
- << ResDerived.getAsString()
- << "'. A method with the same name (same selector) is also defined in "
- "class '"
- << MethAncestor->getClassInterface()
- << "' and has a return type of '"
- << ResAncestor.getAsString()
- << "'. These two types are incompatible, and may result in undefined "
- "behavior for clients of these classes.";
-
- BR.EmitBasicReport("Incompatible instance method return type",
- os.str(), MethDerived->getLocStart());
- }
-}
-
-void ento::CheckObjCInstMethSignature(const ObjCImplementationDecl* ID,
- BugReporter& BR) {
-
- const ObjCInterfaceDecl* D = ID->getClassInterface();
- const ObjCInterfaceDecl* C = D->getSuperClass();
-
- if (!C)
- return;
-
- ASTContext& Ctx = BR.getContext();
-
- // Build a DenseMap of the methods for quick querying.
- typedef llvm::DenseMap<Selector,ObjCMethodDecl*> MapTy;
- MapTy IMeths;
- unsigned NumMethods = 0;
-
- for (ObjCImplementationDecl::instmeth_iterator I=ID->instmeth_begin(),
- E=ID->instmeth_end(); I!=E; ++I) {
-
- ObjCMethodDecl* M = *I;
- IMeths[M->getSelector()] = M;
- ++NumMethods;
- }
-
- // Now recurse the class hierarchy chain looking for methods with the
- // same signatures.
- while (C && NumMethods) {
- for (ObjCInterfaceDecl::instmeth_iterator I=C->instmeth_begin(),
- E=C->instmeth_end(); I!=E; ++I) {
-
- ObjCMethodDecl* M = *I;
- Selector S = M->getSelector();
-
- MapTy::iterator MI = IMeths.find(S);
-
- if (MI == IMeths.end() || MI->second == 0)
- continue;
-
- --NumMethods;
- ObjCMethodDecl* MethDerived = MI->second;
- MI->second = 0;
-
- CompareReturnTypes(MethDerived, M, BR, Ctx, ID);
- }
-
- C = C->getSuperClass();
- }
-}
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/CheckSecuritySyntaxOnly.cpp b/clang/lib/StaticAnalyzer/EntoSA/Checkers/CheckSecuritySyntaxOnly.cpp
deleted file mode 100644
index b30e985f38a..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/CheckSecuritySyntaxOnly.cpp
+++ /dev/null
@@ -1,503 +0,0 @@
-//==- CheckSecuritySyntaxOnly.cpp - Basic security checks --------*- C++ -*-==//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines a set of flow-insensitive security checks.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/Basic/TargetInfo.h"
-#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
-#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
-#include "clang/AST/StmtVisitor.h"
-#include "llvm/Support/raw_ostream.h"
-
-using namespace clang;
-using namespace ento;
-
-static bool isArc4RandomAvailable(const ASTContext &Ctx) {
- const llvm::Triple &T = Ctx.Target.getTriple();
- return T.getVendor() == llvm::Triple::Apple ||
- T.getOS() == llvm::Triple::FreeBSD;
-}
-
-namespace {
-class WalkAST : public StmtVisitor<WalkAST> {
- BugReporter &BR;
- IdentifierInfo *II_gets;
- IdentifierInfo *II_getpw;
- IdentifierInfo *II_mktemp;
- enum { num_rands = 9 };
- IdentifierInfo *II_rand[num_rands];
- IdentifierInfo *II_random;
- enum { num_setids = 6 };
- IdentifierInfo *II_setid[num_setids];
-
- const bool CheckRand;
-
-public:
- WalkAST(BugReporter &br) : BR(br),
- II_gets(0), II_getpw(0), II_mktemp(0),
- II_rand(), II_random(0), II_setid(),
- CheckRand(isArc4RandomAvailable(BR.getContext())) {}
-
- // Statement visitor methods.
- void VisitCallExpr(CallExpr *CE);
- void VisitForStmt(ForStmt *S);
- void VisitCompoundStmt (CompoundStmt *S);
- void VisitStmt(Stmt *S) { VisitChildren(S); }
-
- void VisitChildren(Stmt *S);
-
- // Helpers.
- IdentifierInfo *GetIdentifier(IdentifierInfo *& II, const char *str);
-
- // Checker-specific methods.
- void CheckLoopConditionForFloat(const ForStmt *FS);
- void CheckCall_gets(const CallExpr *CE, const FunctionDecl *FD);
- void CheckCall_getpw(const CallExpr *CE, const FunctionDecl *FD);
- void CheckCall_mktemp(const CallExpr *CE, const FunctionDecl *FD);
- void CheckCall_rand(const CallExpr *CE, const FunctionDecl *FD);
- void CheckCall_random(const CallExpr *CE, const FunctionDecl *FD);
- void CheckUncheckedReturnValue(CallExpr *CE);
-};
-} // end anonymous namespace
-
-//===----------------------------------------------------------------------===//
-// Helper methods.
-//===----------------------------------------------------------------------===//
-
-IdentifierInfo *WalkAST::GetIdentifier(IdentifierInfo *& II, const char *str) {
- if (!II)
- II = &BR.getContext().Idents.get(str);
-
- return II;
-}
-
-//===----------------------------------------------------------------------===//
-// AST walking.
-//===----------------------------------------------------------------------===//
-
-void WalkAST::VisitChildren(Stmt *S) {
- for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I)
- if (Stmt *child = *I)
- Visit(child);
-}
-
-void WalkAST::VisitCallExpr(CallExpr *CE) {
- if (const FunctionDecl *FD = CE->getDirectCallee()) {
- CheckCall_gets(CE, FD);
- CheckCall_getpw(CE, FD);
- CheckCall_mktemp(CE, FD);
- if (CheckRand) {
- CheckCall_rand(CE, FD);
- CheckCall_random(CE, FD);
- }
- }
-
- // Recurse and check children.
- VisitChildren(CE);
-}
-
-void WalkAST::VisitCompoundStmt(CompoundStmt *S) {
- for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I)
- if (Stmt *child = *I) {
- if (CallExpr *CE = dyn_cast<CallExpr>(child))
- CheckUncheckedReturnValue(CE);
- Visit(child);
- }
-}
-
-void WalkAST::VisitForStmt(ForStmt *FS) {
- CheckLoopConditionForFloat(FS);
-
- // Recurse and check children.
- VisitChildren(FS);
-}
-
-//===----------------------------------------------------------------------===//
-// Check: floating poing variable used as loop counter.
-// Originally: <rdar://problem/6336718>
-// Implements: CERT security coding advisory FLP-30.
-//===----------------------------------------------------------------------===//
-
-static const DeclRefExpr*
-GetIncrementedVar(const Expr *expr, const VarDecl *x, const VarDecl *y) {
- expr = expr->IgnoreParenCasts();
-
- if (const BinaryOperator *B = dyn_cast<BinaryOperator>(expr)) {
- if (!(B->isAssignmentOp() || B->isCompoundAssignmentOp() ||
- B->getOpcode() == BO_Comma))
- return NULL;
-
- if (const DeclRefExpr *lhs = GetIncrementedVar(B->getLHS(), x, y))
- return lhs;
-
- if (const DeclRefExpr *rhs = GetIncrementedVar(B->getRHS(), x, y))
- return rhs;
-
- return NULL;
- }
-
- if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(expr)) {
- const NamedDecl *ND = DR->getDecl();
- return ND == x || ND == y ? DR : NULL;
- }
-
- if (const UnaryOperator *U = dyn_cast<UnaryOperator>(expr))
- return U->isIncrementDecrementOp()
- ? GetIncrementedVar(U->getSubExpr(), x, y) : NULL;
-
- return NULL;
-}
-
-/// CheckLoopConditionForFloat - This check looks for 'for' statements that
-/// use a floating point variable as a loop counter.
-/// CERT: FLP30-C, FLP30-CPP.
-///
-void WalkAST::CheckLoopConditionForFloat(const ForStmt *FS) {
- // Does the loop have a condition?
- const Expr *condition = FS->getCond();
-
- if (!condition)
- return;
-
- // Does the loop have an increment?
- const Expr *increment = FS->getInc();
-
- if (!increment)
- return;
-
- // Strip away '()' and casts.
- condition = condition->IgnoreParenCasts();
- increment = increment->IgnoreParenCasts();
-
- // Is the loop condition a comparison?
- const BinaryOperator *B = dyn_cast<BinaryOperator>(condition);
-
- if (!B)
- return;
-
- // Is this a comparison?
- if (!(B->isRelationalOp() || B->isEqualityOp()))
- return;
-
- // Are we comparing variables?
- const DeclRefExpr *drLHS =
- dyn_cast<DeclRefExpr>(B->getLHS()->IgnoreParenLValueCasts());
- const DeclRefExpr *drRHS =
- dyn_cast<DeclRefExpr>(B->getRHS()->IgnoreParenLValueCasts());
-
- // Does at least one of the variables have a floating point type?
- drLHS = drLHS && drLHS->getType()->isRealFloatingType() ? drLHS : NULL;
- drRHS = drRHS && drRHS->getType()->isRealFloatingType() ? drRHS : NULL;
-
- if (!drLHS && !drRHS)
- return;
-
- const VarDecl *vdLHS = drLHS ? dyn_cast<VarDecl>(drLHS->getDecl()) : NULL;
- const VarDecl *vdRHS = drRHS ? dyn_cast<VarDecl>(drRHS->getDecl()) : NULL;
-
- if (!vdLHS && !vdRHS)
- return;
-
- // Does either variable appear in increment?
- const DeclRefExpr *drInc = GetIncrementedVar(increment, vdLHS, vdRHS);
-
- if (!drInc)
- return;
-
- // Emit the error. First figure out which DeclRefExpr in the condition
- // referenced the compared variable.
- const DeclRefExpr *drCond = vdLHS == drInc->getDecl() ? drLHS : drRHS;
-
- llvm::SmallVector<SourceRange, 2> ranges;
- llvm::SmallString<256> sbuf;
- llvm::raw_svector_ostream os(sbuf);
-
- os << "Variable '" << drCond->getDecl()->getName()
- << "' with floating point type '" << drCond->getType().getAsString()
- << "' should not be used as a loop counter";
-
- ranges.push_back(drCond->getSourceRange());
- ranges.push_back(drInc->getSourceRange());
-
- const char *bugType = "Floating point variable used as loop counter";
- BR.EmitBasicReport(bugType, "Security", os.str(),
- FS->getLocStart(), ranges.data(), ranges.size());
-}
-
-//===----------------------------------------------------------------------===//
-// Check: Any use of 'gets' is insecure.
-// Originally: <rdar://problem/6335715>
-// Implements (part of): 300-BSI (buildsecurityin.us-cert.gov)
-// CWE-242: Use of Inherently Dangerous Function
-//===----------------------------------------------------------------------===//
-
-void WalkAST::CheckCall_gets(const CallExpr *CE, const FunctionDecl *FD) {
- if (FD->getIdentifier() != GetIdentifier(II_gets, "gets"))
- return;
-
- const FunctionProtoType *FPT
- = dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens());
- if (!FPT)
- return;
-
- // Verify that the function takes a single argument.
- if (FPT->getNumArgs() != 1)
- return;
-
- // Is the argument a 'char*'?
- const PointerType *PT = dyn_cast<PointerType>(FPT->getArgType(0));
- if (!PT)
- return;
-
- if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
- return;
-
- // Issue a warning.
- SourceRange R = CE->getCallee()->getSourceRange();
- BR.EmitBasicReport("Potential buffer overflow in call to 'gets'",
- "Security",
- "Call to function 'gets' is extremely insecure as it can "
- "always result in a buffer overflow",
- CE->getLocStart(), &R, 1);
-}
-
-//===----------------------------------------------------------------------===//
-// Check: Any use of 'getpwd' is insecure.
-// CWE-477: Use of Obsolete Functions
-//===----------------------------------------------------------------------===//
-
-void WalkAST::CheckCall_getpw(const CallExpr *CE, const FunctionDecl *FD) {
- if (FD->getIdentifier() != GetIdentifier(II_getpw, "getpw"))
- return;
-
- const FunctionProtoType *FPT
- = dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens());
- if (!FPT)
- return;
-
- // Verify that the function takes two arguments.
- if (FPT->getNumArgs() != 2)
- return;
-
- // Verify the first argument type is integer.
- if (!FPT->getArgType(0)->isIntegerType())
- return;
-
- // Verify the second argument type is char*.
- const PointerType *PT = dyn_cast<PointerType>(FPT->getArgType(1));
- if (!PT)
- return;
-
- if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
- return;
-
- // Issue a warning.
- SourceRange R = CE->getCallee()->getSourceRange();
- BR.EmitBasicReport("Potential buffer overflow in call to 'getpw'",
- "Security",
- "The getpw() function is dangerous as it may overflow the "
- "provided buffer. It is obsoleted by getpwuid().",
- CE->getLocStart(), &R, 1);
-}
-
-//===----------------------------------------------------------------------===//
-// Check: Any use of 'mktemp' is insecure.It is obsoleted by mkstemp().
-// CWE-377: Insecure Temporary File
-//===----------------------------------------------------------------------===//
-
-void WalkAST::CheckCall_mktemp(const CallExpr *CE, const FunctionDecl *FD) {
- if (FD->getIdentifier() != GetIdentifier(II_mktemp, "mktemp"))
- return;
-
- const FunctionProtoType *FPT
- = dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens());
- if(!FPT)
- return;
-
- // Verify that the funcion takes a single argument.
- if (FPT->getNumArgs() != 1)
- return;
-
- // Verify that the argument is Pointer Type.
- const PointerType *PT = dyn_cast<PointerType>(FPT->getArgType(0));
- if (!PT)
- return;
-
- // Verify that the argument is a 'char*'.
- if (PT->getPointeeType().getUnqualifiedType() != BR.getContext().CharTy)
- return;
-
- // Issue a waring.
- SourceRange R = CE->getCallee()->getSourceRange();
- BR.EmitBasicReport("Potential insecure temporary file in call 'mktemp'",
- "Security",
- "Call to function 'mktemp' is insecure as it always "
- "creates or uses insecure temporary file. Use 'mkstemp' instead",
- CE->getLocStart(), &R, 1);
-}
-
-//===----------------------------------------------------------------------===//
-// Check: Linear congruent random number generators should not be used
-// Originally: <rdar://problem/63371000>
-// CWE-338: Use of cryptographically weak prng
-//===----------------------------------------------------------------------===//
-
-void WalkAST::CheckCall_rand(const CallExpr *CE, const FunctionDecl *FD) {
- if (II_rand[0] == NULL) {
- // This check applies to these functions
- static const char * const identifiers[num_rands] = {
- "drand48", "erand48", "jrand48", "lrand48", "mrand48", "nrand48",
- "lcong48",
- "rand", "rand_r"
- };
-
- for (size_t i = 0; i < num_rands; i++)
- II_rand[i] = &BR.getContext().Idents.get(identifiers[i]);
- }
-
- const IdentifierInfo *id = FD->getIdentifier();
- size_t identifierid;
-
- for (identifierid = 0; identifierid < num_rands; identifierid++)
- if (id == II_rand[identifierid])
- break;
-
- if (identifierid >= num_rands)
- return;
-
- const FunctionProtoType *FTP
- = dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens());
- if (!FTP)
- return;
-
- if (FTP->getNumArgs() == 1) {
- // Is the argument an 'unsigned short *'?
- // (Actually any integer type is allowed.)
- const PointerType *PT = dyn_cast<PointerType>(FTP->getArgType(0));
- if (!PT)
- return;
-
- if (! PT->getPointeeType()->isIntegerType())
- return;
- }
- else if (FTP->getNumArgs() != 0)
- return;
-
- // Issue a warning.
- llvm::SmallString<256> buf1;
- llvm::raw_svector_ostream os1(buf1);
- os1 << '\'' << FD << "' is a poor random number generator";
-
- llvm::SmallString<256> buf2;
- llvm::raw_svector_ostream os2(buf2);
- os2 << "Function '" << FD
- << "' is obsolete because it implements a poor random number generator."
- << " Use 'arc4random' instead";
-
- SourceRange R = CE->getCallee()->getSourceRange();
- BR.EmitBasicReport(os1.str(), "Security", os2.str(),CE->getLocStart(), &R, 1);
-}
-
-//===----------------------------------------------------------------------===//
-// Check: 'random' should not be used
-// Originally: <rdar://problem/63371000>
-//===----------------------------------------------------------------------===//
-
-void WalkAST::CheckCall_random(const CallExpr *CE, const FunctionDecl *FD) {
- if (FD->getIdentifier() != GetIdentifier(II_random, "random"))
- return;
-
- const FunctionProtoType *FTP
- = dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens());
- if (!FTP)
- return;
-
- // Verify that the function takes no argument.
- if (FTP->getNumArgs() != 0)
- return;
-
- // Issue a warning.
- SourceRange R = CE->getCallee()->getSourceRange();
- BR.EmitBasicReport("'random' is not a secure random number generator",
- "Security",
- "The 'random' function produces a sequence of values that "
- "an adversary may be able to predict. Use 'arc4random' "
- "instead", CE->getLocStart(), &R, 1);
-}
-
-//===----------------------------------------------------------------------===//
-// Check: Should check whether privileges are dropped successfully.
-// Originally: <rdar://problem/6337132>
-//===----------------------------------------------------------------------===//
-
-void WalkAST::CheckUncheckedReturnValue(CallExpr *CE) {
- const FunctionDecl *FD = CE->getDirectCallee();
- if (!FD)
- return;
-
- if (II_setid[0] == NULL) {
- static const char * const identifiers[num_setids] = {
- "setuid", "setgid", "seteuid", "setegid",
- "setreuid", "setregid"
- };
-
- for (size_t i = 0; i < num_setids; i++)
- II_setid[i] = &BR.getContext().Idents.get(identifiers[i]);
- }
-
- const IdentifierInfo *id = FD->getIdentifier();
- size_t identifierid;
-
- for (identifierid = 0; identifierid < num_setids; identifierid++)
- if (id == II_setid[identifierid])
- break;
-
- if (identifierid >= num_setids)
- return;
-
- const FunctionProtoType *FTP
- = dyn_cast<FunctionProtoType>(FD->getType().IgnoreParens());
- if (!FTP)
- return;
-
- // Verify that the function takes one or two arguments (depending on
- // the function).
- if (FTP->getNumArgs() != (identifierid < 4 ? 1 : 2))
- return;
-
- // The arguments must be integers.
- for (unsigned i = 0; i < FTP->getNumArgs(); i++)
- if (! FTP->getArgType(i)->isIntegerType())
- return;
-
- // Issue a warning.
- llvm::SmallString<256> buf1;
- llvm::raw_svector_ostream os1(buf1);
- os1 << "Return value is not checked in call to '" << FD << '\'';
-
- llvm::SmallString<256> buf2;
- llvm::raw_svector_ostream os2(buf2);
- os2 << "The return value from the call to '" << FD
- << "' is not checked. If an error occurs in '" << FD
- << "', the following code may execute with unexpected privileges";
-
- SourceRange R = CE->getCallee()->getSourceRange();
- BR.EmitBasicReport(os1.str(), "Security", os2.str(),CE->getLocStart(), &R, 1);
-}
-
-//===----------------------------------------------------------------------===//
-// Entry point for check.
-//===----------------------------------------------------------------------===//
-
-void ento::CheckSecuritySyntaxOnly(const Decl *D, BugReporter &BR) {
- WalkAST walker(BR);
- walker.Visit(D->getBody());
-}
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/CheckSizeofPointer.cpp b/clang/lib/StaticAnalyzer/EntoSA/Checkers/CheckSizeofPointer.cpp
deleted file mode 100644
index ed060b27fb4..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/CheckSizeofPointer.cpp
+++ /dev/null
@@ -1,72 +0,0 @@
-//==- CheckSizeofPointer.cpp - Check for sizeof on pointers ------*- C++ -*-==//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines a check for unintended use of sizeof() on pointer
-// expressions.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
-#include "clang/AST/StmtVisitor.h"
-#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
-
-using namespace clang;
-using namespace ento;
-
-namespace {
-class WalkAST : public StmtVisitor<WalkAST> {
- BugReporter &BR;
-
-public:
- WalkAST(BugReporter &br) : BR(br) {}
- void VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E);
- void VisitStmt(Stmt *S) { VisitChildren(S); }
- void VisitChildren(Stmt *S);
-};
-}
-
-void WalkAST::VisitChildren(Stmt *S) {
- for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I)
- if (Stmt *child = *I)
- Visit(child);
-}
-
-// CWE-467: Use of sizeof() on a Pointer Type
-void WalkAST::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *E) {
- if (!E->isSizeOf())
- return;
-
- // If an explicit type is used in the code, usually the coder knows what he is
- // doing.
- if (E->isArgumentType())
- return;
-
- QualType T = E->getTypeOfArgument();
- if (T->isPointerType()) {
-
- // Many false positives have the form 'sizeof *p'. This is reasonable
- // because people know what they are doing when they intentionally
- // dereference the pointer.
- Expr *ArgEx = E->getArgumentExpr();
- if (!isa<DeclRefExpr>(ArgEx->IgnoreParens()))
- return;
-
- SourceRange R = ArgEx->getSourceRange();
- BR.EmitBasicReport("Potential unintended use of sizeof() on pointer type",
- "Logic",
- "The code calls sizeof() on a pointer type. "
- "This can produce an unexpected result.",
- E->getLocStart(), &R, 1);
- }
-}
-
-void ento::CheckSizeofPointer(const Decl *D, BugReporter &BR) {
- WalkAST walker(BR);
- walker.Visit(D->getBody());
-}
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/ChrootChecker.cpp b/clang/lib/StaticAnalyzer/EntoSA/Checkers/ChrootChecker.cpp
deleted file mode 100644
index a3f4daa3b05..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/ChrootChecker.cpp
+++ /dev/null
@@ -1,162 +0,0 @@
-//===- Chrootchecker.cpp -------- Basic security checks ----------*- C++ -*-==//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines chroot checker, which checks improper use of chroot.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ExprEngineExperimentalChecks.h"
-#include "clang/StaticAnalyzer/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
-#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
-#include "clang/StaticAnalyzer/PathSensitive/GRStateTrait.h"
-#include "clang/StaticAnalyzer/PathSensitive/SymbolManager.h"
-#include "llvm/ADT/ImmutableMap.h"
-using namespace clang;
-using namespace ento;
-
-namespace {
-
-// enum value that represent the jail state
-enum Kind { NO_CHROOT, ROOT_CHANGED, JAIL_ENTERED };
-
-bool isRootChanged(intptr_t k) { return k == ROOT_CHANGED; }
-//bool isJailEntered(intptr_t k) { return k == JAIL_ENTERED; }
-
-// This checker checks improper use of chroot.
-// The state transition:
-// NO_CHROOT ---chroot(path)--> ROOT_CHANGED ---chdir(/) --> JAIL_ENTERED
-// | |
-// ROOT_CHANGED<--chdir(..)-- JAIL_ENTERED<--chdir(..)--
-// | |
-// bug<--foo()-- JAIL_ENTERED<--foo()--
-class ChrootChecker : public CheckerVisitor<ChrootChecker> {
- IdentifierInfo *II_chroot, *II_chdir;
- // This bug refers to possibly break out of a chroot() jail.
- BuiltinBug *BT_BreakJail;
-
-public:
- ChrootChecker() : II_chroot(0), II_chdir(0), BT_BreakJail(0) {}
-
- static void *getTag() {
- static int x;
- return &x;
- }
-
- virtual bool evalCallExpr(CheckerContext &C, const CallExpr *CE);
- virtual void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
-
-private:
- void Chroot(CheckerContext &C, const CallExpr *CE);
- void Chdir(CheckerContext &C, const CallExpr *CE);
-};
-
-} // end anonymous namespace
-
-void ento::RegisterChrootChecker(ExprEngine &Eng) {
- Eng.registerCheck(new ChrootChecker());
-}
-
-bool ChrootChecker::evalCallExpr(CheckerContext &C, const CallExpr *CE) {
- const GRState *state = C.getState();
- const Expr *Callee = CE->getCallee();
- SVal L = state->getSVal(Callee);
- const FunctionDecl *FD = L.getAsFunctionDecl();
- if (!FD)
- return false;
-
- ASTContext &Ctx = C.getASTContext();
- if (!II_chroot)
- II_chroot = &Ctx.Idents.get("chroot");
- if (!II_chdir)
- II_chdir = &Ctx.Idents.get("chdir");
-
- if (FD->getIdentifier() == II_chroot) {
- Chroot(C, CE);
- return true;
- }
- if (FD->getIdentifier() == II_chdir) {
- Chdir(C, CE);
- return true;
- }
-
- return false;
-}
-
-void ChrootChecker::Chroot(CheckerContext &C, const CallExpr *CE) {
- const GRState *state = C.getState();
- GRStateManager &Mgr = state->getStateManager();
-
- // Once encouter a chroot(), set the enum value ROOT_CHANGED directly in
- // the GDM.
- state = Mgr.addGDM(state, ChrootChecker::getTag(), (void*) ROOT_CHANGED);
- C.addTransition(state);
-}
-
-void ChrootChecker::Chdir(CheckerContext &C, const CallExpr *CE) {
- const GRState *state = C.getState();
- GRStateManager &Mgr = state->getStateManager();
-
- // If there are no jail state in the GDM, just return.
- const void* k = state->FindGDM(ChrootChecker::getTag());
- if (!k)
- return;
-
- // After chdir("/"), enter the jail, set the enum value JAIL_ENTERED.
- const Expr *ArgExpr = CE->getArg(0);
- SVal ArgVal = state->getSVal(ArgExpr);
-
- if (const MemRegion *R = ArgVal.getAsRegion()) {
- R = R->StripCasts();
- if (const StringRegion* StrRegion= dyn_cast<StringRegion>(R)) {
- const StringLiteral* Str = StrRegion->getStringLiteral();
- if (Str->getString() == "/")
- state = Mgr.addGDM(state, ChrootChecker::getTag(),
- (void*) JAIL_ENTERED);
- }
- }
-
- C.addTransition(state);
-}
-
-// Check the jail state before any function call except chroot and chdir().
-void ChrootChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
- const GRState *state = C.getState();
- const Expr *Callee = CE->getCallee();
- SVal L = state->getSVal(Callee);
- const FunctionDecl *FD = L.getAsFunctionDecl();
- if (!FD)
- return;
-
- ASTContext &Ctx = C.getASTContext();
- if (!II_chroot)
- II_chroot = &Ctx.Idents.get("chroot");
- if (!II_chdir)
- II_chdir = &Ctx.Idents.get("chdir");
-
- // Ingnore chroot and chdir.
- if (FD->getIdentifier() == II_chroot || FD->getIdentifier() == II_chdir)
- return;
-
- // If jail state is ROOT_CHANGED, generate BugReport.
- void* const* k = state->FindGDM(ChrootChecker::getTag());
- if (k)
- if (isRootChanged((intptr_t) *k))
- if (ExplodedNode *N = C.generateNode()) {
- if (!BT_BreakJail)
- BT_BreakJail = new BuiltinBug("Break out of jail",
- "No call of chdir(\"/\") immediately "
- "after chroot");
- BugReport *R = new BugReport(*BT_BreakJail,
- BT_BreakJail->getDescription(), N);
- C.EmitReport(R);
- }
-
- return;
-}
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/DereferenceChecker.cpp b/clang/lib/StaticAnalyzer/EntoSA/Checkers/DereferenceChecker.cpp
deleted file mode 100644
index 7dc8ec84dfe..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/DereferenceChecker.cpp
+++ /dev/null
@@ -1,204 +0,0 @@
-//== NullDerefChecker.cpp - Null dereference checker ------------*- C++ -*--==//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This defines NullDerefChecker, a builtin check in ExprEngine that performs
-// checks for null pointers at loads and stores.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ExprEngineInternalChecks.h"
-#include "clang/StaticAnalyzer/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Checkers/DereferenceChecker.h"
-#include "clang/StaticAnalyzer/PathSensitive/Checker.h"
-#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
-
-using namespace clang;
-using namespace ento;
-
-namespace {
-class DereferenceChecker : public Checker {
- BuiltinBug *BT_null;
- BuiltinBug *BT_undef;
- llvm::SmallVector<ExplodedNode*, 2> ImplicitNullDerefNodes;
-public:
- DereferenceChecker() : BT_null(0), BT_undef(0) {}
- static void *getTag() { static int tag = 0; return &tag; }
- void visitLocation(CheckerContext &C, const Stmt *S, SVal location);
-
- std::pair<ExplodedNode * const*, ExplodedNode * const*>
- getImplicitNodes() const {
- return std::make_pair(ImplicitNullDerefNodes.data(),
- ImplicitNullDerefNodes.data() +
- ImplicitNullDerefNodes.size());
- }
- void AddDerefSource(llvm::raw_ostream &os,
- llvm::SmallVectorImpl<SourceRange> &Ranges,
- const Expr *Ex, bool loadedFrom = false);
-};
-} // end anonymous namespace
-
-void ento::RegisterDereferenceChecker(ExprEngine &Eng) {
- Eng.registerCheck(new DereferenceChecker());
-}
-
-std::pair<ExplodedNode * const *, ExplodedNode * const *>
-ento::GetImplicitNullDereferences(ExprEngine &Eng) {
- DereferenceChecker *checker = Eng.getChecker<DereferenceChecker>();
- if (!checker)
- return std::make_pair((ExplodedNode * const *) 0,
- (ExplodedNode * const *) 0);
- return checker->getImplicitNodes();
-}
-
-void DereferenceChecker::AddDerefSource(llvm::raw_ostream &os,
- llvm::SmallVectorImpl<SourceRange> &Ranges,
- const Expr *Ex,
- bool loadedFrom) {
- Ex = Ex->IgnoreParenLValueCasts();
- switch (Ex->getStmtClass()) {
- default:
- return;
- case Stmt::DeclRefExprClass: {
- const DeclRefExpr *DR = cast<DeclRefExpr>(Ex);
- if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
- os << " (" << (loadedFrom ? "loaded from" : "from")
- << " variable '" << VD->getName() << "')";
- Ranges.push_back(DR->getSourceRange());
- }
- return;
- }
- case Stmt::MemberExprClass: {
- const MemberExpr *ME = cast<MemberExpr>(Ex);
- os << " (" << (loadedFrom ? "loaded from" : "via")
- << " field '" << ME->getMemberNameInfo() << "')";
- SourceLocation L = ME->getMemberLoc();
- Ranges.push_back(SourceRange(L, L));
- break;
- }
- }
-}
-
-void DereferenceChecker::visitLocation(CheckerContext &C, const Stmt *S,
- SVal l) {
- // Check for dereference of an undefined value.
- if (l.isUndef()) {
- if (ExplodedNode *N = C.generateSink()) {
- if (!BT_undef)
- BT_undef = new BuiltinBug("Dereference of undefined pointer value");
-
- EnhancedBugReport *report =
- new EnhancedBugReport(*BT_undef, BT_undef->getDescription(), N);
- report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
- bugreporter::GetDerefExpr(N));
- C.EmitReport(report);
- }
- return;
- }
-
- DefinedOrUnknownSVal location = cast<DefinedOrUnknownSVal>(l);
-
- // Check for null dereferences.
- if (!isa<Loc>(location))
- return;
-
- const GRState *state = C.getState();
- const GRState *notNullState, *nullState;
- llvm::tie(notNullState, nullState) = state->assume(location);
-
- // The explicit NULL case.
- if (nullState) {
- if (!notNullState) {
- // Generate an error node.
- ExplodedNode *N = C.generateSink(nullState);
- if (!N)
- return;
-
- // We know that 'location' cannot be non-null. This is what
- // we call an "explicit" null dereference.
- if (!BT_null)
- BT_null = new BuiltinBug("Dereference of null pointer");
-
- llvm::SmallString<100> buf;
- llvm::SmallVector<SourceRange, 2> Ranges;
-
- // Walk through lvalue casts to get the original expression
- // that syntactically caused the load.
- if (const Expr *expr = dyn_cast<Expr>(S))
- S = expr->IgnoreParenLValueCasts();
-
- switch (S->getStmtClass()) {
- case Stmt::ArraySubscriptExprClass: {
- llvm::raw_svector_ostream os(buf);
- os << "Array access";
- const ArraySubscriptExpr *AE = cast<ArraySubscriptExpr>(S);
- AddDerefSource(os, Ranges, AE->getBase()->IgnoreParenCasts());
- os << " results in a null pointer dereference";
- break;
- }
- case Stmt::UnaryOperatorClass: {
- llvm::raw_svector_ostream os(buf);
- os << "Dereference of null pointer";
- const UnaryOperator *U = cast<UnaryOperator>(S);
- AddDerefSource(os, Ranges, U->getSubExpr()->IgnoreParens(), true);
- break;
- }
- case Stmt::MemberExprClass: {
- const MemberExpr *M = cast<MemberExpr>(S);
- if (M->isArrow()) {
- llvm::raw_svector_ostream os(buf);
- os << "Access to field '" << M->getMemberNameInfo()
- << "' results in a dereference of a null pointer";
- AddDerefSource(os, Ranges, M->getBase()->IgnoreParenCasts(), true);
- }
- break;
- }
- case Stmt::ObjCIvarRefExprClass: {
- const ObjCIvarRefExpr *IV = cast<ObjCIvarRefExpr>(S);
- if (const DeclRefExpr *DR =
- dyn_cast<DeclRefExpr>(IV->getBase()->IgnoreParenCasts())) {
- if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
- llvm::raw_svector_ostream os(buf);
- os << "Instance variable access (via '" << VD->getName()
- << "') results in a null pointer dereference";
- }
- }
- Ranges.push_back(IV->getSourceRange());
- break;
- }
- default:
- break;
- }
-
- EnhancedBugReport *report =
- new EnhancedBugReport(*BT_null,
- buf.empty() ? BT_null->getDescription():buf.str(),
- N);
-
- report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
- bugreporter::GetDerefExpr(N));
-
- for (llvm::SmallVectorImpl<SourceRange>::iterator
- I = Ranges.begin(), E = Ranges.end(); I!=E; ++I)
- report->addRange(*I);
-
- C.EmitReport(report);
- return;
- }
- else {
- // Otherwise, we have the case where the location could either be
- // null or not-null. Record the error node as an "implicit" null
- // dereference.
- if (ExplodedNode *N = C.generateSink(nullState))
- ImplicitNullDerefNodes.push_back(N);
- }
- }
-
- // From this point forward, we know that the location is not null.
- C.addTransition(notNullState);
-}
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/DivZeroChecker.cpp b/clang/lib/StaticAnalyzer/EntoSA/Checkers/DivZeroChecker.cpp
deleted file mode 100644
index 8332af8f5d0..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/DivZeroChecker.cpp
+++ /dev/null
@@ -1,86 +0,0 @@
-//== DivZeroChecker.cpp - Division by zero checker --------------*- C++ -*--==//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This defines DivZeroChecker, a builtin check in ExprEngine that performs
-// checks for division by zeros.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ExprEngineInternalChecks.h"
-#include "clang/StaticAnalyzer/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
-
-using namespace clang;
-using namespace ento;
-
-namespace {
-class DivZeroChecker : public CheckerVisitor<DivZeroChecker> {
- BuiltinBug *BT;
-public:
- DivZeroChecker() : BT(0) {}
- static void *getTag();
- void PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B);
-};
-} // end anonymous namespace
-
-void ento::RegisterDivZeroChecker(ExprEngine &Eng) {
- Eng.registerCheck(new DivZeroChecker());
-}
-
-void *DivZeroChecker::getTag() {
- static int x;
- return &x;
-}
-
-void DivZeroChecker::PreVisitBinaryOperator(CheckerContext &C,
- const BinaryOperator *B) {
- BinaryOperator::Opcode Op = B->getOpcode();
- if (Op != BO_Div &&
- Op != BO_Rem &&
- Op != BO_DivAssign &&
- Op != BO_RemAssign)
- return;
-
- if (!B->getRHS()->getType()->isIntegerType() ||
- !B->getRHS()->getType()->isScalarType())
- return;
-
- SVal Denom = C.getState()->getSVal(B->getRHS());
- const DefinedSVal *DV = dyn_cast<DefinedSVal>(&Denom);
-
- // Divide-by-undefined handled in the generic checking for uses of
- // undefined values.
- if (!DV)
- return;
-
- // Check for divide by zero.
- ConstraintManager &CM = C.getConstraintManager();
- const GRState *stateNotZero, *stateZero;
- llvm::tie(stateNotZero, stateZero) = CM.assumeDual(C.getState(), *DV);
-
- if (stateZero && !stateNotZero) {
- if (ExplodedNode *N = C.generateSink(stateZero)) {
- if (!BT)
- BT = new BuiltinBug("Division by zero");
-
- EnhancedBugReport *R =
- new EnhancedBugReport(*BT, BT->getDescription(), N);
-
- R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
- bugreporter::GetDenomExpr(N));
-
- C.EmitReport(R);
- }
- return;
- }
-
- // If we get here, then the denom should not be zero. We abandon the implicit
- // zero denom case for now.
- C.addTransition(stateNotZero);
-}
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/ExprEngine.cpp b/clang/lib/StaticAnalyzer/EntoSA/Checkers/ExprEngine.cpp
deleted file mode 100644
index 17bc339f754..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/ExprEngine.cpp
+++ /dev/null
@@ -1,3513 +0,0 @@
-//=-- ExprEngine.cpp - Path-Sensitive Expression-Level Dataflow ---*- C++ -*-=
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines a meta-engine for path-sensitive dataflow analysis that
-// is built on GREngine, but provides the boilerplate to execute transfer
-// functions and build the ExplodedGraph at the expression level.
-//
-//===----------------------------------------------------------------------===//
-
-// FIXME: Restructure checker registration.
-#include "ExprEngineInternalChecks.h"
-
-#include "clang/StaticAnalyzer/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/PathSensitive/AnalysisManager.h"
-#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
-#include "clang/StaticAnalyzer/PathSensitive/ExprEngineBuilders.h"
-#include "clang/StaticAnalyzer/PathSensitive/Checker.h"
-#include "clang/AST/CharUnits.h"
-#include "clang/AST/ParentMap.h"
-#include "clang/AST/StmtObjC.h"
-#include "clang/AST/DeclCXX.h"
-#include "clang/Basic/Builtins.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/Basic/PrettyStackTrace.h"
-#include "llvm/Support/raw_ostream.h"
-#include "llvm/ADT/ImmutableList.h"
-
-#ifndef NDEBUG
-#include "llvm/Support/GraphWriter.h"
-#endif
-
-using namespace clang;
-using namespace ento;
-using llvm::dyn_cast;
-using llvm::dyn_cast_or_null;
-using llvm::cast;
-using llvm::APSInt;
-
-namespace {
- // Trait class for recording returned expression in the state.
- struct ReturnExpr {
- static int TagInt;
- typedef const Stmt *data_type;
- };
- int ReturnExpr::TagInt;
-}
-
-//===----------------------------------------------------------------------===//
-// Utility functions.
-//===----------------------------------------------------------------------===//
-
-static inline Selector GetNullarySelector(const char* name, ASTContext& Ctx) {
- IdentifierInfo* II = &Ctx.Idents.get(name);
- return Ctx.Selectors.getSelector(0, &II);
-}
-
-//===----------------------------------------------------------------------===//
-// Checker worklist routines.
-//===----------------------------------------------------------------------===//
-
-void ExprEngine::CheckerVisit(const Stmt *S, ExplodedNodeSet &Dst,
- ExplodedNodeSet &Src, CallbackKind Kind) {
-
- // Determine if we already have a cached 'CheckersOrdered' vector
- // specifically tailored for the provided <CallbackKind, Stmt kind>. This
- // can reduce the number of checkers actually called.
- CheckersOrdered *CO = &Checkers;
- llvm::OwningPtr<CheckersOrdered> NewCO;
-
- // The cache key is made up of the and the callback kind (pre- or post-visit)
- // and the statement kind.
- CallbackTag K = GetCallbackTag(Kind, S->getStmtClass());
-
- CheckersOrdered *& CO_Ref = COCache[K];
-
- if (!CO_Ref) {
- // If we have no previously cached CheckersOrdered vector for this
- // statement kind, then create one.
- NewCO.reset(new CheckersOrdered);
- }
- else {
- // Use the already cached set.
- CO = CO_Ref;
- }
-
- if (CO->empty()) {
- // If there are no checkers, return early without doing any
- // more work.
- Dst.insert(Src);
- return;
- }
-
- ExplodedNodeSet Tmp;
- ExplodedNodeSet *PrevSet = &Src;
- unsigned checkersEvaluated = 0;
-
- for (CheckersOrdered::iterator I=CO->begin(), E=CO->end(); I!=E; ++I) {
- // If all nodes are sunk, bail out early.
- if (PrevSet->empty())
- break;
- ExplodedNodeSet *CurrSet = 0;
- if (I+1 == E)
- CurrSet = &Dst;
- else {
- CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp;
- CurrSet->clear();
- }
- void *tag = I->first;
- Checker *checker = I->second;
- bool respondsToCallback = true;
-
- for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end();
- NI != NE; ++NI) {
-
- checker->GR_Visit(*CurrSet, *Builder, *this, S, *NI, tag,
- Kind == PreVisitStmtCallback, respondsToCallback);
-
- }
-
- PrevSet = CurrSet;
-
- if (NewCO.get()) {
- ++checkersEvaluated;
- if (respondsToCallback)
- NewCO->push_back(*I);
- }
- }
-
- // If we built NewCO, check if we called all the checkers. This is important
- // so that we know that we accurately determined the entire set of checkers
- // that responds to this callback. Note that 'checkersEvaluated' might
- // not be the same as Checkers.size() if one of the Checkers generates
- // a sink node.
- if (NewCO.get() && checkersEvaluated == Checkers.size())
- CO_Ref = NewCO.take();
-
- // Don't autotransition. The CheckerContext objects should do this
- // automatically.
-}
-
-void ExprEngine::CheckerEvalNilReceiver(const ObjCMessageExpr *ME,
- ExplodedNodeSet &Dst,
- const GRState *state,
- ExplodedNode *Pred) {
- bool evaluated = false;
- ExplodedNodeSet DstTmp;
-
- for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end();I!=E;++I) {
- void *tag = I->first;
- Checker *checker = I->second;
-
- if (checker->GR_evalNilReceiver(DstTmp, *Builder, *this, ME, Pred, state,
- tag)) {
- evaluated = true;
- break;
- } else
- // The checker didn't evaluate the expr. Restore the Dst.
- DstTmp.clear();
- }
-
- if (evaluated)
- Dst.insert(DstTmp);
- else
- Dst.insert(Pred);
-}
-
-// CheckerEvalCall returns true if one of the checkers processed the node.
-// This may return void when all call evaluation logic goes to some checker
-// in the future.
-bool ExprEngine::CheckerEvalCall(const CallExpr *CE,
- ExplodedNodeSet &Dst,
- ExplodedNode *Pred) {
- bool evaluated = false;
- ExplodedNodeSet DstTmp;
-
- for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end();I!=E;++I) {
- void *tag = I->first;
- Checker *checker = I->second;
-
- if (checker->GR_evalCallExpr(DstTmp, *Builder, *this, CE, Pred, tag)) {
- evaluated = true;
- break;
- } else
- // The checker didn't evaluate the expr. Restore the DstTmp set.
- DstTmp.clear();
- }
-
- if (evaluated)
- Dst.insert(DstTmp);
- else
- Dst.insert(Pred);
-
- return evaluated;
-}
-
-// FIXME: This is largely copy-paste from CheckerVisit(). Need to
-// unify.
-void ExprEngine::CheckerVisitBind(const Stmt *StoreE, ExplodedNodeSet &Dst,
- ExplodedNodeSet &Src, SVal location,
- SVal val, bool isPrevisit) {
-
- if (Checkers.empty()) {
- Dst.insert(Src);
- return;
- }
-
- ExplodedNodeSet Tmp;
- ExplodedNodeSet *PrevSet = &Src;
-
- for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I)
- {
- ExplodedNodeSet *CurrSet = 0;
- if (I+1 == E)
- CurrSet = &Dst;
- else {
- CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp;
- CurrSet->clear();
- }
-
- void *tag = I->first;
- Checker *checker = I->second;
-
- for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end();
- NI != NE; ++NI)
- checker->GR_VisitBind(*CurrSet, *Builder, *this, StoreE,
- *NI, tag, location, val, isPrevisit);
-
- // Update which NodeSet is the current one.
- PrevSet = CurrSet;
- }
-
- // Don't autotransition. The CheckerContext objects should do this
- // automatically.
-}
-//===----------------------------------------------------------------------===//
-// Engine construction and deletion.
-//===----------------------------------------------------------------------===//
-
-static void RegisterInternalChecks(ExprEngine &Eng) {
- // Register internal "built-in" BugTypes with the BugReporter. These BugTypes
- // are different than what probably many checks will do since they don't
- // create BugReports on-the-fly but instead wait until ExprEngine finishes
- // analyzing a function. Generation of BugReport objects is done via a call
- // to 'FlushReports' from BugReporter.
- // The following checks do not need to have their associated BugTypes
- // explicitly registered with the BugReporter. If they issue any BugReports,
- // their associated BugType will get registered with the BugReporter
- // automatically. Note that the check itself is owned by the ExprEngine
- // object.
- RegisterAdjustedReturnValueChecker(Eng);
- // CallAndMessageChecker should be registered before AttrNonNullChecker,
- // where we assume arguments are not undefined.
- RegisterCallAndMessageChecker(Eng);
- RegisterAttrNonNullChecker(Eng);
- RegisterDereferenceChecker(Eng);
- RegisterVLASizeChecker(Eng);
- RegisterDivZeroChecker(Eng);
- RegisterReturnUndefChecker(Eng);
- RegisterUndefinedArraySubscriptChecker(Eng);
- RegisterUndefinedAssignmentChecker(Eng);
- RegisterUndefBranchChecker(Eng);
- RegisterUndefCapturedBlockVarChecker(Eng);
- RegisterUndefResultChecker(Eng);
- RegisterStackAddrLeakChecker(Eng);
- RegisterObjCAtSyncChecker(Eng);
-
- // This is not a checker yet.
- RegisterNoReturnFunctionChecker(Eng);
- RegisterBuiltinFunctionChecker(Eng);
- RegisterOSAtomicChecker(Eng);
- RegisterUnixAPIChecker(Eng);
- RegisterMacOSXAPIChecker(Eng);
-}
-
-ExprEngine::ExprEngine(AnalysisManager &mgr, TransferFuncs *tf)
- : AMgr(mgr),
- Engine(*this),
- G(Engine.getGraph()),
- Builder(NULL),
- StateMgr(getContext(), mgr.getStoreManagerCreator(),
- mgr.getConstraintManagerCreator(), G.getAllocator(),
- *this),
- SymMgr(StateMgr.getSymbolManager()),
- svalBuilder(StateMgr.getSValBuilder()),
- EntryNode(NULL), currentStmt(NULL),
- NSExceptionII(NULL), NSExceptionInstanceRaiseSelectors(NULL),
- RaiseSel(GetNullarySelector("raise", getContext())),
- BR(mgr, *this), TF(tf) {
- // Register internal checks.
- RegisterInternalChecks(*this);
-
- // FIXME: Eventually remove the TF object entirely.
- TF->RegisterChecks(*this);
- TF->RegisterPrinters(getStateManager().Printers);
-}
-
-ExprEngine::~ExprEngine() {
- BR.FlushReports();
- delete [] NSExceptionInstanceRaiseSelectors;
-
- // Delete the set of checkers.
- for (CheckersOrdered::iterator I=Checkers.begin(), E=Checkers.end(); I!=E;++I)
- delete I->second;
-
- for (CheckersOrderedCache::iterator I=COCache.begin(), E=COCache.end();
- I!=E;++I)
- delete I->second;
-}
-
-//===----------------------------------------------------------------------===//
-// Utility methods.
-//===----------------------------------------------------------------------===//
-
-const GRState* ExprEngine::getInitialState(const LocationContext *InitLoc) {
- const GRState *state = StateMgr.getInitialState(InitLoc);
-
- // Preconditions.
-
- // FIXME: It would be nice if we had a more general mechanism to add
- // such preconditions. Some day.
- do {
- const Decl *D = InitLoc->getDecl();
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
- // Precondition: the first argument of 'main' is an integer guaranteed
- // to be > 0.
- const IdentifierInfo *II = FD->getIdentifier();
- if (!II || !(II->getName() == "main" && FD->getNumParams() > 0))
- break;
-
- const ParmVarDecl *PD = FD->getParamDecl(0);
- QualType T = PD->getType();
- if (!T->isIntegerType())
- break;
-
- const MemRegion *R = state->getRegion(PD, InitLoc);
- if (!R)
- break;
-
- SVal V = state->getSVal(loc::MemRegionVal(R));
- SVal Constraint_untested = evalBinOp(state, BO_GT, V,
- svalBuilder.makeZeroVal(T),
- getContext().IntTy);
-
- DefinedOrUnknownSVal *Constraint =
- dyn_cast<DefinedOrUnknownSVal>(&Constraint_untested);
-
- if (!Constraint)
- break;
-
- if (const GRState *newState = state->assume(*Constraint, true))
- state = newState;
-
- break;
- }
-
- if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
- // Precondition: 'self' is always non-null upon entry to an Objective-C
- // method.
- const ImplicitParamDecl *SelfD = MD->getSelfDecl();
- const MemRegion *R = state->getRegion(SelfD, InitLoc);
- SVal V = state->getSVal(loc::MemRegionVal(R));
-
- if (const Loc *LV = dyn_cast<Loc>(&V)) {
- // Assume that the pointer value in 'self' is non-null.
- state = state->assume(*LV, true);
- assert(state && "'self' cannot be null");
- }
- }
- } while (0);
-
- return state;
-}
-
-//===----------------------------------------------------------------------===//
-// Top-level transfer function logic (Dispatcher).
-//===----------------------------------------------------------------------===//
-
-/// evalAssume - Called by ConstraintManager. Used to call checker-specific
-/// logic for handling assumptions on symbolic values.
-const GRState *ExprEngine::ProcessAssume(const GRState *state, SVal cond,
- bool assumption) {
- // Determine if we already have a cached 'CheckersOrdered' vector
- // specifically tailored for processing assumptions. This
- // can reduce the number of checkers actually called.
- CheckersOrdered *CO = &Checkers;
- llvm::OwningPtr<CheckersOrdered> NewCO;
-
- CallbackTag K = GetCallbackTag(ProcessAssumeCallback);
- CheckersOrdered *& CO_Ref = COCache[K];
-
- if (!CO_Ref) {
- // If we have no previously cached CheckersOrdered vector for this
- // statement kind, then create one.
- NewCO.reset(new CheckersOrdered);
- }
- else {
- // Use the already cached set.
- CO = CO_Ref;
- }
-
- if (!CO->empty()) {
- // Let the checkers have a crack at the assume before the transfer functions
- // get their turn.
- for (CheckersOrdered::iterator I = CO->begin(), E = CO->end(); I!=E; ++I) {
-
- // If any checker declares the state infeasible (or if it starts that
- // way), bail out.
- if (!state)
- return NULL;
-
- Checker *C = I->second;
- bool respondsToCallback = true;
-
- state = C->evalAssume(state, cond, assumption, &respondsToCallback);
-
- // Check if we're building the cache of checkers that care about
- // assumptions.
- if (NewCO.get() && respondsToCallback)
- NewCO->push_back(*I);
- }
-
- // If we got through all the checkers, and we built a list of those that
- // care about assumptions, save it.
- if (NewCO.get())
- CO_Ref = NewCO.take();
- }
-
- // If the state is infeasible at this point, bail out.
- if (!state)
- return NULL;
-
- return TF->evalAssume(state, cond, assumption);
-}
-
-bool ExprEngine::WantsRegionChangeUpdate(const GRState* state) {
- CallbackTag K = GetCallbackTag(EvalRegionChangesCallback);
- CheckersOrdered *CO = COCache[K];
-
- if (!CO)
- CO = &Checkers;
-
- for (CheckersOrdered::iterator I = CO->begin(), E = CO->end(); I != E; ++I) {
- Checker *C = I->second;
- if (C->WantsRegionChangeUpdate(state))
- return true;
- }
-
- return false;
-}
-
-const GRState *
-ExprEngine::ProcessRegionChanges(const GRState *state,
- const MemRegion * const *Begin,
- const MemRegion * const *End) {
- // FIXME: Most of this method is copy-pasted from ProcessAssume.
-
- // Determine if we already have a cached 'CheckersOrdered' vector
- // specifically tailored for processing region changes. This
- // can reduce the number of checkers actually called.
- CheckersOrdered *CO = &Checkers;
- llvm::OwningPtr<CheckersOrdered> NewCO;
-
- CallbackTag K = GetCallbackTag(EvalRegionChangesCallback);
- CheckersOrdered *& CO_Ref = COCache[K];
-
- if (!CO_Ref) {
- // If we have no previously cached CheckersOrdered vector for this
- // callback, then create one.
- NewCO.reset(new CheckersOrdered);
- }
- else {
- // Use the already cached set.
- CO = CO_Ref;
- }
-
- // If there are no checkers, just return the state as is.
- if (CO->empty())
- return state;
-
- for (CheckersOrdered::iterator I = CO->begin(), E = CO->end(); I != E; ++I) {
- // If any checker declares the state infeasible (or if it starts that way),
- // bail out.
- if (!state)
- return NULL;
-
- Checker *C = I->second;
- bool respondsToCallback = true;
-
- state = C->EvalRegionChanges(state, Begin, End, &respondsToCallback);
-
- // See if we're building a cache of checkers that care about region changes.
- if (NewCO.get() && respondsToCallback)
- NewCO->push_back(*I);
- }
-
- // If we got through all the checkers, and we built a list of those that
- // care about region changes, save it.
- if (NewCO.get())
- CO_Ref = NewCO.take();
-
- return state;
-}
-
-void ExprEngine::ProcessEndWorklist(bool hasWorkRemaining) {
- for (CheckersOrdered::iterator I = Checkers.begin(), E = Checkers.end();
- I != E; ++I) {
- I->second->VisitEndAnalysis(G, BR, *this);
- }
-}
-
-void ExprEngine::ProcessElement(const CFGElement E,
- StmtNodeBuilder& builder) {
- switch (E.getKind()) {
- case CFGElement::Statement:
- ProcessStmt(E.getAs<CFGStmt>(), builder);
- break;
- case CFGElement::Initializer:
- ProcessInitializer(E.getAs<CFGInitializer>(), builder);
- break;
- case CFGElement::ImplicitDtor:
- ProcessImplicitDtor(E.getAs<CFGImplicitDtor>(), builder);
- break;
- default:
- // Suppress compiler warning.
- llvm_unreachable("Unexpected CFGElement kind.");
- }
-}
-
-void ExprEngine::ProcessStmt(const CFGStmt S, StmtNodeBuilder& builder) {
- currentStmt = S.getStmt();
- PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
- currentStmt->getLocStart(),
- "Error evaluating statement");
-
- Builder = &builder;
- EntryNode = builder.getBasePredecessor();
-
- // Create the cleaned state.
- const LocationContext *LC = EntryNode->getLocationContext();
- SymbolReaper SymReaper(LC, currentStmt, SymMgr);
-
- if (AMgr.shouldPurgeDead()) {
- const GRState *St = EntryNode->getState();
-
- for (CheckersOrdered::iterator I = Checkers.begin(), E = Checkers.end();
- I != E; ++I) {
- Checker *checker = I->second;
- checker->MarkLiveSymbols(St, SymReaper);
- }
-
- const StackFrameContext *SFC = LC->getCurrentStackFrame();
- CleanedState = StateMgr.RemoveDeadBindings(St, SFC, SymReaper);
- } else {
- CleanedState = EntryNode->getState();
- }
-
- // Process any special transfer function for dead symbols.
- ExplodedNodeSet Tmp;
-
- if (!SymReaper.hasDeadSymbols())
- Tmp.Add(EntryNode);
- else {
- SaveAndRestore<bool> OldSink(Builder->BuildSinks);
- SaveOr OldHasGen(Builder->HasGeneratedNode);
-
- SaveAndRestore<bool> OldPurgeDeadSymbols(Builder->PurgingDeadSymbols);
- Builder->PurgingDeadSymbols = true;
-
- // FIXME: This should soon be removed.
- ExplodedNodeSet Tmp2;
- getTF().evalDeadSymbols(Tmp2, *this, *Builder, EntryNode,
- CleanedState, SymReaper);
-
- if (Checkers.empty())
- Tmp.insert(Tmp2);
- else {
- ExplodedNodeSet Tmp3;
- ExplodedNodeSet *SrcSet = &Tmp2;
- for (CheckersOrdered::iterator I = Checkers.begin(), E = Checkers.end();
- I != E; ++I) {
- ExplodedNodeSet *DstSet = 0;
- if (I+1 == E)
- DstSet = &Tmp;
- else {
- DstSet = (SrcSet == &Tmp2) ? &Tmp3 : &Tmp2;
- DstSet->clear();
- }
-
- void *tag = I->first;
- Checker *checker = I->second;
- for (ExplodedNodeSet::iterator NI = SrcSet->begin(), NE = SrcSet->end();
- NI != NE; ++NI)
- checker->GR_evalDeadSymbols(*DstSet, *Builder, *this, currentStmt,
- *NI, SymReaper, tag);
- SrcSet = DstSet;
- }
- }
-
- if (!Builder->BuildSinks && !Builder->HasGeneratedNode)
- Tmp.Add(EntryNode);
- }
-
- bool HasAutoGenerated = false;
-
- for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
- ExplodedNodeSet Dst;
-
- // Set the cleaned state.
- Builder->SetCleanedState(*I == EntryNode ? CleanedState : GetState(*I));
-
- // Visit the statement.
- Visit(currentStmt, *I, Dst);
-
- // Do we need to auto-generate a node? We only need to do this to generate
- // a node with a "cleaned" state; CoreEngine will actually handle
- // auto-transitions for other cases.
- if (Dst.size() == 1 && *Dst.begin() == EntryNode
- && !Builder->HasGeneratedNode && !HasAutoGenerated) {
- HasAutoGenerated = true;
- builder.generateNode(currentStmt, GetState(EntryNode), *I);
- }
- }
-
- // NULL out these variables to cleanup.
- CleanedState = NULL;
- EntryNode = NULL;
-
- currentStmt = 0;
-
- Builder = NULL;
-}
-
-void ExprEngine::ProcessInitializer(const CFGInitializer Init,
- StmtNodeBuilder &builder) {
- // We don't set EntryNode and currentStmt. And we don't clean up state.
- const CXXBaseOrMemberInitializer *BMI = Init.getInitializer();
-
- ExplodedNode *Pred = builder.getBasePredecessor();
- const LocationContext *LC = Pred->getLocationContext();
-
- if (BMI->isAnyMemberInitializer()) {
- ExplodedNodeSet Dst;
-
- // Evaluate the initializer.
- Visit(BMI->getInit(), Pred, Dst);
-
- for (ExplodedNodeSet::iterator I = Dst.begin(), E = Dst.end(); I != E; ++I){
- ExplodedNode *Pred = *I;
- const GRState *state = Pred->getState();
-
- const FieldDecl *FD = BMI->getAnyMember();
- const RecordDecl *RD = FD->getParent();
- const CXXThisRegion *ThisR = getCXXThisRegion(cast<CXXRecordDecl>(RD),
- cast<StackFrameContext>(LC));
-
- SVal ThisV = state->getSVal(ThisR);
- SVal FieldLoc = state->getLValue(FD, ThisV);
- SVal InitVal = state->getSVal(BMI->getInit());
- state = state->bindLoc(FieldLoc, InitVal);
-
- // Use a custom node building process.
- PostInitializer PP(BMI, LC);
- // Builder automatically add the generated node to the deferred set,
- // which are processed in the builder's dtor.
- builder.generateNode(PP, state, Pred);
- }
- }
-}
-
-void ExprEngine::ProcessImplicitDtor(const CFGImplicitDtor D,
- StmtNodeBuilder &builder) {
- Builder = &builder;
-
- switch (D.getDtorKind()) {
- case CFGElement::AutomaticObjectDtor:
- ProcessAutomaticObjDtor(cast<CFGAutomaticObjDtor>(D), builder);
- break;
- case CFGElement::BaseDtor:
- ProcessBaseDtor(cast<CFGBaseDtor>(D), builder);
- break;
- case CFGElement::MemberDtor:
- ProcessMemberDtor(cast<CFGMemberDtor>(D), builder);
- break;
- case CFGElement::TemporaryDtor:
- ProcessTemporaryDtor(cast<CFGTemporaryDtor>(D), builder);
- break;
- default:
- llvm_unreachable("Unexpected dtor kind.");
- }
-}
-
-void ExprEngine::ProcessAutomaticObjDtor(const CFGAutomaticObjDtor dtor,
- StmtNodeBuilder &builder) {
- ExplodedNode *pred = builder.getBasePredecessor();
- const GRState *state = pred->getState();
- const VarDecl *varDecl = dtor.getVarDecl();
-
- QualType varType = varDecl->getType();
-
- if (const ReferenceType *refType = varType->getAs<ReferenceType>())
- varType = refType->getPointeeType();
-
- const CXXRecordDecl *recordDecl = varType->getAsCXXRecordDecl();
- assert(recordDecl && "get CXXRecordDecl fail");
- const CXXDestructorDecl *dtorDecl = recordDecl->getDestructor();
-
- Loc dest = state->getLValue(varDecl, pred->getLocationContext());
-
- ExplodedNodeSet dstSet;
- VisitCXXDestructor(dtorDecl, cast<loc::MemRegionVal>(dest).getRegion(),
- dtor.getTriggerStmt(), pred, dstSet);
-}
-
-void ExprEngine::ProcessBaseDtor(const CFGBaseDtor D,
- StmtNodeBuilder &builder) {
-}
-
-void ExprEngine::ProcessMemberDtor(const CFGMemberDtor D,
- StmtNodeBuilder &builder) {
-}
-
-void ExprEngine::ProcessTemporaryDtor(const CFGTemporaryDtor D,
- StmtNodeBuilder &builder) {
-}
-
-void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
- ExplodedNodeSet& Dst) {
- PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
- S->getLocStart(),
- "Error evaluating statement");
-
- // Expressions to ignore.
- if (const Expr *Ex = dyn_cast<Expr>(S))
- S = Ex->IgnoreParens();
-
- // FIXME: add metadata to the CFG so that we can disable
- // this check when we KNOW that there is no block-level subexpression.
- // The motivation is that this check requires a hashtable lookup.
-
- if (S != currentStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(S)) {
- Dst.Add(Pred);
- return;
- }
-
- switch (S->getStmtClass()) {
- // C++ stuff we don't support yet.
- case Stmt::CXXBindTemporaryExprClass:
- case Stmt::CXXCatchStmtClass:
- case Stmt::CXXDefaultArgExprClass:
- case Stmt::CXXDependentScopeMemberExprClass:
- case Stmt::ExprWithCleanupsClass:
- case Stmt::CXXNullPtrLiteralExprClass:
- case Stmt::CXXPseudoDestructorExprClass:
- case Stmt::CXXTemporaryObjectExprClass:
- case Stmt::CXXThrowExprClass:
- case Stmt::CXXTryStmtClass:
- case Stmt::CXXTypeidExprClass:
- case Stmt::CXXUuidofExprClass:
- case Stmt::CXXUnresolvedConstructExprClass:
- case Stmt::CXXScalarValueInitExprClass:
- case Stmt::DependentScopeDeclRefExprClass:
- case Stmt::UnaryTypeTraitExprClass:
- case Stmt::BinaryTypeTraitExprClass:
- case Stmt::UnresolvedLookupExprClass:
- case Stmt::UnresolvedMemberExprClass:
- case Stmt::CXXNoexceptExprClass:
- {
- SaveAndRestore<bool> OldSink(Builder->BuildSinks);
- Builder->BuildSinks = true;
- MakeNode(Dst, S, Pred, GetState(Pred));
- break;
- }
-
- case Stmt::ParenExprClass:
- llvm_unreachable("ParenExprs already handled.");
- // Cases that should never be evaluated simply because they shouldn't
- // appear in the CFG.
- case Stmt::BreakStmtClass:
- case Stmt::CaseStmtClass:
- case Stmt::CompoundStmtClass:
- case Stmt::ContinueStmtClass:
- case Stmt::DefaultStmtClass:
- case Stmt::DoStmtClass:
- case Stmt::GotoStmtClass:
- case Stmt::IndirectGotoStmtClass:
- case Stmt::LabelStmtClass:
- case Stmt::NoStmtClass:
- case Stmt::NullStmtClass:
- case Stmt::SwitchCaseClass:
- case Stmt::OpaqueValueExprClass:
- llvm_unreachable("Stmt should not be in analyzer evaluation loop");
- break;
-
- case Stmt::GNUNullExprClass: {
- MakeNode(Dst, S, Pred, GetState(Pred)->BindExpr(S, svalBuilder.makeNull()));
- break;
- }
-
- case Stmt::ObjCAtSynchronizedStmtClass:
- VisitObjCAtSynchronizedStmt(cast<ObjCAtSynchronizedStmt>(S), Pred, Dst);
- break;
-
- // Cases not handled yet; but will handle some day.
- case Stmt::DesignatedInitExprClass:
- case Stmt::ExtVectorElementExprClass:
- case Stmt::ImaginaryLiteralClass:
- case Stmt::ImplicitValueInitExprClass:
- case Stmt::ObjCAtCatchStmtClass:
- case Stmt::ObjCAtFinallyStmtClass:
- case Stmt::ObjCAtTryStmtClass:
- case Stmt::ObjCEncodeExprClass:
- case Stmt::ObjCIsaExprClass:
- case Stmt::ObjCPropertyRefExprClass:
- case Stmt::ObjCProtocolExprClass:
- case Stmt::ObjCSelectorExprClass:
- case Stmt::ObjCStringLiteralClass:
- case Stmt::ParenListExprClass:
- case Stmt::PredefinedExprClass:
- case Stmt::ShuffleVectorExprClass:
- case Stmt::VAArgExprClass:
- // Fall through.
-
- // Cases we intentionally don't evaluate, since they don't need
- // to be explicitly evaluated.
- case Stmt::AddrLabelExprClass:
- case Stmt::IntegerLiteralClass:
- case Stmt::CharacterLiteralClass:
- case Stmt::CXXBoolLiteralExprClass:
- case Stmt::FloatingLiteralClass:
- Dst.Add(Pred); // No-op. Simply propagate the current state unchanged.
- break;
-
- case Stmt::ArraySubscriptExprClass:
- VisitLvalArraySubscriptExpr(cast<ArraySubscriptExpr>(S), Pred, Dst);
- break;
-
- case Stmt::AsmStmtClass:
- VisitAsmStmt(cast<AsmStmt>(S), Pred, Dst);
- break;
-
- case Stmt::BlockDeclRefExprClass: {
- const BlockDeclRefExpr *BE = cast<BlockDeclRefExpr>(S);
- VisitCommonDeclRefExpr(BE, BE->getDecl(), Pred, Dst);
- break;
- }
-
- case Stmt::BlockExprClass:
- VisitBlockExpr(cast<BlockExpr>(S), Pred, Dst);
- break;
-
- case Stmt::BinaryOperatorClass: {
- const BinaryOperator* B = cast<BinaryOperator>(S);
- if (B->isLogicalOp()) {
- VisitLogicalExpr(B, Pred, Dst);
- break;
- }
- else if (B->getOpcode() == BO_Comma) {
- const GRState* state = GetState(Pred);
- MakeNode(Dst, B, Pred, state->BindExpr(B, state->getSVal(B->getRHS())));
- break;
- }
-
- if (AMgr.shouldEagerlyAssume() &&
- (B->isRelationalOp() || B->isEqualityOp())) {
- ExplodedNodeSet Tmp;
- VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Tmp);
- evalEagerlyAssume(Dst, Tmp, cast<Expr>(S));
- }
- else
- VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst);
-
- break;
- }
-
- case Stmt::CallExprClass: {
- const CallExpr* C = cast<CallExpr>(S);
- VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst);
- break;
- }
-
- case Stmt::CXXConstructExprClass: {
- const CXXConstructExpr *C = cast<CXXConstructExpr>(S);
- // For block-level CXXConstructExpr, we don't have a destination region.
- // Let VisitCXXConstructExpr() create one.
- VisitCXXConstructExpr(C, 0, Pred, Dst);
- break;
- }
-
- case Stmt::CXXMemberCallExprClass: {
- const CXXMemberCallExpr *MCE = cast<CXXMemberCallExpr>(S);
- VisitCXXMemberCallExpr(MCE, Pred, Dst);
- break;
- }
-
- case Stmt::CXXOperatorCallExprClass: {
- const CXXOperatorCallExpr *C = cast<CXXOperatorCallExpr>(S);
- VisitCXXOperatorCallExpr(C, Pred, Dst);
- break;
- }
-
- case Stmt::CXXNewExprClass: {
- const CXXNewExpr *NE = cast<CXXNewExpr>(S);
- VisitCXXNewExpr(NE, Pred, Dst);
- break;
- }
-
- case Stmt::CXXDeleteExprClass: {
- const CXXDeleteExpr *CDE = cast<CXXDeleteExpr>(S);
- VisitCXXDeleteExpr(CDE, Pred, Dst);
- break;
- }
- // FIXME: ChooseExpr is really a constant. We need to fix
- // the CFG do not model them as explicit control-flow.
-
- case Stmt::ChooseExprClass: { // __builtin_choose_expr
- const ChooseExpr* C = cast<ChooseExpr>(S);
- VisitGuardedExpr(C, C->getLHS(), C->getRHS(), Pred, Dst);
- break;
- }
-
- case Stmt::CompoundAssignOperatorClass:
- VisitBinaryOperator(cast<BinaryOperator>(S), Pred, Dst);
- break;
-
- case Stmt::CompoundLiteralExprClass:
- VisitCompoundLiteralExpr(cast<CompoundLiteralExpr>(S), Pred, Dst);
- break;
-
- case Stmt::ConditionalOperatorClass: { // '?' operator
- const ConditionalOperator* C = cast<ConditionalOperator>(S);
- VisitGuardedExpr(C, C->getLHS(), C->getRHS(), Pred, Dst);
- break;
- }
-
- case Stmt::CXXThisExprClass:
- VisitCXXThisExpr(cast<CXXThisExpr>(S), Pred, Dst);
- break;
-
- case Stmt::DeclRefExprClass: {
- const DeclRefExpr *DE = cast<DeclRefExpr>(S);
- VisitCommonDeclRefExpr(DE, DE->getDecl(), Pred, Dst);
- break;
- }
-
- case Stmt::DeclStmtClass:
- VisitDeclStmt(cast<DeclStmt>(S), Pred, Dst);
- break;
-
- case Stmt::ForStmtClass:
- // This case isn't for branch processing, but for handling the
- // initialization of a condition variable.
- VisitCondInit(cast<ForStmt>(S)->getConditionVariable(), S, Pred, Dst);
- break;
-
- case Stmt::ImplicitCastExprClass:
- case Stmt::CStyleCastExprClass:
- case Stmt::CXXStaticCastExprClass:
- case Stmt::CXXDynamicCastExprClass:
- case Stmt::CXXReinterpretCastExprClass:
- case Stmt::CXXConstCastExprClass:
- case Stmt::CXXFunctionalCastExprClass: {
- const CastExpr* C = cast<CastExpr>(S);
- VisitCast(C, C->getSubExpr(), Pred, Dst);
- break;
- }
-
- case Stmt::IfStmtClass:
- // This case isn't for branch processing, but for handling the
- // initialization of a condition variable.
- VisitCondInit(cast<IfStmt>(S)->getConditionVariable(), S, Pred, Dst);
- break;
-
- case Stmt::InitListExprClass:
- VisitInitListExpr(cast<InitListExpr>(S), Pred, Dst);
- break;
-
- case Stmt::MemberExprClass:
- VisitMemberExpr(cast<MemberExpr>(S), Pred, Dst);
- break;
- case Stmt::ObjCIvarRefExprClass:
- VisitLvalObjCIvarRefExpr(cast<ObjCIvarRefExpr>(S), Pred, Dst);
- break;
-
- case Stmt::ObjCForCollectionStmtClass:
- VisitObjCForCollectionStmt(cast<ObjCForCollectionStmt>(S), Pred, Dst);
- break;
-
- case Stmt::ObjCMessageExprClass:
- VisitObjCMessageExpr(cast<ObjCMessageExpr>(S), Pred, Dst);
- break;
-
- case Stmt::ObjCAtThrowStmtClass: {
- // FIXME: This is not complete. We basically treat @throw as
- // an abort.
- SaveAndRestore<bool> OldSink(Builder->BuildSinks);
- Builder->BuildSinks = true;
- MakeNode(Dst, S, Pred, GetState(Pred));
- break;
- }
-
- case Stmt::ReturnStmtClass:
- VisitReturnStmt(cast<ReturnStmt>(S), Pred, Dst);
- break;
-
- case Stmt::OffsetOfExprClass:
- VisitOffsetOfExpr(cast<OffsetOfExpr>(S), Pred, Dst);
- break;
-
- case Stmt::SizeOfAlignOfExprClass:
- VisitSizeOfAlignOfExpr(cast<SizeOfAlignOfExpr>(S), Pred, Dst);
- break;
-
- case Stmt::StmtExprClass: {
- const StmtExpr* SE = cast<StmtExpr>(S);
-
- if (SE->getSubStmt()->body_empty()) {
- // Empty statement expression.
- assert(SE->getType() == getContext().VoidTy
- && "Empty statement expression must have void type.");
- Dst.Add(Pred);
- break;
- }
-
- if (Expr* LastExpr = dyn_cast<Expr>(*SE->getSubStmt()->body_rbegin())) {
- const GRState* state = GetState(Pred);
- MakeNode(Dst, SE, Pred, state->BindExpr(SE, state->getSVal(LastExpr)));
- }
- else
- Dst.Add(Pred);
-
- break;
- }
-
- case Stmt::StringLiteralClass: {
- const GRState* state = GetState(Pred);
- SVal V = state->getLValue(cast<StringLiteral>(S));
- MakeNode(Dst, S, Pred, state->BindExpr(S, V));
- return;
- }
-
- case Stmt::SwitchStmtClass:
- // This case isn't for branch processing, but for handling the
- // initialization of a condition variable.
- VisitCondInit(cast<SwitchStmt>(S)->getConditionVariable(), S, Pred, Dst);
- break;
-
- case Stmt::UnaryOperatorClass: {
- const UnaryOperator *U = cast<UnaryOperator>(S);
- if (AMgr.shouldEagerlyAssume()&&(U->getOpcode() == UO_LNot)) {
- ExplodedNodeSet Tmp;
- VisitUnaryOperator(U, Pred, Tmp);
- evalEagerlyAssume(Dst, Tmp, U);
- }
- else
- VisitUnaryOperator(U, Pred, Dst);
- break;
- }
-
- case Stmt::WhileStmtClass:
- // This case isn't for branch processing, but for handling the
- // initialization of a condition variable.
- VisitCondInit(cast<WhileStmt>(S)->getConditionVariable(), S, Pred, Dst);
- break;
- }
-}
-
-//===----------------------------------------------------------------------===//
-// Block entrance. (Update counters).
-//===----------------------------------------------------------------------===//
-
-bool ExprEngine::ProcessBlockEntrance(const CFGBlock* B,
- const ExplodedNode *Pred,
- BlockCounter BC) {
- return BC.getNumVisited(Pred->getLocationContext()->getCurrentStackFrame(),
- B->getBlockID()) < AMgr.getMaxVisit();
-}
-
-//===----------------------------------------------------------------------===//
-// Generic node creation.
-//===----------------------------------------------------------------------===//
-
-ExplodedNode* ExprEngine::MakeNode(ExplodedNodeSet& Dst, const Stmt* S,
- ExplodedNode* Pred, const GRState* St,
- ProgramPoint::Kind K, const void *tag) {
- assert (Builder && "StmtNodeBuilder not present.");
- SaveAndRestore<const void*> OldTag(Builder->Tag);
- Builder->Tag = tag;
- return Builder->MakeNode(Dst, S, Pred, St, K);
-}
-
-//===----------------------------------------------------------------------===//
-// Branch processing.
-//===----------------------------------------------------------------------===//
-
-const GRState* ExprEngine::MarkBranch(const GRState* state,
- const Stmt* Terminator,
- bool branchTaken) {
-
- switch (Terminator->getStmtClass()) {
- default:
- return state;
-
- case Stmt::BinaryOperatorClass: { // '&&' and '||'
-
- const BinaryOperator* B = cast<BinaryOperator>(Terminator);
- BinaryOperator::Opcode Op = B->getOpcode();
-
- assert (Op == BO_LAnd || Op == BO_LOr);
-
- // For &&, if we take the true branch, then the value of the whole
- // expression is that of the RHS expression.
- //
- // For ||, if we take the false branch, then the value of the whole
- // expression is that of the RHS expression.
-
- const Expr* Ex = (Op == BO_LAnd && branchTaken) ||
- (Op == BO_LOr && !branchTaken)
- ? B->getRHS() : B->getLHS();
-
- return state->BindExpr(B, UndefinedVal(Ex));
- }
-
- case Stmt::ConditionalOperatorClass: { // ?:
-
- const ConditionalOperator* C = cast<ConditionalOperator>(Terminator);
-
- // For ?, if branchTaken == true then the value is either the LHS or
- // the condition itself. (GNU extension).
-
- const Expr* Ex;
-
- if (branchTaken)
- Ex = C->getLHS() ? C->getLHS() : C->getCond();
- else
- Ex = C->getRHS();
-
- return state->BindExpr(C, UndefinedVal(Ex));
- }
-
- case Stmt::ChooseExprClass: { // ?:
-
- const ChooseExpr* C = cast<ChooseExpr>(Terminator);
-
- const Expr* Ex = branchTaken ? C->getLHS() : C->getRHS();
- return state->BindExpr(C, UndefinedVal(Ex));
- }
- }
-}
-
-/// RecoverCastedSymbol - A helper function for ProcessBranch that is used
-/// to try to recover some path-sensitivity for casts of symbolic
-/// integers that promote their values (which are currently not tracked well).
-/// This function returns the SVal bound to Condition->IgnoreCasts if all the
-// cast(s) did was sign-extend the original value.
-static SVal RecoverCastedSymbol(GRStateManager& StateMgr, const GRState* state,
- const Stmt* Condition, ASTContext& Ctx) {
-
- const Expr *Ex = dyn_cast<Expr>(Condition);
- if (!Ex)
- return UnknownVal();
-
- uint64_t bits = 0;
- bool bitsInit = false;
-
- while (const CastExpr *CE = dyn_cast<CastExpr>(Ex)) {
- QualType T = CE->getType();
-
- if (!T->isIntegerType())
- return UnknownVal();
-
- uint64_t newBits = Ctx.getTypeSize(T);
- if (!bitsInit || newBits < bits) {
- bitsInit = true;
- bits = newBits;
- }
-
- Ex = CE->getSubExpr();
- }
-
- // We reached a non-cast. Is it a symbolic value?
- QualType T = Ex->getType();
-
- if (!bitsInit || !T->isIntegerType() || Ctx.getTypeSize(T) > bits)
- return UnknownVal();
-
- return state->getSVal(Ex);
-}
-
-void ExprEngine::ProcessBranch(const Stmt* Condition, const Stmt* Term,
- BranchNodeBuilder& builder) {
-
- // Check for NULL conditions; e.g. "for(;;)"
- if (!Condition) {
- builder.markInfeasible(false);
- return;
- }
-
- PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
- Condition->getLocStart(),
- "Error evaluating branch");
-
- for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end();I!=E;++I) {
- void *tag = I->first;
- Checker *checker = I->second;
- checker->VisitBranchCondition(builder, *this, Condition, tag);
- }
-
- // If the branch condition is undefined, return;
- if (!builder.isFeasible(true) && !builder.isFeasible(false))
- return;
-
- const GRState* PrevState = builder.getState();
- SVal X = PrevState->getSVal(Condition);
-
- if (X.isUnknown()) {
- // Give it a chance to recover from unknown.
- if (const Expr *Ex = dyn_cast<Expr>(Condition)) {
- if (Ex->getType()->isIntegerType()) {
- // Try to recover some path-sensitivity. Right now casts of symbolic
- // integers that promote their values are currently not tracked well.
- // If 'Condition' is such an expression, try and recover the
- // underlying value and use that instead.
- SVal recovered = RecoverCastedSymbol(getStateManager(),
- builder.getState(), Condition,
- getContext());
-
- if (!recovered.isUnknown()) {
- X = recovered;
- }
- }
- }
- // If the condition is still unknown, give up.
- if (X.isUnknown()) {
- builder.generateNode(MarkBranch(PrevState, Term, true), true);
- builder.generateNode(MarkBranch(PrevState, Term, false), false);
- return;
- }
- }
-
- DefinedSVal V = cast<DefinedSVal>(X);
-
- // Process the true branch.
- if (builder.isFeasible(true)) {
- if (const GRState *state = PrevState->assume(V, true))
- builder.generateNode(MarkBranch(state, Term, true), true);
- else
- builder.markInfeasible(true);
- }
-
- // Process the false branch.
- if (builder.isFeasible(false)) {
- if (const GRState *state = PrevState->assume(V, false))
- builder.generateNode(MarkBranch(state, Term, false), false);
- else
- builder.markInfeasible(false);
- }
-}
-
-/// ProcessIndirectGoto - Called by CoreEngine. Used to generate successor
-/// nodes by processing the 'effects' of a computed goto jump.
-void ExprEngine::ProcessIndirectGoto(IndirectGotoNodeBuilder& builder) {
-
- const GRState *state = builder.getState();
- SVal V = state->getSVal(builder.getTarget());
-
- // Three possibilities:
- //
- // (1) We know the computed label.
- // (2) The label is NULL (or some other constant), or Undefined.
- // (3) We have no clue about the label. Dispatch to all targets.
- //
-
- typedef IndirectGotoNodeBuilder::iterator iterator;
-
- if (isa<loc::GotoLabel>(V)) {
- const LabelStmt* L = cast<loc::GotoLabel>(V).getLabel();
-
- for (iterator I=builder.begin(), E=builder.end(); I != E; ++I) {
- if (I.getLabel() == L) {
- builder.generateNode(I, state);
- return;
- }
- }
-
- assert (false && "No block with label.");
- return;
- }
-
- if (isa<loc::ConcreteInt>(V) || isa<UndefinedVal>(V)) {
- // Dispatch to the first target and mark it as a sink.
- //ExplodedNode* N = builder.generateNode(builder.begin(), state, true);
- // FIXME: add checker visit.
- // UndefBranches.insert(N);
- return;
- }
-
- // This is really a catch-all. We don't support symbolics yet.
- // FIXME: Implement dispatch for symbolic pointers.
-
- for (iterator I=builder.begin(), E=builder.end(); I != E; ++I)
- builder.generateNode(I, state);
-}
-
-
-void ExprEngine::VisitGuardedExpr(const Expr* Ex, const Expr* L,
- const Expr* R,
- ExplodedNode* Pred, ExplodedNodeSet& Dst) {
-
- assert(Ex == currentStmt &&
- Pred->getLocationContext()->getCFG()->isBlkExpr(Ex));
-
- const GRState* state = GetState(Pred);
- SVal X = state->getSVal(Ex);
-
- assert (X.isUndef());
-
- const Expr *SE = (Expr*) cast<UndefinedVal>(X).getData();
- assert(SE);
- X = state->getSVal(SE);
-
- // Make sure that we invalidate the previous binding.
- MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, X, true));
-}
-
-/// ProcessEndPath - Called by CoreEngine. Used to generate end-of-path
-/// nodes when the control reaches the end of a function.
-void ExprEngine::ProcessEndPath(EndPathNodeBuilder& builder) {
- getTF().evalEndPath(*this, builder);
- StateMgr.EndPath(builder.getState());
- for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E;++I){
- void *tag = I->first;
- Checker *checker = I->second;
- checker->evalEndPath(builder, tag, *this);
- }
-}
-
-/// ProcessSwitch - Called by CoreEngine. Used to generate successor
-/// nodes by processing the 'effects' of a switch statement.
-void ExprEngine::ProcessSwitch(SwitchNodeBuilder& builder) {
- typedef SwitchNodeBuilder::iterator iterator;
- const GRState* state = builder.getState();
- const Expr* CondE = builder.getCondition();
- SVal CondV_untested = state->getSVal(CondE);
-
- if (CondV_untested.isUndef()) {
- //ExplodedNode* N = builder.generateDefaultCaseNode(state, true);
- // FIXME: add checker
- //UndefBranches.insert(N);
-
- return;
- }
- DefinedOrUnknownSVal CondV = cast<DefinedOrUnknownSVal>(CondV_untested);
-
- const GRState *DefaultSt = state;
-
- iterator I = builder.begin(), EI = builder.end();
- bool defaultIsFeasible = I == EI;
-
- for ( ; I != EI; ++I) {
- const CaseStmt* Case = I.getCase();
-
- // Evaluate the LHS of the case value.
- Expr::EvalResult V1;
- bool b = Case->getLHS()->Evaluate(V1, getContext());
-
- // Sanity checks. These go away in Release builds.
- assert(b && V1.Val.isInt() && !V1.HasSideEffects
- && "Case condition must evaluate to an integer constant.");
- (void)b; // silence unused variable warning
- assert(V1.Val.getInt().getBitWidth() ==
- getContext().getTypeSize(CondE->getType()));
-
- // Get the RHS of the case, if it exists.
- Expr::EvalResult V2;
-
- if (const Expr* E = Case->getRHS()) {
- b = E->Evaluate(V2, getContext());
- assert(b && V2.Val.isInt() && !V2.HasSideEffects
- && "Case condition must evaluate to an integer constant.");
- (void)b; // silence unused variable warning
- }
- else
- V2 = V1;
-
- // FIXME: Eventually we should replace the logic below with a range
- // comparison, rather than concretize the values within the range.
- // This should be easy once we have "ranges" for NonLVals.
-
- do {
- nonloc::ConcreteInt CaseVal(getBasicVals().getValue(V1.Val.getInt()));
- DefinedOrUnknownSVal Res = svalBuilder.evalEQ(DefaultSt ? DefaultSt : state,
- CondV, CaseVal);
-
- // Now "assume" that the case matches.
- if (const GRState* stateNew = state->assume(Res, true)) {
- builder.generateCaseStmtNode(I, stateNew);
-
- // If CondV evaluates to a constant, then we know that this
- // is the *only* case that we can take, so stop evaluating the
- // others.
- if (isa<nonloc::ConcreteInt>(CondV))
- return;
- }
-
- // Now "assume" that the case doesn't match. Add this state
- // to the default state (if it is feasible).
- if (DefaultSt) {
- if (const GRState *stateNew = DefaultSt->assume(Res, false)) {
- defaultIsFeasible = true;
- DefaultSt = stateNew;
- }
- else {
- defaultIsFeasible = false;
- DefaultSt = NULL;
- }
- }
-
- // Concretize the next value in the range.
- if (V1.Val.getInt() == V2.Val.getInt())
- break;
-
- ++V1.Val.getInt();
- assert (V1.Val.getInt() <= V2.Val.getInt());
-
- } while (true);
- }
-
- if (!defaultIsFeasible)
- return;
-
- // If we have switch(enum value), the default branch is not
- // feasible if all of the enum constants not covered by 'case:' statements
- // are not feasible values for the switch condition.
- //
- // Note that this isn't as accurate as it could be. Even if there isn't
- // a case for a particular enum value as long as that enum value isn't
- // feasible then it shouldn't be considered for making 'default:' reachable.
- const SwitchStmt *SS = builder.getSwitch();
- const Expr *CondExpr = SS->getCond()->IgnoreParenImpCasts();
- if (CondExpr->getType()->getAs<EnumType>()) {
- if (SS->isAllEnumCasesCovered())
- return;
- }
-
- builder.generateDefaultCaseNode(DefaultSt);
-}
-
-void ExprEngine::ProcessCallEnter(CallEnterNodeBuilder &B) {
- const GRState *state = B.getState()->EnterStackFrame(B.getCalleeContext());
- B.generateNode(state);
-}
-
-void ExprEngine::ProcessCallExit(CallExitNodeBuilder &B) {
- const GRState *state = B.getState();
- const ExplodedNode *Pred = B.getPredecessor();
- const StackFrameContext *calleeCtx =
- cast<StackFrameContext>(Pred->getLocationContext());
- const Stmt *CE = calleeCtx->getCallSite();
-
- // If the callee returns an expression, bind its value to CallExpr.
- const Stmt *ReturnedExpr = state->get<ReturnExpr>();
- if (ReturnedExpr) {
- SVal RetVal = state->getSVal(ReturnedExpr);
- state = state->BindExpr(CE, RetVal);
- // Clear the return expr GDM.
- state = state->remove<ReturnExpr>();
- }
-
- // Bind the constructed object value to CXXConstructExpr.
- if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(CE)) {
- const CXXThisRegion *ThisR =
- getCXXThisRegion(CCE->getConstructor()->getParent(), calleeCtx);
-
- SVal ThisV = state->getSVal(ThisR);
- // Always bind the region to the CXXConstructExpr.
- state = state->BindExpr(CCE, ThisV);
- }
-
- B.generateNode(state);
-}
-
-//===----------------------------------------------------------------------===//
-// Transfer functions: logical operations ('&&', '||').
-//===----------------------------------------------------------------------===//
-
-void ExprEngine::VisitLogicalExpr(const BinaryOperator* B, ExplodedNode* Pred,
- ExplodedNodeSet& Dst) {
-
- assert(B->getOpcode() == BO_LAnd ||
- B->getOpcode() == BO_LOr);
-
- assert(B==currentStmt && Pred->getLocationContext()->getCFG()->isBlkExpr(B));
-
- const GRState* state = GetState(Pred);
- SVal X = state->getSVal(B);
- assert(X.isUndef());
-
- const Expr *Ex = (const Expr*) cast<UndefinedVal>(X).getData();
- assert(Ex);
-
- if (Ex == B->getRHS()) {
- X = state->getSVal(Ex);
-
- // Handle undefined values.
- if (X.isUndef()) {
- MakeNode(Dst, B, Pred, state->BindExpr(B, X));
- return;
- }
-
- DefinedOrUnknownSVal XD = cast<DefinedOrUnknownSVal>(X);
-
- // We took the RHS. Because the value of the '&&' or '||' expression must
- // evaluate to 0 or 1, we must assume the value of the RHS evaluates to 0
- // or 1. Alternatively, we could take a lazy approach, and calculate this
- // value later when necessary. We don't have the machinery in place for
- // this right now, and since most logical expressions are used for branches,
- // the payoff is not likely to be large. Instead, we do eager evaluation.
- if (const GRState *newState = state->assume(XD, true))
- MakeNode(Dst, B, Pred,
- newState->BindExpr(B, svalBuilder.makeIntVal(1U, B->getType())));
-
- if (const GRState *newState = state->assume(XD, false))
- MakeNode(Dst, B, Pred,
- newState->BindExpr(B, svalBuilder.makeIntVal(0U, B->getType())));
- }
- else {
- // We took the LHS expression. Depending on whether we are '&&' or
- // '||' we know what the value of the expression is via properties of
- // the short-circuiting.
- X = svalBuilder.makeIntVal(B->getOpcode() == BO_LAnd ? 0U : 1U,
- B->getType());
- MakeNode(Dst, B, Pred, state->BindExpr(B, X));
- }
-}
-
-//===----------------------------------------------------------------------===//
-// Transfer functions: Loads and stores.
-//===----------------------------------------------------------------------===//
-
-void ExprEngine::VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred,
- ExplodedNodeSet &Dst) {
-
- ExplodedNodeSet Tmp;
-
- CanQualType T = getContext().getCanonicalType(BE->getType());
- SVal V = svalBuilder.getBlockPointer(BE->getBlockDecl(), T,
- Pred->getLocationContext());
-
- MakeNode(Tmp, BE, Pred, GetState(Pred)->BindExpr(BE, V),
- ProgramPoint::PostLValueKind);
-
- // Post-visit the BlockExpr.
- CheckerVisit(BE, Dst, Tmp, PostVisitStmtCallback);
-}
-
-void ExprEngine::VisitCommonDeclRefExpr(const Expr *Ex, const NamedDecl *D,
- ExplodedNode *Pred,
- ExplodedNodeSet &Dst) {
- const GRState *state = GetState(Pred);
-
- if (const VarDecl* VD = dyn_cast<VarDecl>(D)) {
- assert(Ex->isLValue());
- SVal V = state->getLValue(VD, Pred->getLocationContext());
-
- // For references, the 'lvalue' is the pointer address stored in the
- // reference region.
- if (VD->getType()->isReferenceType()) {
- if (const MemRegion *R = V.getAsRegion())
- V = state->getSVal(R);
- else
- V = UnknownVal();
- }
-
- MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V),
- ProgramPoint::PostLValueKind);
- return;
- }
- if (const EnumConstantDecl* ED = dyn_cast<EnumConstantDecl>(D)) {
- assert(!Ex->isLValue());
- SVal V = svalBuilder.makeIntVal(ED->getInitVal());
- MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V));
- return;
- }
- if (const FunctionDecl* FD = dyn_cast<FunctionDecl>(D)) {
- SVal V = svalBuilder.getFunctionPointer(FD);
- MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V),
- ProgramPoint::PostLValueKind);
- return;
- }
- assert (false &&
- "ValueDecl support for this ValueDecl not implemented.");
-}
-
-/// VisitArraySubscriptExpr - Transfer function for array accesses
-void ExprEngine::VisitLvalArraySubscriptExpr(const ArraySubscriptExpr* A,
- ExplodedNode* Pred,
- ExplodedNodeSet& Dst){
-
- const Expr* Base = A->getBase()->IgnoreParens();
- const Expr* Idx = A->getIdx()->IgnoreParens();
-
- // Evaluate the base.
- ExplodedNodeSet Tmp;
- Visit(Base, Pred, Tmp);
-
- for (ExplodedNodeSet::iterator I1=Tmp.begin(), E1=Tmp.end(); I1!=E1; ++I1) {
- ExplodedNodeSet Tmp2;
- Visit(Idx, *I1, Tmp2); // Evaluate the index.
- ExplodedNodeSet Tmp3;
- CheckerVisit(A, Tmp3, Tmp2, PreVisitStmtCallback);
-
- for (ExplodedNodeSet::iterator I2=Tmp3.begin(),E2=Tmp3.end();I2!=E2; ++I2) {
- const GRState* state = GetState(*I2);
- SVal V = state->getLValue(A->getType(), state->getSVal(Idx),
- state->getSVal(Base));
- assert(A->isLValue());
- MakeNode(Dst, A, *I2, state->BindExpr(A, V), ProgramPoint::PostLValueKind);
- }
- }
-}
-
-/// VisitMemberExpr - Transfer function for member expressions.
-void ExprEngine::VisitMemberExpr(const MemberExpr* M, ExplodedNode* Pred,
- ExplodedNodeSet& Dst) {
-
- Expr *baseExpr = M->getBase()->IgnoreParens();
- ExplodedNodeSet dstBase;
- Visit(baseExpr, Pred, dstBase);
-
- FieldDecl *field = dyn_cast<FieldDecl>(M->getMemberDecl());
- if (!field) // FIXME: skipping member expressions for non-fields
- return;
-
- for (ExplodedNodeSet::iterator I = dstBase.begin(), E = dstBase.end();
- I != E; ++I) {
- const GRState* state = GetState(*I);
- SVal baseExprVal = state->getSVal(baseExpr);
- if (isa<nonloc::LazyCompoundVal>(baseExprVal) ||
- isa<nonloc::CompoundVal>(baseExprVal)) {
- MakeNode(Dst, M, *I, state->BindExpr(M, UnknownVal()));
- continue;
- }
-
- // FIXME: Should we insert some assumption logic in here to determine
- // if "Base" is a valid piece of memory? Before we put this assumption
- // later when using FieldOffset lvals (which we no longer have).
-
- // For all other cases, compute an lvalue.
- SVal L = state->getLValue(field, baseExprVal);
- if (M->isLValue())
- MakeNode(Dst, M, *I, state->BindExpr(M, L), ProgramPoint::PostLValueKind);
- else
- evalLoad(Dst, M, *I, state, L);
- }
-}
-
-/// evalBind - Handle the semantics of binding a value to a specific location.
-/// This method is used by evalStore and (soon) VisitDeclStmt, and others.
-void ExprEngine::evalBind(ExplodedNodeSet& Dst, const Stmt* StoreE,
- ExplodedNode* Pred, const GRState* state,
- SVal location, SVal Val, bool atDeclInit) {
-
-
- // Do a previsit of the bind.
- ExplodedNodeSet CheckedSet, Src;
- Src.Add(Pred);
- CheckerVisitBind(StoreE, CheckedSet, Src, location, Val, true);
-
- for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end();
- I!=E; ++I) {
-
- if (Pred != *I)
- state = GetState(*I);
-
- const GRState* newState = 0;
-
- if (atDeclInit) {
- const VarRegion *VR =
- cast<VarRegion>(cast<loc::MemRegionVal>(location).getRegion());
-
- newState = state->bindDecl(VR, Val);
- }
- else {
- if (location.isUnknown()) {
- // We know that the new state will be the same as the old state since
- // the location of the binding is "unknown". Consequently, there
- // is no reason to just create a new node.
- newState = state;
- }
- else {
- // We are binding to a value other than 'unknown'. Perform the binding
- // using the StoreManager.
- newState = state->bindLoc(cast<Loc>(location), Val);
- }
- }
-
- // The next thing to do is check if the TransferFuncs object wants to
- // update the state based on the new binding. If the GRTransferFunc object
- // doesn't do anything, just auto-propagate the current state.
-
- // NOTE: We use 'AssignE' for the location of the PostStore if 'AssignE'
- // is non-NULL. Checkers typically care about
-
- StmtNodeBuilderRef BuilderRef(Dst, *Builder, *this, *I, newState, StoreE,
- true);
-
- getTF().evalBind(BuilderRef, location, Val);
- }
-}
-
-/// evalStore - Handle the semantics of a store via an assignment.
-/// @param Dst The node set to store generated state nodes
-/// @param AssignE The assignment expression if the store happens in an
-/// assignment.
-/// @param LocatioinE The location expression that is stored to.
-/// @param state The current simulation state
-/// @param location The location to store the value
-/// @param Val The value to be stored
-void ExprEngine::evalStore(ExplodedNodeSet& Dst, const Expr *AssignE,
- const Expr* LocationE,
- ExplodedNode* Pred,
- const GRState* state, SVal location, SVal Val,
- const void *tag) {
-
- assert(Builder && "StmtNodeBuilder must be defined.");
-
- // Evaluate the location (checks for bad dereferences).
- ExplodedNodeSet Tmp;
- evalLocation(Tmp, LocationE, Pred, state, location, tag, false);
-
- if (Tmp.empty())
- return;
-
- assert(!location.isUndef());
-
- SaveAndRestore<ProgramPoint::Kind> OldSPointKind(Builder->PointKind,
- ProgramPoint::PostStoreKind);
- SaveAndRestore<const void*> OldTag(Builder->Tag, tag);
-
- // Proceed with the store. We use AssignE as the anchor for the PostStore
- // ProgramPoint if it is non-NULL, and LocationE otherwise.
- const Expr *StoreE = AssignE ? AssignE : LocationE;
-
- for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI)
- evalBind(Dst, StoreE, *NI, GetState(*NI), location, Val);
-}
-
-void ExprEngine::evalLoad(ExplodedNodeSet& Dst, const Expr *Ex,
- ExplodedNode* Pred,
- const GRState* state, SVal location,
- const void *tag, QualType LoadTy) {
- assert(!isa<NonLoc>(location) && "location cannot be a NonLoc.");
-
- // Are we loading from a region? This actually results in two loads; one
- // to fetch the address of the referenced value and one to fetch the
- // referenced value.
- if (const TypedRegion *TR =
- dyn_cast_or_null<TypedRegion>(location.getAsRegion())) {
-
- QualType ValTy = TR->getValueType();
- if (const ReferenceType *RT = ValTy->getAs<ReferenceType>()) {
- static int loadReferenceTag = 0;
- ExplodedNodeSet Tmp;
- evalLoadCommon(Tmp, Ex, Pred, state, location, &loadReferenceTag,
- getContext().getPointerType(RT->getPointeeType()));
-
- // Perform the load from the referenced value.
- for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end() ; I!=E; ++I) {
- state = GetState(*I);
- location = state->getSVal(Ex);
- evalLoadCommon(Dst, Ex, *I, state, location, tag, LoadTy);
- }
- return;
- }
- }
-
- evalLoadCommon(Dst, Ex, Pred, state, location, tag, LoadTy);
-}
-
-void ExprEngine::evalLoadCommon(ExplodedNodeSet& Dst, const Expr *Ex,
- ExplodedNode* Pred,
- const GRState* state, SVal location,
- const void *tag, QualType LoadTy) {
-
- // Evaluate the location (checks for bad dereferences).
- ExplodedNodeSet Tmp;
- evalLocation(Tmp, Ex, Pred, state, location, tag, true);
-
- if (Tmp.empty())
- return;
-
- assert(!location.isUndef());
-
- SaveAndRestore<ProgramPoint::Kind> OldSPointKind(Builder->PointKind);
- SaveAndRestore<const void*> OldTag(Builder->Tag);
-
- // Proceed with the load.
- for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) {
- state = GetState(*NI);
-
- if (location.isUnknown()) {
- // This is important. We must nuke the old binding.
- MakeNode(Dst, Ex, *NI, state->BindExpr(Ex, UnknownVal()),
- ProgramPoint::PostLoadKind, tag);
- }
- else {
- if (LoadTy.isNull())
- LoadTy = Ex->getType();
- SVal V = state->getSVal(cast<Loc>(location), LoadTy);
- MakeNode(Dst, Ex, *NI, state->bindExprAndLocation(Ex, location, V),
- ProgramPoint::PostLoadKind, tag);
- }
- }
-}
-
-void ExprEngine::evalLocation(ExplodedNodeSet &Dst, const Stmt *S,
- ExplodedNode* Pred,
- const GRState* state, SVal location,
- const void *tag, bool isLoad) {
- // Early checks for performance reason.
- if (location.isUnknown() || Checkers.empty()) {
- Dst.Add(Pred);
- return;
- }
-
- ExplodedNodeSet Src, Tmp;
- Src.Add(Pred);
- ExplodedNodeSet *PrevSet = &Src;
-
- for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I)
- {
- ExplodedNodeSet *CurrSet = 0;
- if (I+1 == E)
- CurrSet = &Dst;
- else {
- CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp;
- CurrSet->clear();
- }
-
- void *tag = I->first;
- Checker *checker = I->second;
-
- for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end();
- NI != NE; ++NI) {
- // Use the 'state' argument only when the predecessor node is the
- // same as Pred. This allows us to catch updates to the state.
- checker->GR_visitLocation(*CurrSet, *Builder, *this, S, *NI,
- *NI == Pred ? state : GetState(*NI),
- location, tag, isLoad);
- }
-
- // Update which NodeSet is the current one.
- PrevSet = CurrSet;
- }
-}
-
-bool ExprEngine::InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE,
- ExplodedNode *Pred) {
- const GRState *state = GetState(Pred);
- const Expr *Callee = CE->getCallee();
- SVal L = state->getSVal(Callee);
-
- const FunctionDecl *FD = L.getAsFunctionDecl();
- if (!FD)
- return false;
-
- // Check if the function definition is in the same translation unit.
- if (FD->hasBody(FD)) {
- const StackFrameContext *stackFrame =
- AMgr.getStackFrame(AMgr.getAnalysisContext(FD),
- Pred->getLocationContext(),
- CE, Builder->getBlock(), Builder->getIndex());
- // Now we have the definition of the callee, create a CallEnter node.
- CallEnter Loc(CE, stackFrame, Pred->getLocationContext());
-
- ExplodedNode *N = Builder->generateNode(Loc, state, Pred);
- Dst.Add(N);
- return true;
- }
-
- // Check if we can find the function definition in other translation units.
- if (AMgr.hasIndexer()) {
- AnalysisContext *C = AMgr.getAnalysisContextInAnotherTU(FD);
- if (C == 0)
- return false;
- const StackFrameContext *stackFrame =
- AMgr.getStackFrame(C, Pred->getLocationContext(),
- CE, Builder->getBlock(), Builder->getIndex());
- CallEnter Loc(CE, stackFrame, Pred->getLocationContext());
- ExplodedNode *N = Builder->generateNode(Loc, state, Pred);
- Dst.Add(N);
- return true;
- }
-
- return false;
-}
-
-void ExprEngine::VisitCall(const CallExpr* CE, ExplodedNode* Pred,
- CallExpr::const_arg_iterator AI,
- CallExpr::const_arg_iterator AE,
- ExplodedNodeSet& Dst) {
-
- // Determine the type of function we're calling (if available).
- const FunctionProtoType *Proto = NULL;
- QualType FnType = CE->getCallee()->IgnoreParens()->getType();
- if (const PointerType *FnTypePtr = FnType->getAs<PointerType>())
- Proto = FnTypePtr->getPointeeType()->getAs<FunctionProtoType>();
-
- // Evaluate the arguments.
- ExplodedNodeSet ArgsEvaluated;
- evalArguments(CE->arg_begin(), CE->arg_end(), Proto, Pred, ArgsEvaluated);
-
- // Now process the call itself.
- ExplodedNodeSet DstTmp;
- const Expr* Callee = CE->getCallee()->IgnoreParens();
-
- for (ExplodedNodeSet::iterator NI=ArgsEvaluated.begin(),
- NE=ArgsEvaluated.end(); NI != NE; ++NI) {
- // Evaluate the callee.
- ExplodedNodeSet DstTmp2;
- Visit(Callee, *NI, DstTmp2);
- // Perform the previsit of the CallExpr, storing the results in DstTmp.
- CheckerVisit(CE, DstTmp, DstTmp2, PreVisitStmtCallback);
- }
-
- // Finally, evaluate the function call. We try each of the checkers
- // to see if the can evaluate the function call.
- ExplodedNodeSet DstTmp3;
-
- for (ExplodedNodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end();
- DI != DE; ++DI) {
-
- const GRState* state = GetState(*DI);
- SVal L = state->getSVal(Callee);
-
- // FIXME: Add support for symbolic function calls (calls involving
- // function pointer values that are symbolic).
- SaveAndRestore<bool> OldSink(Builder->BuildSinks);
- ExplodedNodeSet DstChecker;
-
- // If the callee is processed by a checker, skip the rest logic.
- if (CheckerEvalCall(CE, DstChecker, *DI))
- DstTmp3.insert(DstChecker);
- else if (AMgr.shouldInlineCall() && InlineCall(Dst, CE, *DI)) {
- // Callee is inlined. We shouldn't do post call checking.
- return;
- }
- else {
- for (ExplodedNodeSet::iterator DI_Checker = DstChecker.begin(),
- DE_Checker = DstChecker.end();
- DI_Checker != DE_Checker; ++DI_Checker) {
-
- // Dispatch to the plug-in transfer function.
- unsigned oldSize = DstTmp3.size();
- SaveOr OldHasGen(Builder->HasGeneratedNode);
- Pred = *DI_Checker;
-
- // Dispatch to transfer function logic to handle the call itself.
- // FIXME: Allow us to chain together transfer functions.
- assert(Builder && "StmtNodeBuilder must be defined.");
- getTF().evalCall(DstTmp3, *this, *Builder, CE, L, Pred);
-
- // Handle the case where no nodes where generated. Auto-generate that
- // contains the updated state if we aren't generating sinks.
- if (!Builder->BuildSinks && DstTmp3.size() == oldSize &&
- !Builder->HasGeneratedNode)
- MakeNode(DstTmp3, CE, Pred, state);
- }
- }
- }
-
- // Finally, perform the post-condition check of the CallExpr and store
- // the created nodes in 'Dst'.
- CheckerVisit(CE, Dst, DstTmp3, PostVisitStmtCallback);
-}
-
-//===----------------------------------------------------------------------===//
-// Transfer function: Objective-C ivar references.
-//===----------------------------------------------------------------------===//
-
-static std::pair<const void*,const void*> EagerlyAssumeTag
- = std::pair<const void*,const void*>(&EagerlyAssumeTag,static_cast<void*>(0));
-
-void ExprEngine::evalEagerlyAssume(ExplodedNodeSet &Dst, ExplodedNodeSet &Src,
- const Expr *Ex) {
- for (ExplodedNodeSet::iterator I=Src.begin(), E=Src.end(); I!=E; ++I) {
- ExplodedNode *Pred = *I;
-
- // Test if the previous node was as the same expression. This can happen
- // when the expression fails to evaluate to anything meaningful and
- // (as an optimization) we don't generate a node.
- ProgramPoint P = Pred->getLocation();
- if (!isa<PostStmt>(P) || cast<PostStmt>(P).getStmt() != Ex) {
- Dst.Add(Pred);
- continue;
- }
-
- const GRState* state = GetState(Pred);
- SVal V = state->getSVal(Ex);
- if (nonloc::SymExprVal *SEV = dyn_cast<nonloc::SymExprVal>(&V)) {
- // First assume that the condition is true.
- if (const GRState *stateTrue = state->assume(*SEV, true)) {
- stateTrue = stateTrue->BindExpr(Ex,
- svalBuilder.makeIntVal(1U, Ex->getType()));
- Dst.Add(Builder->generateNode(PostStmtCustom(Ex,
- &EagerlyAssumeTag, Pred->getLocationContext()),
- stateTrue, Pred));
- }
-
- // Next, assume that the condition is false.
- if (const GRState *stateFalse = state->assume(*SEV, false)) {
- stateFalse = stateFalse->BindExpr(Ex,
- svalBuilder.makeIntVal(0U, Ex->getType()));
- Dst.Add(Builder->generateNode(PostStmtCustom(Ex, &EagerlyAssumeTag,
- Pred->getLocationContext()),
- stateFalse, Pred));
- }
- }
- else
- Dst.Add(Pred);
- }
-}
-
-//===----------------------------------------------------------------------===//
-// Transfer function: Objective-C @synchronized.
-//===----------------------------------------------------------------------===//
-
-void ExprEngine::VisitObjCAtSynchronizedStmt(const ObjCAtSynchronizedStmt *S,
- ExplodedNode *Pred,
- ExplodedNodeSet &Dst) {
-
- // The mutex expression is a CFGElement, so we don't need to explicitly
- // visit it since it will already be processed.
-
- // Pre-visit the ObjCAtSynchronizedStmt.
- ExplodedNodeSet Tmp;
- Tmp.Add(Pred);
- CheckerVisit(S, Dst, Tmp, PreVisitStmtCallback);
-}
-
-//===----------------------------------------------------------------------===//
-// Transfer function: Objective-C ivar references.
-//===----------------------------------------------------------------------===//
-
-void ExprEngine::VisitLvalObjCIvarRefExpr(const ObjCIvarRefExpr* Ex,
- ExplodedNode* Pred,
- ExplodedNodeSet& Dst) {
-
- // Visit the base expression, which is needed for computing the lvalue
- // of the ivar.
- ExplodedNodeSet dstBase;
- const Expr *baseExpr = Ex->getBase();
- Visit(baseExpr, Pred, dstBase);
-
- // Using the base, compute the lvalue of the instance variable.
- for (ExplodedNodeSet::iterator I = dstBase.begin(), E = dstBase.end();
- I!=E; ++I) {
- ExplodedNode *nodeBase = *I;
- const GRState *state = GetState(nodeBase);
- SVal baseVal = state->getSVal(baseExpr);
- SVal location = state->getLValue(Ex->getDecl(), baseVal);
- MakeNode(Dst, Ex, *I, state->BindExpr(Ex, location));
- }
-}
-
-//===----------------------------------------------------------------------===//
-// Transfer function: Objective-C fast enumeration 'for' statements.
-//===----------------------------------------------------------------------===//
-
-void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt* S,
- ExplodedNode* Pred, ExplodedNodeSet& Dst) {
-
- // ObjCForCollectionStmts are processed in two places. This method
- // handles the case where an ObjCForCollectionStmt* occurs as one of the
- // statements within a basic block. This transfer function does two things:
- //
- // (1) binds the next container value to 'element'. This creates a new
- // node in the ExplodedGraph.
- //
- // (2) binds the value 0/1 to the ObjCForCollectionStmt* itself, indicating
- // whether or not the container has any more elements. This value
- // will be tested in ProcessBranch. We need to explicitly bind
- // this value because a container can contain nil elements.
- //
- // FIXME: Eventually this logic should actually do dispatches to
- // 'countByEnumeratingWithState:objects:count:' (NSFastEnumeration).
- // This will require simulating a temporary NSFastEnumerationState, either
- // through an SVal or through the use of MemRegions. This value can
- // be affixed to the ObjCForCollectionStmt* instead of 0/1; when the loop
- // terminates we reclaim the temporary (it goes out of scope) and we
- // we can test if the SVal is 0 or if the MemRegion is null (depending
- // on what approach we take).
- //
- // For now: simulate (1) by assigning either a symbol or nil if the
- // container is empty. Thus this transfer function will by default
- // result in state splitting.
-
- const Stmt* elem = S->getElement();
- SVal ElementV;
-
- if (const DeclStmt* DS = dyn_cast<DeclStmt>(elem)) {
- const VarDecl* ElemD = cast<VarDecl>(DS->getSingleDecl());
- assert (ElemD->getInit() == 0);
- ElementV = GetState(Pred)->getLValue(ElemD, Pred->getLocationContext());
- VisitObjCForCollectionStmtAux(S, Pred, Dst, ElementV);
- return;
- }
-
- ExplodedNodeSet Tmp;
- Visit(cast<Expr>(elem), Pred, Tmp);
- for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I!=E; ++I) {
- const GRState* state = GetState(*I);
- VisitObjCForCollectionStmtAux(S, *I, Dst, state->getSVal(elem));
- }
-}
-
-void ExprEngine::VisitObjCForCollectionStmtAux(const ObjCForCollectionStmt* S,
- ExplodedNode* Pred, ExplodedNodeSet& Dst,
- SVal ElementV) {
-
- // Check if the location we are writing back to is a null pointer.
- const Stmt* elem = S->getElement();
- ExplodedNodeSet Tmp;
- evalLocation(Tmp, elem, Pred, GetState(Pred), ElementV, NULL, false);
-
- if (Tmp.empty())
- return;
-
- for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) {
- Pred = *NI;
- const GRState *state = GetState(Pred);
-
- // Handle the case where the container still has elements.
- SVal TrueV = svalBuilder.makeTruthVal(1);
- const GRState *hasElems = state->BindExpr(S, TrueV);
-
- // Handle the case where the container has no elements.
- SVal FalseV = svalBuilder.makeTruthVal(0);
- const GRState *noElems = state->BindExpr(S, FalseV);
-
- if (loc::MemRegionVal* MV = dyn_cast<loc::MemRegionVal>(&ElementV))
- if (const TypedRegion* R = dyn_cast<TypedRegion>(MV->getRegion())) {
- // FIXME: The proper thing to do is to really iterate over the
- // container. We will do this with dispatch logic to the store.
- // For now, just 'conjure' up a symbolic value.
- QualType T = R->getValueType();
- assert(Loc::IsLocType(T));
- unsigned Count = Builder->getCurrentBlockCount();
- SymbolRef Sym = SymMgr.getConjuredSymbol(elem, T, Count);
- SVal V = svalBuilder.makeLoc(Sym);
- hasElems = hasElems->bindLoc(ElementV, V);
-
- // Bind the location to 'nil' on the false branch.
- SVal nilV = svalBuilder.makeIntVal(0, T);
- noElems = noElems->bindLoc(ElementV, nilV);
- }
-
- // Create the new nodes.
- MakeNode(Dst, S, Pred, hasElems);
- MakeNode(Dst, S, Pred, noElems);
- }
-}
-
-//===----------------------------------------------------------------------===//
-// Transfer function: Objective-C message expressions.
-//===----------------------------------------------------------------------===//
-
-namespace {
-class ObjCMsgWLItem {
-public:
- ObjCMessageExpr::const_arg_iterator I;
- ExplodedNode *N;
-
- ObjCMsgWLItem(const ObjCMessageExpr::const_arg_iterator &i, ExplodedNode *n)
- : I(i), N(n) {}
-};
-} // end anonymous namespace
-
-void ExprEngine::VisitObjCMessageExpr(const ObjCMessageExpr* ME,
- ExplodedNode* Pred,
- ExplodedNodeSet& Dst){
-
- // Create a worklist to process both the arguments.
- llvm::SmallVector<ObjCMsgWLItem, 20> WL;
-
- // But first evaluate the receiver (if any).
- ObjCMessageExpr::const_arg_iterator AI = ME->arg_begin(), AE = ME->arg_end();
- if (const Expr *Receiver = ME->getInstanceReceiver()) {
- ExplodedNodeSet Tmp;
- Visit(Receiver, Pred, Tmp);
-
- if (Tmp.empty())
- return;
-
- for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I)
- WL.push_back(ObjCMsgWLItem(AI, *I));
- }
- else
- WL.push_back(ObjCMsgWLItem(AI, Pred));
-
- // Evaluate the arguments.
- ExplodedNodeSet ArgsEvaluated;
- while (!WL.empty()) {
- ObjCMsgWLItem Item = WL.back();
- WL.pop_back();
-
- if (Item.I == AE) {
- ArgsEvaluated.insert(Item.N);
- continue;
- }
-
- // Evaluate the subexpression.
- ExplodedNodeSet Tmp;
-
- // FIXME: [Objective-C++] handle arguments that are references
- Visit(*Item.I, Item.N, Tmp);
-
- // Enqueue evaluating the next argument on the worklist.
- ++(Item.I);
- for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI)
- WL.push_back(ObjCMsgWLItem(Item.I, *NI));
- }
-
- // Now that the arguments are processed, handle the previsits checks.
- ExplodedNodeSet DstPrevisit;
- CheckerVisit(ME, DstPrevisit, ArgsEvaluated, PreVisitStmtCallback);
-
- // Proceed with evaluate the message expression.
- ExplodedNodeSet dstEval;
-
- for (ExplodedNodeSet::iterator DI = DstPrevisit.begin(),
- DE = DstPrevisit.end(); DI != DE; ++DI) {
-
- Pred = *DI;
- bool RaisesException = false;
- unsigned oldSize = dstEval.size();
- SaveAndRestore<bool> OldSink(Builder->BuildSinks);
- SaveOr OldHasGen(Builder->HasGeneratedNode);
-
- if (const Expr *Receiver = ME->getInstanceReceiver()) {
- const GRState *state = GetState(Pred);
-
- // Bifurcate the state into nil and non-nil ones.
- DefinedOrUnknownSVal receiverVal =
- cast<DefinedOrUnknownSVal>(state->getSVal(Receiver));
-
- const GRState *notNilState, *nilState;
- llvm::tie(notNilState, nilState) = state->assume(receiverVal);
-
- // There are three cases: can be nil or non-nil, must be nil, must be
- // non-nil. We handle must be nil, and merge the rest two into non-nil.
- if (nilState && !notNilState) {
- CheckerEvalNilReceiver(ME, dstEval, nilState, Pred);
- continue;
- }
-
- // Check if the "raise" message was sent.
- assert(notNilState);
- if (ME->getSelector() == RaiseSel)
- RaisesException = true;
-
- // Check if we raise an exception. For now treat these as sinks.
- // Eventually we will want to handle exceptions properly.
- if (RaisesException)
- Builder->BuildSinks = true;
-
- // Dispatch to plug-in transfer function.
- evalObjCMessageExpr(dstEval, ME, Pred, notNilState);
- }
- else if (ObjCInterfaceDecl *Iface = ME->getReceiverInterface()) {
- IdentifierInfo* ClsName = Iface->getIdentifier();
- Selector S = ME->getSelector();
-
- // Check for special instance methods.
- if (!NSExceptionII) {
- ASTContext& Ctx = getContext();
- NSExceptionII = &Ctx.Idents.get("NSException");
- }
-
- if (ClsName == NSExceptionII) {
- enum { NUM_RAISE_SELECTORS = 2 };
-
- // Lazily create a cache of the selectors.
- if (!NSExceptionInstanceRaiseSelectors) {
- ASTContext& Ctx = getContext();
- NSExceptionInstanceRaiseSelectors =
- new Selector[NUM_RAISE_SELECTORS];
- llvm::SmallVector<IdentifierInfo*, NUM_RAISE_SELECTORS> II;
- unsigned idx = 0;
-
- // raise:format:
- II.push_back(&Ctx.Idents.get("raise"));
- II.push_back(&Ctx.Idents.get("format"));
- NSExceptionInstanceRaiseSelectors[idx++] =
- Ctx.Selectors.getSelector(II.size(), &II[0]);
-
- // raise:format::arguments:
- II.push_back(&Ctx.Idents.get("arguments"));
- NSExceptionInstanceRaiseSelectors[idx++] =
- Ctx.Selectors.getSelector(II.size(), &II[0]);
- }
-
- for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i)
- if (S == NSExceptionInstanceRaiseSelectors[i]) {
- RaisesException = true;
- break;
- }
- }
-
- // Check if we raise an exception. For now treat these as sinks.
- // Eventually we will want to handle exceptions properly.
- if (RaisesException)
- Builder->BuildSinks = true;
-
- // Dispatch to plug-in transfer function.
- evalObjCMessageExpr(dstEval, ME, Pred, Builder->GetState(Pred));
- }
-
- // Handle the case where no nodes where generated. Auto-generate that
- // contains the updated state if we aren't generating sinks.
- if (!Builder->BuildSinks && dstEval.size() == oldSize &&
- !Builder->HasGeneratedNode)
- MakeNode(dstEval, ME, Pred, GetState(Pred));
- }
-
- // Finally, perform the post-condition check of the ObjCMessageExpr and store
- // the created nodes in 'Dst'.
- CheckerVisit(ME, Dst, dstEval, PostVisitStmtCallback);
-}
-
-//===----------------------------------------------------------------------===//
-// Transfer functions: Miscellaneous statements.
-//===----------------------------------------------------------------------===//
-
-void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,
- ExplodedNode *Pred, ExplodedNodeSet &Dst) {
-
- ExplodedNodeSet S1;
- Visit(Ex, Pred, S1);
- ExplodedNodeSet S2;
- CheckerVisit(CastE, S2, S1, PreVisitStmtCallback);
-
- if (CastE->getCastKind() == CK_LValueToRValue) {
- for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I!=E; ++I) {
- ExplodedNode *subExprNode = *I;
- const GRState *state = GetState(subExprNode);
- evalLoad(Dst, CastE, subExprNode, state, state->getSVal(Ex));
- }
- return;
- }
-
- // All other casts.
- QualType T = CastE->getType();
- QualType ExTy = Ex->getType();
-
- if (const ExplicitCastExpr *ExCast=dyn_cast_or_null<ExplicitCastExpr>(CastE))
- T = ExCast->getTypeAsWritten();
-
-#if 0
- // If we are evaluating the cast in an lvalue context, we implicitly want
- // the cast to evaluate to a location.
- if (asLValue) {
- ASTContext &Ctx = getContext();
- T = Ctx.getPointerType(Ctx.getCanonicalType(T));
- ExTy = Ctx.getPointerType(Ctx.getCanonicalType(ExTy));
- }
-#endif
-
- switch (CastE->getCastKind()) {
- case CK_ToVoid:
- for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I)
- Dst.Add(*I);
- return;
-
- case CK_LValueToRValue:
- case CK_NoOp:
- case CK_FunctionToPointerDecay:
- for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) {
- // Copy the SVal of Ex to CastE.
- ExplodedNode *N = *I;
- const GRState *state = GetState(N);
- SVal V = state->getSVal(Ex);
- state = state->BindExpr(CastE, V);
- MakeNode(Dst, CastE, N, state);
- }
- return;
-
- case CK_GetObjCProperty:
- case CK_Dependent:
- case CK_ArrayToPointerDecay:
- case CK_BitCast:
- case CK_LValueBitCast:
- case CK_IntegralCast:
- case CK_NullToPointer:
- case CK_IntegralToPointer:
- case CK_PointerToIntegral:
- case CK_PointerToBoolean:
- case CK_IntegralToBoolean:
- case CK_IntegralToFloating:
- case CK_FloatingToIntegral:
- case CK_FloatingToBoolean:
- case CK_FloatingCast:
- case CK_FloatingRealToComplex:
- case CK_FloatingComplexToReal:
- case CK_FloatingComplexToBoolean:
- case CK_FloatingComplexCast:
- case CK_FloatingComplexToIntegralComplex:
- case CK_IntegralRealToComplex:
- case CK_IntegralComplexToReal:
- case CK_IntegralComplexToBoolean:
- case CK_IntegralComplexCast:
- case CK_IntegralComplexToFloatingComplex:
- case CK_AnyPointerToObjCPointerCast:
- case CK_AnyPointerToBlockPointerCast:
-
- case CK_ObjCObjectLValueCast: {
- // Delegate to SValBuilder to process.
- for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) {
- ExplodedNode* N = *I;
- const GRState* state = GetState(N);
- SVal V = state->getSVal(Ex);
- V = svalBuilder.evalCast(V, T, ExTy);
- state = state->BindExpr(CastE, V);
- MakeNode(Dst, CastE, N, state);
- }
- return;
- }
-
- case CK_DerivedToBase:
- case CK_UncheckedDerivedToBase:
- // For DerivedToBase cast, delegate to the store manager.
- for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) {
- ExplodedNode *node = *I;
- const GRState *state = GetState(node);
- SVal val = state->getSVal(Ex);
- val = getStoreManager().evalDerivedToBase(val, T);
- state = state->BindExpr(CastE, val);
- MakeNode(Dst, CastE, node, state);
- }
- return;
-
- // Various C++ casts that are not handled yet.
- case CK_Dynamic:
- case CK_ToUnion:
- case CK_BaseToDerived:
- case CK_NullToMemberPointer:
- case CK_BaseToDerivedMemberPointer:
- case CK_DerivedToBaseMemberPointer:
- case CK_UserDefinedConversion:
- case CK_ConstructorConversion:
- case CK_VectorSplat:
- case CK_MemberPointerToBoolean: {
- SaveAndRestore<bool> OldSink(Builder->BuildSinks);
- Builder->BuildSinks = true;
- MakeNode(Dst, CastE, Pred, GetState(Pred));
- return;
- }
- }
-}
-
-void ExprEngine::VisitCompoundLiteralExpr(const CompoundLiteralExpr* CL,
- ExplodedNode* Pred,
- ExplodedNodeSet& Dst) {
- const InitListExpr* ILE
- = cast<InitListExpr>(CL->getInitializer()->IgnoreParens());
- ExplodedNodeSet Tmp;
- Visit(ILE, Pred, Tmp);
-
- for (ExplodedNodeSet::iterator I = Tmp.begin(), EI = Tmp.end(); I!=EI; ++I) {
- const GRState* state = GetState(*I);
- SVal ILV = state->getSVal(ILE);
- const LocationContext *LC = (*I)->getLocationContext();
- state = state->bindCompoundLiteral(CL, LC, ILV);
-
- if (CL->isLValue()) {
- MakeNode(Dst, CL, *I, state->BindExpr(CL, state->getLValue(CL, LC)));
- }
- else
- MakeNode(Dst, CL, *I, state->BindExpr(CL, ILV));
- }
-}
-
-void ExprEngine::VisitDeclStmt(const DeclStmt *DS, ExplodedNode *Pred,
- ExplodedNodeSet& Dst) {
-
- // The CFG has one DeclStmt per Decl.
- const Decl* D = *DS->decl_begin();
-
- if (!D || !isa<VarDecl>(D))
- return;
-
- const VarDecl* VD = dyn_cast<VarDecl>(D);
- const Expr* InitEx = VD->getInit();
-
- // FIXME: static variables may have an initializer, but the second
- // time a function is called those values may not be current.
- ExplodedNodeSet Tmp;
-
- if (InitEx) {
- if (VD->getType()->isReferenceType() && !InitEx->isLValue()) {
- // If the initializer is C++ record type, it should already has a
- // temp object.
- if (!InitEx->getType()->isRecordType())
- CreateCXXTemporaryObject(InitEx, Pred, Tmp);
- else
- Tmp.Add(Pred);
- } else
- Visit(InitEx, Pred, Tmp);
- } else
- Tmp.Add(Pred);
-
- ExplodedNodeSet Tmp2;
- CheckerVisit(DS, Tmp2, Tmp, PreVisitStmtCallback);
-
- for (ExplodedNodeSet::iterator I=Tmp2.begin(), E=Tmp2.end(); I!=E; ++I) {
- ExplodedNode *N = *I;
- const GRState *state = GetState(N);
-
- // Decls without InitExpr are not initialized explicitly.
- const LocationContext *LC = N->getLocationContext();
-
- if (InitEx) {
- SVal InitVal = state->getSVal(InitEx);
-
- // We bound the temp obj region to the CXXConstructExpr. Now recover
- // the lazy compound value when the variable is not a reference.
- if (AMgr.getLangOptions().CPlusPlus && VD->getType()->isRecordType() &&
- !VD->getType()->isReferenceType() && isa<loc::MemRegionVal>(InitVal)){
- InitVal = state->getSVal(cast<loc::MemRegionVal>(InitVal).getRegion());
- assert(isa<nonloc::LazyCompoundVal>(InitVal));
- }
-
- // Recover some path-sensitivity if a scalar value evaluated to
- // UnknownVal.
- if ((InitVal.isUnknown() ||
- !getConstraintManager().canReasonAbout(InitVal)) &&
- !VD->getType()->isReferenceType()) {
- InitVal = svalBuilder.getConjuredSymbolVal(NULL, InitEx,
- Builder->getCurrentBlockCount());
- }
-
- evalBind(Dst, DS, *I, state,
- loc::MemRegionVal(state->getRegion(VD, LC)), InitVal, true);
- }
- else {
- state = state->bindDeclWithNoInit(state->getRegion(VD, LC));
- MakeNode(Dst, DS, *I, state);
- }
- }
-}
-
-void ExprEngine::VisitCondInit(const VarDecl *VD, const Stmt *S,
- ExplodedNode *Pred, ExplodedNodeSet& Dst) {
-
- const Expr* InitEx = VD->getInit();
- ExplodedNodeSet Tmp;
- Visit(InitEx, Pred, Tmp);
-
- for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
- ExplodedNode *N = *I;
- const GRState *state = GetState(N);
-
- const LocationContext *LC = N->getLocationContext();
- SVal InitVal = state->getSVal(InitEx);
-
- // Recover some path-sensitivity if a scalar value evaluated to
- // UnknownVal.
- if (InitVal.isUnknown() ||
- !getConstraintManager().canReasonAbout(InitVal)) {
- InitVal = svalBuilder.getConjuredSymbolVal(NULL, InitEx,
- Builder->getCurrentBlockCount());
- }
-
- evalBind(Dst, S, N, state,
- loc::MemRegionVal(state->getRegion(VD, LC)), InitVal, true);
- }
-}
-
-namespace {
- // This class is used by VisitInitListExpr as an item in a worklist
- // for processing the values contained in an InitListExpr.
-class InitListWLItem {
-public:
- llvm::ImmutableList<SVal> Vals;
- ExplodedNode* N;
- InitListExpr::const_reverse_iterator Itr;
-
- InitListWLItem(ExplodedNode* n, llvm::ImmutableList<SVal> vals,
- InitListExpr::const_reverse_iterator itr)
- : Vals(vals), N(n), Itr(itr) {}
-};
-}
-
-
-void ExprEngine::VisitInitListExpr(const InitListExpr* E, ExplodedNode* Pred,
- ExplodedNodeSet& Dst) {
-
- const GRState* state = GetState(Pred);
- QualType T = getContext().getCanonicalType(E->getType());
- unsigned NumInitElements = E->getNumInits();
-
- if (T->isArrayType() || T->isRecordType() || T->isVectorType()) {
- llvm::ImmutableList<SVal> StartVals = getBasicVals().getEmptySValList();
-
- // Handle base case where the initializer has no elements.
- // e.g: static int* myArray[] = {};
- if (NumInitElements == 0) {
- SVal V = svalBuilder.makeCompoundVal(T, StartVals);
- MakeNode(Dst, E, Pred, state->BindExpr(E, V));
- return;
- }
-
- // Create a worklist to process the initializers.
- llvm::SmallVector<InitListWLItem, 10> WorkList;
- WorkList.reserve(NumInitElements);
- WorkList.push_back(InitListWLItem(Pred, StartVals, E->rbegin()));
- InitListExpr::const_reverse_iterator ItrEnd = E->rend();
- assert(!(E->rbegin() == E->rend()));
-
- // Process the worklist until it is empty.
- while (!WorkList.empty()) {
- InitListWLItem X = WorkList.back();
- WorkList.pop_back();
-
- ExplodedNodeSet Tmp;
- Visit(*X.Itr, X.N, Tmp);
-
- InitListExpr::const_reverse_iterator NewItr = X.Itr + 1;
-
- for (ExplodedNodeSet::iterator NI=Tmp.begin(),NE=Tmp.end();NI!=NE;++NI) {
- // Get the last initializer value.
- state = GetState(*NI);
- SVal InitV = state->getSVal(cast<Expr>(*X.Itr));
-
- // Construct the new list of values by prepending the new value to
- // the already constructed list.
- llvm::ImmutableList<SVal> NewVals =
- getBasicVals().consVals(InitV, X.Vals);
-
- if (NewItr == ItrEnd) {
- // Now we have a list holding all init values. Make CompoundValData.
- SVal V = svalBuilder.makeCompoundVal(T, NewVals);
-
- // Make final state and node.
- MakeNode(Dst, E, *NI, state->BindExpr(E, V));
- }
- else {
- // Still some initializer values to go. Push them onto the worklist.
- WorkList.push_back(InitListWLItem(*NI, NewVals, NewItr));
- }
- }
- }
-
- return;
- }
-
- if (Loc::IsLocType(T) || T->isIntegerType()) {
- assert (E->getNumInits() == 1);
- ExplodedNodeSet Tmp;
- const Expr* Init = E->getInit(0);
- Visit(Init, Pred, Tmp);
- for (ExplodedNodeSet::iterator I=Tmp.begin(), EI=Tmp.end(); I != EI; ++I) {
- state = GetState(*I);
- MakeNode(Dst, E, *I, state->BindExpr(E, state->getSVal(Init)));
- }
- return;
- }
-
- assert(0 && "unprocessed InitListExpr type");
-}
-
-/// VisitSizeOfAlignOfExpr - Transfer function for sizeof(type).
-void ExprEngine::VisitSizeOfAlignOfExpr(const SizeOfAlignOfExpr* Ex,
- ExplodedNode* Pred,
- ExplodedNodeSet& Dst) {
- QualType T = Ex->getTypeOfArgument();
- CharUnits amt;
-
- if (Ex->isSizeOf()) {
- if (T == getContext().VoidTy) {
- // sizeof(void) == 1 byte.
- amt = CharUnits::One();
- }
- else if (!T->isConstantSizeType()) {
- assert(T->isVariableArrayType() && "Unknown non-constant-sized type.");
-
- // FIXME: Add support for VLA type arguments, not just VLA expressions.
- // When that happens, we should probably refactor VLASizeChecker's code.
- if (Ex->isArgumentType()) {
- Dst.Add(Pred);
- return;
- }
-
- // Get the size by getting the extent of the sub-expression.
- // First, visit the sub-expression to find its region.
- const Expr *Arg = Ex->getArgumentExpr();
- ExplodedNodeSet Tmp;
- Visit(Arg, Pred, Tmp);
-
- for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
- const GRState* state = GetState(*I);
- const MemRegion *MR = state->getSVal(Arg).getAsRegion();
-
- // If the subexpression can't be resolved to a region, we don't know
- // anything about its size. Just leave the state as is and continue.
- if (!MR) {
- Dst.Add(*I);
- continue;
- }
-
- // The result is the extent of the VLA.
- SVal Extent = cast<SubRegion>(MR)->getExtent(svalBuilder);
- MakeNode(Dst, Ex, *I, state->BindExpr(Ex, Extent));
- }
-
- return;
- }
- else if (T->getAs<ObjCObjectType>()) {
- // Some code tries to take the sizeof an ObjCObjectType, relying that
- // the compiler has laid out its representation. Just report Unknown
- // for these.
- Dst.Add(Pred);
- return;
- }
- else {
- // All other cases.
- amt = getContext().getTypeSizeInChars(T);
- }
- }
- else // Get alignment of the type.
- amt = getContext().getTypeAlignInChars(T);
-
- MakeNode(Dst, Ex, Pred,
- GetState(Pred)->BindExpr(Ex,
- svalBuilder.makeIntVal(amt.getQuantity(), Ex->getType())));
-}
-
-void ExprEngine::VisitOffsetOfExpr(const OffsetOfExpr* OOE,
- ExplodedNode* Pred, ExplodedNodeSet& Dst) {
- Expr::EvalResult Res;
- if (OOE->Evaluate(Res, getContext()) && Res.Val.isInt()) {
- const APSInt &IV = Res.Val.getInt();
- assert(IV.getBitWidth() == getContext().getTypeSize(OOE->getType()));
- assert(OOE->getType()->isIntegerType());
- assert(IV.isSigned() == OOE->getType()->isSignedIntegerType());
- SVal X = svalBuilder.makeIntVal(IV);
- MakeNode(Dst, OOE, Pred, GetState(Pred)->BindExpr(OOE, X));
- return;
- }
- // FIXME: Handle the case where __builtin_offsetof is not a constant.
- Dst.Add(Pred);
-}
-
-void ExprEngine::VisitUnaryOperator(const UnaryOperator* U,
- ExplodedNode* Pred,
- ExplodedNodeSet& Dst) {
-
- switch (U->getOpcode()) {
-
- default:
- break;
-
- case UO_Real: {
- const Expr* Ex = U->getSubExpr()->IgnoreParens();
- ExplodedNodeSet Tmp;
- Visit(Ex, Pred, Tmp);
-
- for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
-
- // FIXME: We don't have complex SValues yet.
- if (Ex->getType()->isAnyComplexType()) {
- // Just report "Unknown."
- Dst.Add(*I);
- continue;
- }
-
- // For all other types, UO_Real is an identity operation.
- assert (U->getType() == Ex->getType());
- const GRState* state = GetState(*I);
- MakeNode(Dst, U, *I, state->BindExpr(U, state->getSVal(Ex)));
- }
-
- return;
- }
-
- case UO_Imag: {
-
- const Expr* Ex = U->getSubExpr()->IgnoreParens();
- ExplodedNodeSet Tmp;
- Visit(Ex, Pred, Tmp);
-
- for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
- // FIXME: We don't have complex SValues yet.
- if (Ex->getType()->isAnyComplexType()) {
- // Just report "Unknown."
- Dst.Add(*I);
- continue;
- }
-
- // For all other types, UO_Imag returns 0.
- const GRState* state = GetState(*I);
- SVal X = svalBuilder.makeZeroVal(Ex->getType());
- MakeNode(Dst, U, *I, state->BindExpr(U, X));
- }
-
- return;
- }
-
- case UO_Plus:
- assert(!U->isLValue());
- // FALL-THROUGH.
- case UO_Deref:
- case UO_AddrOf:
- case UO_Extension: {
-
- // Unary "+" is a no-op, similar to a parentheses. We still have places
- // where it may be a block-level expression, so we need to
- // generate an extra node that just propagates the value of the
- // subexpression.
-
- const Expr* Ex = U->getSubExpr()->IgnoreParens();
- ExplodedNodeSet Tmp;
- Visit(Ex, Pred, Tmp);
-
- for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
- const GRState* state = GetState(*I);
- MakeNode(Dst, U, *I, state->BindExpr(U, state->getSVal(Ex)));
- }
-
- return;
- }
-
- case UO_LNot:
- case UO_Minus:
- case UO_Not: {
- assert (!U->isLValue());
- const Expr* Ex = U->getSubExpr()->IgnoreParens();
- ExplodedNodeSet Tmp;
- Visit(Ex, Pred, Tmp);
-
- for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
- const GRState* state = GetState(*I);
-
- // Get the value of the subexpression.
- SVal V = state->getSVal(Ex);
-
- if (V.isUnknownOrUndef()) {
- MakeNode(Dst, U, *I, state->BindExpr(U, V));
- continue;
- }
-
-// QualType DstT = getContext().getCanonicalType(U->getType());
-// QualType SrcT = getContext().getCanonicalType(Ex->getType());
-//
-// if (DstT != SrcT) // Perform promotions.
-// V = evalCast(V, DstT);
-//
-// if (V.isUnknownOrUndef()) {
-// MakeNode(Dst, U, *I, BindExpr(St, U, V));
-// continue;
-// }
-
- switch (U->getOpcode()) {
- default:
- assert(false && "Invalid Opcode.");
- break;
-
- case UO_Not:
- // FIXME: Do we need to handle promotions?
- state = state->BindExpr(U, evalComplement(cast<NonLoc>(V)));
- break;
-
- case UO_Minus:
- // FIXME: Do we need to handle promotions?
- state = state->BindExpr(U, evalMinus(cast<NonLoc>(V)));
- break;
-
- case UO_LNot:
-
- // C99 6.5.3.3: "The expression !E is equivalent to (0==E)."
- //
- // Note: technically we do "E == 0", but this is the same in the
- // transfer functions as "0 == E".
- SVal Result;
-
- if (isa<Loc>(V)) {
- Loc X = svalBuilder.makeNull();
- Result = evalBinOp(state, BO_EQ, cast<Loc>(V), X,
- U->getType());
- }
- else {
- nonloc::ConcreteInt X(getBasicVals().getValue(0, Ex->getType()));
- Result = evalBinOp(state, BO_EQ, cast<NonLoc>(V), X,
- U->getType());
- }
-
- state = state->BindExpr(U, Result);
-
- break;
- }
-
- MakeNode(Dst, U, *I, state);
- }
-
- return;
- }
- }
-
- // Handle ++ and -- (both pre- and post-increment).
- assert (U->isIncrementDecrementOp());
- ExplodedNodeSet Tmp;
- const Expr* Ex = U->getSubExpr()->IgnoreParens();
- Visit(Ex, Pred, Tmp);
-
- for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I!=E; ++I) {
-
- const GRState* state = GetState(*I);
- SVal loc = state->getSVal(Ex);
-
- // Perform a load.
- ExplodedNodeSet Tmp2;
- evalLoad(Tmp2, Ex, *I, state, loc);
-
- for (ExplodedNodeSet::iterator I2=Tmp2.begin(), E2=Tmp2.end();I2!=E2;++I2) {
-
- state = GetState(*I2);
- SVal V2_untested = state->getSVal(Ex);
-
- // Propagate unknown and undefined values.
- if (V2_untested.isUnknownOrUndef()) {
- MakeNode(Dst, U, *I2, state->BindExpr(U, V2_untested));
- continue;
- }
- DefinedSVal V2 = cast<DefinedSVal>(V2_untested);
-
- // Handle all other values.
- BinaryOperator::Opcode Op = U->isIncrementOp() ? BO_Add
- : BO_Sub;
-
- // If the UnaryOperator has non-location type, use its type to create the
- // constant value. If the UnaryOperator has location type, create the
- // constant with int type and pointer width.
- SVal RHS;
-
- if (U->getType()->isAnyPointerType())
- RHS = svalBuilder.makeIntValWithPtrWidth(1, false);
- else
- RHS = svalBuilder.makeIntVal(1, U->getType());
-
- SVal Result = evalBinOp(state, Op, V2, RHS, U->getType());
-
- // Conjure a new symbol if necessary to recover precision.
- if (Result.isUnknown() || !getConstraintManager().canReasonAbout(Result)){
- DefinedOrUnknownSVal SymVal =
- svalBuilder.getConjuredSymbolVal(NULL, Ex,
- Builder->getCurrentBlockCount());
- Result = SymVal;
-
- // If the value is a location, ++/-- should always preserve
- // non-nullness. Check if the original value was non-null, and if so
- // propagate that constraint.
- if (Loc::IsLocType(U->getType())) {
- DefinedOrUnknownSVal Constraint =
- svalBuilder.evalEQ(state, V2,svalBuilder.makeZeroVal(U->getType()));
-
- if (!state->assume(Constraint, true)) {
- // It isn't feasible for the original value to be null.
- // Propagate this constraint.
- Constraint = svalBuilder.evalEQ(state, SymVal,
- svalBuilder.makeZeroVal(U->getType()));
-
-
- state = state->assume(Constraint, false);
- assert(state);
- }
- }
- }
-
- // Since the lvalue-to-rvalue conversion is explicit in the AST,
- // we bind an l-value if the operator is prefix and an lvalue (in C++).
- if (U->isPrefix() && U->isLValue())
- state = state->BindExpr(U, loc);
- else
- state = state->BindExpr(U, V2);
-
- // Perform the store.
- evalStore(Dst, NULL, U, *I2, state, loc, Result);
- }
- }
-}
-
-void ExprEngine::VisitAsmStmt(const AsmStmt* A, ExplodedNode* Pred,
- ExplodedNodeSet& Dst) {
- VisitAsmStmtHelperOutputs(A, A->begin_outputs(), A->end_outputs(), Pred, Dst);
-}
-
-void ExprEngine::VisitAsmStmtHelperOutputs(const AsmStmt* A,
- AsmStmt::const_outputs_iterator I,
- AsmStmt::const_outputs_iterator E,
- ExplodedNode* Pred, ExplodedNodeSet& Dst) {
- if (I == E) {
- VisitAsmStmtHelperInputs(A, A->begin_inputs(), A->end_inputs(), Pred, Dst);
- return;
- }
-
- ExplodedNodeSet Tmp;
- Visit(*I, Pred, Tmp);
- ++I;
-
- for (ExplodedNodeSet::iterator NI = Tmp.begin(), NE = Tmp.end();NI != NE;++NI)
- VisitAsmStmtHelperOutputs(A, I, E, *NI, Dst);
-}
-
-void ExprEngine::VisitAsmStmtHelperInputs(const AsmStmt* A,
- AsmStmt::const_inputs_iterator I,
- AsmStmt::const_inputs_iterator E,
- ExplodedNode* Pred,
- ExplodedNodeSet& Dst) {
- if (I == E) {
-
- // We have processed both the inputs and the outputs. All of the outputs
- // should evaluate to Locs. Nuke all of their values.
-
- // FIXME: Some day in the future it would be nice to allow a "plug-in"
- // which interprets the inline asm and stores proper results in the
- // outputs.
-
- const GRState* state = GetState(Pred);
-
- for (AsmStmt::const_outputs_iterator OI = A->begin_outputs(),
- OE = A->end_outputs(); OI != OE; ++OI) {
-
- SVal X = state->getSVal(*OI);
- assert (!isa<NonLoc>(X)); // Should be an Lval, or unknown, undef.
-
- if (isa<Loc>(X))
- state = state->bindLoc(cast<Loc>(X), UnknownVal());
- }
-
- MakeNode(Dst, A, Pred, state);
- return;
- }
-
- ExplodedNodeSet Tmp;
- Visit(*I, Pred, Tmp);
-
- ++I;
-
- for (ExplodedNodeSet::iterator NI = Tmp.begin(), NE = Tmp.end(); NI!=NE; ++NI)
- VisitAsmStmtHelperInputs(A, I, E, *NI, Dst);
-}
-
-void ExprEngine::VisitReturnStmt(const ReturnStmt *RS, ExplodedNode *Pred,
- ExplodedNodeSet &Dst) {
- ExplodedNodeSet Src;
- if (const Expr *RetE = RS->getRetValue()) {
- // Record the returned expression in the state. It will be used in
- // ProcessCallExit to bind the return value to the call expr.
- {
- static int Tag = 0;
- SaveAndRestore<const void *> OldTag(Builder->Tag, &Tag);
- const GRState *state = GetState(Pred);
- state = state->set<ReturnExpr>(RetE);
- Pred = Builder->generateNode(RetE, state, Pred);
- }
- // We may get a NULL Pred because we generated a cached node.
- if (Pred)
- Visit(RetE, Pred, Src);
- }
- else {
- Src.Add(Pred);
- }
-
- ExplodedNodeSet CheckedSet;
- CheckerVisit(RS, CheckedSet, Src, PreVisitStmtCallback);
-
- for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end();
- I != E; ++I) {
-
- assert(Builder && "StmtNodeBuilder must be defined.");
-
- Pred = *I;
- unsigned size = Dst.size();
-
- SaveAndRestore<bool> OldSink(Builder->BuildSinks);
- SaveOr OldHasGen(Builder->HasGeneratedNode);
-
- getTF().evalReturn(Dst, *this, *Builder, RS, Pred);
-
- // Handle the case where no nodes where generated.
- if (!Builder->BuildSinks && Dst.size() == size &&
- !Builder->HasGeneratedNode)
- MakeNode(Dst, RS, Pred, GetState(Pred));
- }
-}
-
-//===----------------------------------------------------------------------===//
-// Transfer functions: Binary operators.
-//===----------------------------------------------------------------------===//
-
-void ExprEngine::VisitBinaryOperator(const BinaryOperator* B,
- ExplodedNode* Pred,
- ExplodedNodeSet& Dst) {
- ExplodedNodeSet Tmp1;
- Expr* LHS = B->getLHS()->IgnoreParens();
- Expr* RHS = B->getRHS()->IgnoreParens();
-
- Visit(LHS, Pred, Tmp1);
- ExplodedNodeSet Tmp3;
-
- for (ExplodedNodeSet::iterator I1=Tmp1.begin(), E1=Tmp1.end(); I1!=E1; ++I1) {
- SVal LeftV = GetState(*I1)->getSVal(LHS);
- ExplodedNodeSet Tmp2;
- Visit(RHS, *I1, Tmp2);
-
- ExplodedNodeSet CheckedSet;
- CheckerVisit(B, CheckedSet, Tmp2, PreVisitStmtCallback);
-
- // With both the LHS and RHS evaluated, process the operation itself.
-
- for (ExplodedNodeSet::iterator I2=CheckedSet.begin(), E2=CheckedSet.end();
- I2 != E2; ++I2) {
-
- const GRState *state = GetState(*I2);
- SVal RightV = state->getSVal(RHS);
-
- BinaryOperator::Opcode Op = B->getOpcode();
-
- if (Op == BO_Assign) {
- // EXPERIMENTAL: "Conjured" symbols.
- // FIXME: Handle structs.
- QualType T = RHS->getType();
-
- if (RightV.isUnknown() ||!getConstraintManager().canReasonAbout(RightV))
- {
- unsigned Count = Builder->getCurrentBlockCount();
- RightV = svalBuilder.getConjuredSymbolVal(NULL, B->getRHS(), Count);
- }
-
- SVal ExprVal = B->isLValue() ? LeftV : RightV;
-
- // Simulate the effects of a "store": bind the value of the RHS
- // to the L-Value represented by the LHS.
- evalStore(Tmp3, B, LHS, *I2, state->BindExpr(B, ExprVal), LeftV,RightV);
- continue;
- }
-
- if (!B->isAssignmentOp()) {
- // Process non-assignments except commas or short-circuited
- // logical expressions (LAnd and LOr).
- SVal Result = evalBinOp(state, Op, LeftV, RightV, B->getType());
-
- if (Result.isUnknown()) {
- MakeNode(Tmp3, B, *I2, state);
- continue;
- }
-
- state = state->BindExpr(B, Result);
-
- MakeNode(Tmp3, B, *I2, state);
- continue;
- }
-
- assert (B->isCompoundAssignmentOp());
-
- switch (Op) {
- default:
- assert(0 && "Invalid opcode for compound assignment.");
- case BO_MulAssign: Op = BO_Mul; break;
- case BO_DivAssign: Op = BO_Div; break;
- case BO_RemAssign: Op = BO_Rem; break;
- case BO_AddAssign: Op = BO_Add; break;
- case BO_SubAssign: Op = BO_Sub; break;
- case BO_ShlAssign: Op = BO_Shl; break;
- case BO_ShrAssign: Op = BO_Shr; break;
- case BO_AndAssign: Op = BO_And; break;
- case BO_XorAssign: Op = BO_Xor; break;
- case BO_OrAssign: Op = BO_Or; break;
- }
-
- // Perform a load (the LHS). This performs the checks for
- // null dereferences, and so on.
- ExplodedNodeSet Tmp4;
- SVal location = state->getSVal(LHS);
- evalLoad(Tmp4, LHS, *I2, state, location);
-
- for (ExplodedNodeSet::iterator I4=Tmp4.begin(), E4=Tmp4.end(); I4!=E4;
- ++I4) {
- state = GetState(*I4);
- SVal V = state->getSVal(LHS);
-
- // Get the computation type.
- QualType CTy =
- cast<CompoundAssignOperator>(B)->getComputationResultType();
- CTy = getContext().getCanonicalType(CTy);
-
- QualType CLHSTy =
- cast<CompoundAssignOperator>(B)->getComputationLHSType();
- CLHSTy = getContext().getCanonicalType(CLHSTy);
-
- QualType LTy = getContext().getCanonicalType(LHS->getType());
- QualType RTy = getContext().getCanonicalType(RHS->getType());
-
- // Promote LHS.
- V = svalBuilder.evalCast(V, CLHSTy, LTy);
-
- // Compute the result of the operation.
- SVal Result = svalBuilder.evalCast(evalBinOp(state, Op, V, RightV, CTy),
- B->getType(), CTy);
-
- // EXPERIMENTAL: "Conjured" symbols.
- // FIXME: Handle structs.
-
- SVal LHSVal;
-
- if (Result.isUnknown() ||
- !getConstraintManager().canReasonAbout(Result)) {
-
- unsigned Count = Builder->getCurrentBlockCount();
-
- // The symbolic value is actually for the type of the left-hand side
- // expression, not the computation type, as this is the value the
- // LValue on the LHS will bind to.
- LHSVal = svalBuilder.getConjuredSymbolVal(NULL, B->getRHS(), LTy, Count);
-
- // However, we need to convert the symbol to the computation type.
- Result = svalBuilder.evalCast(LHSVal, CTy, LTy);
- }
- else {
- // The left-hand side may bind to a different value then the
- // computation type.
- LHSVal = svalBuilder.evalCast(Result, LTy, CTy);
- }
-
- evalStore(Tmp3, B, LHS, *I4, state->BindExpr(B, Result),
- location, LHSVal);
- }
- }
- }
-
- CheckerVisit(B, Dst, Tmp3, PostVisitStmtCallback);
-}
-
-//===----------------------------------------------------------------------===//
-// Checker registration/lookup.
-//===----------------------------------------------------------------------===//
-
-Checker *ExprEngine::lookupChecker(void *tag) const {
- CheckerMap::const_iterator I = CheckerM.find(tag);
- return (I == CheckerM.end()) ? NULL : Checkers[I->second].second;
-}
-
-//===----------------------------------------------------------------------===//
-// Visualization.
-//===----------------------------------------------------------------------===//
-
-#ifndef NDEBUG
-static ExprEngine* GraphPrintCheckerState;
-static SourceManager* GraphPrintSourceManager;
-
-namespace llvm {
-template<>
-struct DOTGraphTraits<ExplodedNode*> :
- public DefaultDOTGraphTraits {
-
- DOTGraphTraits (bool isSimple=false) : DefaultDOTGraphTraits(isSimple) {}
-
- // FIXME: Since we do not cache error nodes in ExprEngine now, this does not
- // work.
- static std::string getNodeAttributes(const ExplodedNode* N, void*) {
-
-#if 0
- // FIXME: Replace with a general scheme to tell if the node is
- // an error node.
- if (GraphPrintCheckerState->isImplicitNullDeref(N) ||
- GraphPrintCheckerState->isExplicitNullDeref(N) ||
- GraphPrintCheckerState->isUndefDeref(N) ||
- GraphPrintCheckerState->isUndefStore(N) ||
- GraphPrintCheckerState->isUndefControlFlow(N) ||
- GraphPrintCheckerState->isUndefResult(N) ||
- GraphPrintCheckerState->isBadCall(N) ||
- GraphPrintCheckerState->isUndefArg(N))
- return "color=\"red\",style=\"filled\"";
-
- if (GraphPrintCheckerState->isNoReturnCall(N))
- return "color=\"blue\",style=\"filled\"";
-#endif
- return "";
- }
-
- static std::string getNodeLabel(const ExplodedNode* N, void*){
-
- std::string sbuf;
- llvm::raw_string_ostream Out(sbuf);
-
- // Program Location.
- ProgramPoint Loc = N->getLocation();
-
- switch (Loc.getKind()) {
- case ProgramPoint::BlockEntranceKind:
- Out << "Block Entrance: B"
- << cast<BlockEntrance>(Loc).getBlock()->getBlockID();
- break;
-
- case ProgramPoint::BlockExitKind:
- assert (false);
- break;
-
- case ProgramPoint::CallEnterKind:
- Out << "CallEnter";
- break;
-
- case ProgramPoint::CallExitKind:
- Out << "CallExit";
- break;
-
- default: {
- if (StmtPoint *L = dyn_cast<StmtPoint>(&Loc)) {
- const Stmt* S = L->getStmt();
- SourceLocation SLoc = S->getLocStart();
-
- Out << S->getStmtClassName() << ' ' << (void*) S << ' ';
- LangOptions LO; // FIXME.
- S->printPretty(Out, 0, PrintingPolicy(LO));
-
- if (SLoc.isFileID()) {
- Out << "\\lline="
- << GraphPrintSourceManager->getInstantiationLineNumber(SLoc)
- << " col="
- << GraphPrintSourceManager->getInstantiationColumnNumber(SLoc)
- << "\\l";
- }
-
- if (isa<PreStmt>(Loc))
- Out << "\\lPreStmt\\l;";
- else if (isa<PostLoad>(Loc))
- Out << "\\lPostLoad\\l;";
- else if (isa<PostStore>(Loc))
- Out << "\\lPostStore\\l";
- else if (isa<PostLValue>(Loc))
- Out << "\\lPostLValue\\l";
-
-#if 0
- // FIXME: Replace with a general scheme to determine
- // the name of the check.
- if (GraphPrintCheckerState->isImplicitNullDeref(N))
- Out << "\\|Implicit-Null Dereference.\\l";
- else if (GraphPrintCheckerState->isExplicitNullDeref(N))
- Out << "\\|Explicit-Null Dereference.\\l";
- else if (GraphPrintCheckerState->isUndefDeref(N))
- Out << "\\|Dereference of undefialied value.\\l";
- else if (GraphPrintCheckerState->isUndefStore(N))
- Out << "\\|Store to Undefined Loc.";
- else if (GraphPrintCheckerState->isUndefResult(N))
- Out << "\\|Result of operation is undefined.";
- else if (GraphPrintCheckerState->isNoReturnCall(N))
- Out << "\\|Call to function marked \"noreturn\".";
- else if (GraphPrintCheckerState->isBadCall(N))
- Out << "\\|Call to NULL/Undefined.";
- else if (GraphPrintCheckerState->isUndefArg(N))
- Out << "\\|Argument in call is undefined";
-#endif
-
- break;
- }
-
- const BlockEdge& E = cast<BlockEdge>(Loc);
- Out << "Edge: (B" << E.getSrc()->getBlockID() << ", B"
- << E.getDst()->getBlockID() << ')';
-
- if (const Stmt* T = E.getSrc()->getTerminator()) {
-
- SourceLocation SLoc = T->getLocStart();
-
- Out << "\\|Terminator: ";
- LangOptions LO; // FIXME.
- E.getSrc()->printTerminator(Out, LO);
-
- if (SLoc.isFileID()) {
- Out << "\\lline="
- << GraphPrintSourceManager->getInstantiationLineNumber(SLoc)
- << " col="
- << GraphPrintSourceManager->getInstantiationColumnNumber(SLoc);
- }
-
- if (isa<SwitchStmt>(T)) {
- const Stmt* Label = E.getDst()->getLabel();
-
- if (Label) {
- if (const CaseStmt* C = dyn_cast<CaseStmt>(Label)) {
- Out << "\\lcase ";
- LangOptions LO; // FIXME.
- C->getLHS()->printPretty(Out, 0, PrintingPolicy(LO));
-
- if (const Stmt* RHS = C->getRHS()) {
- Out << " .. ";
- RHS->printPretty(Out, 0, PrintingPolicy(LO));
- }
-
- Out << ":";
- }
- else {
- assert (isa<DefaultStmt>(Label));
- Out << "\\ldefault:";
- }
- }
- else
- Out << "\\l(implicit) default:";
- }
- else if (isa<IndirectGotoStmt>(T)) {
- // FIXME
- }
- else {
- Out << "\\lCondition: ";
- if (*E.getSrc()->succ_begin() == E.getDst())
- Out << "true";
- else
- Out << "false";
- }
-
- Out << "\\l";
- }
-
-#if 0
- // FIXME: Replace with a general scheme to determine
- // the name of the check.
- if (GraphPrintCheckerState->isUndefControlFlow(N)) {
- Out << "\\|Control-flow based on\\lUndefined value.\\l";
- }
-#endif
- }
- }
-
- const GRState *state = N->getState();
- Out << "\\|StateID: " << (void*) state
- << " NodeID: " << (void*) N << "\\|";
- state->printDOT(Out, *N->getLocationContext()->getCFG());
- Out << "\\l";
- return Out.str();
- }
-};
-} // end llvm namespace
-#endif
-
-#ifndef NDEBUG
-template <typename ITERATOR>
-ExplodedNode* GetGraphNode(ITERATOR I) { return *I; }
-
-template <> ExplodedNode*
-GetGraphNode<llvm::DenseMap<ExplodedNode*, Expr*>::iterator>
- (llvm::DenseMap<ExplodedNode*, Expr*>::iterator I) {
- return I->first;
-}
-#endif
-
-void ExprEngine::ViewGraph(bool trim) {
-#ifndef NDEBUG
- if (trim) {
- std::vector<ExplodedNode*> Src;
-
- // Flush any outstanding reports to make sure we cover all the nodes.
- // This does not cause them to get displayed.
- for (BugReporter::iterator I=BR.begin(), E=BR.end(); I!=E; ++I)
- const_cast<BugType*>(*I)->FlushReports(BR);
-
- // Iterate through the reports and get their nodes.
- for (BugReporter::iterator I=BR.begin(), E=BR.end(); I!=E; ++I) {
- for (BugType::const_iterator I2=(*I)->begin(), E2=(*I)->end();
- I2!=E2; ++I2) {
- const BugReportEquivClass& EQ = *I2;
- const BugReport &R = **EQ.begin();
- ExplodedNode *N = const_cast<ExplodedNode*>(R.getErrorNode());
- if (N) Src.push_back(N);
- }
- }
-
- ViewGraph(&Src[0], &Src[0]+Src.size());
- }
- else {
- GraphPrintCheckerState = this;
- GraphPrintSourceManager = &getContext().getSourceManager();
-
- llvm::ViewGraph(*G.roots_begin(), "ExprEngine");
-
- GraphPrintCheckerState = NULL;
- GraphPrintSourceManager = NULL;
- }
-#endif
-}
-
-void ExprEngine::ViewGraph(ExplodedNode** Beg, ExplodedNode** End) {
-#ifndef NDEBUG
- GraphPrintCheckerState = this;
- GraphPrintSourceManager = &getContext().getSourceManager();
-
- std::auto_ptr<ExplodedGraph> TrimmedG(G.Trim(Beg, End).first);
-
- if (!TrimmedG.get())
- llvm::errs() << "warning: Trimmed ExplodedGraph is empty.\n";
- else
- llvm::ViewGraph(*TrimmedG->roots_begin(), "TrimmedExprEngine");
-
- GraphPrintCheckerState = NULL;
- GraphPrintSourceManager = NULL;
-#endif
-}
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/ExprEngineExperimentalChecks.cpp b/clang/lib/StaticAnalyzer/EntoSA/Checkers/ExprEngineExperimentalChecks.cpp
deleted file mode 100644
index 52a3aced2d0..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/ExprEngineExperimentalChecks.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-//=-- ExprEngineExperimentalChecks.h ------------------------------*- C++ -*-=
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines functions to instantiate and register experimental
-// checks in ExprEngine.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ExprEngineInternalChecks.h"
-#include "ExprEngineExperimentalChecks.h"
-#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
-
-using namespace clang;
-using namespace ento;
-
-void ento::RegisterExperimentalChecks(ExprEngine &Eng) {
- // These are checks that never belong as internal checks
- // within ExprEngine.
- RegisterCStringChecker(Eng);
- RegisterChrootChecker(Eng);
- RegisterMallocChecker(Eng);
- RegisterPthreadLockChecker(Eng);
- RegisterStreamChecker(Eng);
- RegisterUnreachableCodeChecker(Eng);
-}
-
-void ento::RegisterExperimentalInternalChecks(ExprEngine &Eng) {
- // These are internal checks that should eventually migrate to
- // RegisterInternalChecks() once they have been further tested.
-
- // Note that this must be registered after ReturnStackAddresEngsChecker.
- RegisterReturnPointerRangeChecker(Eng);
-
- RegisterArrayBoundChecker(Eng);
- RegisterCastSizeChecker(Eng);
- RegisterCastToStructChecker(Eng);
- RegisterFixedAddressChecker(Eng);
- RegisterPointerArithChecker(Eng);
- RegisterPointerSubChecker(Eng);
-}
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/ExprEngineExperimentalChecks.h b/clang/lib/StaticAnalyzer/EntoSA/Checkers/ExprEngineExperimentalChecks.h
deleted file mode 100644
index f8359d1c5cd..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/ExprEngineExperimentalChecks.h
+++ /dev/null
@@ -1,37 +0,0 @@
-//=-- ExprEngineExperimentalChecks.h ------------------------------*- C++ -*-=
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines functions to instantiate and register experimental
-// checks in ExprEngine.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_GR_ExprEngine_EXPERIMENTAL_CHECKS
-#define LLVM_CLANG_GR_ExprEngine_EXPERIMENTAL_CHECKS
-
-namespace clang {
-
-namespace ento {
-
-class ExprEngine;
-
-void RegisterAnalyzerStatsChecker(ExprEngine &Eng);
-void RegisterChrootChecker(ExprEngine &Eng);
-void RegisterCStringChecker(ExprEngine &Eng);
-void RegisterIdempotentOperationChecker(ExprEngine &Eng);
-void RegisterMallocChecker(ExprEngine &Eng);
-void RegisterPthreadLockChecker(ExprEngine &Eng);
-void RegisterStreamChecker(ExprEngine &Eng);
-void RegisterUnreachableCodeChecker(ExprEngine &Eng);
-
-} // end GR namespace
-
-} // end clang namespace
-
-#endif
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/ExprEngineInternalChecks.h b/clang/lib/StaticAnalyzer/EntoSA/Checkers/ExprEngineInternalChecks.h
deleted file mode 100644
index f67371da0fc..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/ExprEngineInternalChecks.h
+++ /dev/null
@@ -1,59 +0,0 @@
-//=-- ExprEngineInternalChecks.h- Builtin ExprEngine Checks -----*- C++ -*-=
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines functions to instantiate and register the "built-in"
-// checks in ExprEngine.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_GR_ExprEngine_INTERNAL_CHECKS
-#define LLVM_CLANG_GR_ExprEngine_INTERNAL_CHECKS
-
-namespace clang {
-
-namespace ento {
-
-class ExprEngine;
-
-// Foundational checks that handle basic semantics.
-void RegisterAdjustedReturnValueChecker(ExprEngine &Eng);
-void RegisterArrayBoundChecker(ExprEngine &Eng);
-void RegisterArrayBoundCheckerV2(ExprEngine &Eng);
-void RegisterAttrNonNullChecker(ExprEngine &Eng);
-void RegisterBuiltinFunctionChecker(ExprEngine &Eng);
-void RegisterCallAndMessageChecker(ExprEngine &Eng);
-void RegisterCastToStructChecker(ExprEngine &Eng);
-void RegisterCastSizeChecker(ExprEngine &Eng);
-void RegisterDereferenceChecker(ExprEngine &Eng);
-void RegisterDivZeroChecker(ExprEngine &Eng);
-void RegisterFixedAddressChecker(ExprEngine &Eng);
-void RegisterNoReturnFunctionChecker(ExprEngine &Eng);
-void RegisterObjCAtSyncChecker(ExprEngine &Eng);
-void RegisterPointerArithChecker(ExprEngine &Eng);
-void RegisterPointerSubChecker(ExprEngine &Eng);
-void RegisterReturnPointerRangeChecker(ExprEngine &Eng);
-void RegisterReturnUndefChecker(ExprEngine &Eng);
-void RegisterStackAddrLeakChecker(ExprEngine &Eng);
-void RegisterUndefBranchChecker(ExprEngine &Eng);
-void RegisterUndefCapturedBlockVarChecker(ExprEngine &Eng);
-void RegisterUndefResultChecker(ExprEngine &Eng);
-void RegisterUndefinedArraySubscriptChecker(ExprEngine &Eng);
-void RegisterUndefinedAssignmentChecker(ExprEngine &Eng);
-void RegisterVLASizeChecker(ExprEngine &Eng);
-
-// API checks.
-void RegisterMacOSXAPIChecker(ExprEngine &Eng);
-void RegisterOSAtomicChecker(ExprEngine &Eng);
-void RegisterUnixAPIChecker(ExprEngine &Eng);
-
-} // end GR namespace
-
-} // end clang namespace
-
-#endif
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/FixedAddressChecker.cpp b/clang/lib/StaticAnalyzer/EntoSA/Checkers/FixedAddressChecker.cpp
deleted file mode 100644
index 77e9876d479..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/FixedAddressChecker.cpp
+++ /dev/null
@@ -1,72 +0,0 @@
-//=== FixedAddressChecker.cpp - Fixed address usage checker ----*- C++ -*--===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This files defines FixedAddressChecker, a builtin checker that checks for
-// assignment of a fixed address to a pointer.
-// This check corresponds to CWE-587.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ExprEngineInternalChecks.h"
-#include "clang/StaticAnalyzer/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
-
-using namespace clang;
-using namespace ento;
-
-namespace {
-class FixedAddressChecker
- : public CheckerVisitor<FixedAddressChecker> {
- BuiltinBug *BT;
-public:
- FixedAddressChecker() : BT(0) {}
- static void *getTag();
- void PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B);
-};
-}
-
-void *FixedAddressChecker::getTag() {
- static int x;
- return &x;
-}
-
-void FixedAddressChecker::PreVisitBinaryOperator(CheckerContext &C,
- const BinaryOperator *B) {
- // Using a fixed address is not portable because that address will probably
- // not be valid in all environments or platforms.
-
- if (B->getOpcode() != BO_Assign)
- return;
-
- QualType T = B->getType();
- if (!T->isPointerType())
- return;
-
- const GRState *state = C.getState();
-
- SVal RV = state->getSVal(B->getRHS());
-
- if (!RV.isConstant() || RV.isZeroConstant())
- return;
-
- if (ExplodedNode *N = C.generateNode()) {
- if (!BT)
- BT = new BuiltinBug("Use fixed address",
- "Using a fixed address is not portable because that "
- "address will probably not be valid in all "
- "environments or platforms.");
- RangedBugReport *R = new RangedBugReport(*BT, BT->getDescription(), N);
- R->addRange(B->getRHS()->getSourceRange());
- C.EmitReport(R);
- }
-}
-
-void ento::RegisterFixedAddressChecker(ExprEngine &Eng) {
- Eng.registerCheck(new FixedAddressChecker());
-}
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/FrontendActions.cpp b/clang/lib/StaticAnalyzer/EntoSA/Checkers/FrontendActions.cpp
deleted file mode 100644
index b0e8e5d9bb1..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/FrontendActions.cpp
+++ /dev/null
@@ -1,22 +0,0 @@
-//===--- FrontendActions.cpp ----------------------------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/StaticAnalyzer/FrontendActions.h"
-#include "clang/Frontend/CompilerInstance.h"
-#include "clang/StaticAnalyzer/AnalysisConsumer.h"
-using namespace clang;
-using namespace ento;
-
-ASTConsumer *AnalysisAction::CreateASTConsumer(CompilerInstance &CI,
- llvm::StringRef InFile) {
- return CreateAnalysisConsumer(CI.getPreprocessor(),
- CI.getFrontendOpts().OutputFile,
- CI.getAnalyzerOpts());
-}
-
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/IdempotentOperationChecker.cpp b/clang/lib/StaticAnalyzer/EntoSA/Checkers/IdempotentOperationChecker.cpp
deleted file mode 100644
index 435d3d4a48e..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/IdempotentOperationChecker.cpp
+++ /dev/null
@@ -1,834 +0,0 @@
-//==- IdempotentOperationChecker.cpp - Idempotent Operations ----*- C++ -*-==//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines a set of path-sensitive checks for idempotent and/or
-// tautological operations. Each potential operation is checked along all paths
-// to see if every path results in a pointless operation.
-// +-------------------------------------------+
-// |Table of idempotent/tautological operations|
-// +-------------------------------------------+
-//+--------------------------------------------------------------------------+
-//|Operator | x op x | x op 1 | 1 op x | x op 0 | 0 op x | x op ~0 | ~0 op x |
-//+--------------------------------------------------------------------------+
-// +, += | | | | x | x | |
-// -, -= | | | | x | -x | |
-// *, *= | | x | x | 0 | 0 | |
-// /, /= | 1 | x | | N/A | 0 | |
-// &, &= | x | | | 0 | 0 | x | x
-// |, |= | x | | | x | x | ~0 | ~0
-// ^, ^= | 0 | | | x | x | |
-// <<, <<= | | | | x | 0 | |
-// >>, >>= | | | | x | 0 | |
-// || | 1 | 1 | 1 | x | x | 1 | 1
-// && | 1 | x | x | 0 | 0 | x | x
-// = | x | | | | | |
-// == | 1 | | | | | |
-// >= | 1 | | | | | |
-// <= | 1 | | | | | |
-// > | 0 | | | | | |
-// < | 0 | | | | | |
-// != | 0 | | | | | |
-//===----------------------------------------------------------------------===//
-//
-// Things TODO:
-// - Improved error messages
-// - Handle mixed assumptions (which assumptions can belong together?)
-// - Finer grained false positive control (levels)
-// - Handling ~0 values
-
-#include "ExprEngineExperimentalChecks.h"
-#include "clang/Analysis/CFGStmtMap.h"
-#include "clang/Analysis/Analyses/PseudoConstantAnalysis.h"
-#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
-#include "clang/StaticAnalyzer/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/PathSensitive/CheckerHelpers.h"
-#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
-#include "clang/StaticAnalyzer/PathSensitive/CoreEngine.h"
-#include "clang/StaticAnalyzer/PathSensitive/SVals.h"
-#include "clang/AST/Stmt.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/SmallSet.h"
-#include "llvm/Support/ErrorHandling.h"
-#include <deque>
-
-using namespace clang;
-using namespace ento;
-
-namespace {
-class IdempotentOperationChecker
- : public CheckerVisitor<IdempotentOperationChecker> {
-public:
- static void *getTag();
- void PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B);
- void PostVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B);
- void VisitEndAnalysis(ExplodedGraph &G, BugReporter &B, ExprEngine &Eng);
-
-private:
- // Our assumption about a particular operation.
- enum Assumption { Possible = 0, Impossible, Equal, LHSis1, RHSis1, LHSis0,
- RHSis0 };
-
- void UpdateAssumption(Assumption &A, const Assumption &New);
-
- // False positive reduction methods
- static bool isSelfAssign(const Expr *LHS, const Expr *RHS);
- static bool isUnused(const Expr *E, AnalysisContext *AC);
- static bool isTruncationExtensionAssignment(const Expr *LHS,
- const Expr *RHS);
- bool PathWasCompletelyAnalyzed(const CFG *C,
- const CFGBlock *CB,
- const CFGStmtMap *CBM,
- const CoreEngine &CE);
- static bool CanVary(const Expr *Ex,
- AnalysisContext *AC);
- static bool isConstantOrPseudoConstant(const DeclRefExpr *DR,
- AnalysisContext *AC);
- static bool containsNonLocalVarDecl(const Stmt *S);
- const ExplodedNodeSet getLastRelevantNodes(const CFGBlock *Begin,
- const ExplodedNode *N);
-
- // Hash table and related data structures
- struct BinaryOperatorData {
- BinaryOperatorData() : assumption(Possible), analysisContext(0) {}
-
- Assumption assumption;
- AnalysisContext *analysisContext;
- ExplodedNodeSet explodedNodes; // Set of ExplodedNodes that refer to a
- // BinaryOperator
- };
- typedef llvm::DenseMap<const BinaryOperator *, BinaryOperatorData>
- AssumptionMap;
- AssumptionMap hash;
-
- // A class that performs reachability queries for CFGBlocks. Several internal
- // checks in this checker require reachability information. The requests all
- // tend to have a common destination, so we lazily do a predecessor search
- // from the destination node and cache the results to prevent work
- // duplication.
- class CFGReachabilityAnalysis {
- typedef llvm::SmallSet<unsigned, 32> ReachableSet;
- typedef llvm::DenseMap<unsigned, ReachableSet> ReachableMap;
- ReachableSet analyzed;
- ReachableMap reachable;
- public:
- inline bool isReachable(const CFGBlock *Src, const CFGBlock *Dst);
- private:
- void MapReachability(const CFGBlock *Dst);
- };
- CFGReachabilityAnalysis CRA;
-};
-}
-
-void *IdempotentOperationChecker::getTag() {
- static int x = 0;
- return &x;
-}
-
-void ento::RegisterIdempotentOperationChecker(ExprEngine &Eng) {
- Eng.registerCheck(new IdempotentOperationChecker());
-}
-
-void IdempotentOperationChecker::PreVisitBinaryOperator(
- CheckerContext &C,
- const BinaryOperator *B) {
- // Find or create an entry in the hash for this BinaryOperator instance.
- // If we haven't done a lookup before, it will get default initialized to
- // 'Possible'. At this stage we do not store the ExplodedNode, as it has not
- // been created yet.
- BinaryOperatorData &Data = hash[B];
- Assumption &A = Data.assumption;
- AnalysisContext *AC = C.getCurrentAnalysisContext();
- Data.analysisContext = AC;
-
- // If we already have visited this node on a path that does not contain an
- // idempotent operation, return immediately.
- if (A == Impossible)
- return;
-
- // Retrieve both sides of the operator and determine if they can vary (which
- // may mean this is a false positive.
- const Expr *LHS = B->getLHS();
- const Expr *RHS = B->getRHS();
-
- // At this stage we can calculate whether each side contains a false positive
- // that applies to all operators. We only need to calculate this the first
- // time.
- bool LHSContainsFalsePositive = false, RHSContainsFalsePositive = false;
- if (A == Possible) {
- // An expression contains a false positive if it can't vary, or if it
- // contains a known false positive VarDecl.
- LHSContainsFalsePositive = !CanVary(LHS, AC)
- || containsNonLocalVarDecl(LHS);
- RHSContainsFalsePositive = !CanVary(RHS, AC)
- || containsNonLocalVarDecl(RHS);
- }
-
- const GRState *state = C.getState();
-
- SVal LHSVal = state->getSVal(LHS);
- SVal RHSVal = state->getSVal(RHS);
-
- // If either value is unknown, we can't be 100% sure of all paths.
- if (LHSVal.isUnknownOrUndef() || RHSVal.isUnknownOrUndef()) {
- A = Impossible;
- return;
- }
- BinaryOperator::Opcode Op = B->getOpcode();
-
- // Dereference the LHS SVal if this is an assign operation
- switch (Op) {
- default:
- break;
-
- // Fall through intentional
- case BO_AddAssign:
- case BO_SubAssign:
- case BO_MulAssign:
- case BO_DivAssign:
- case BO_AndAssign:
- case BO_OrAssign:
- case BO_XorAssign:
- case BO_ShlAssign:
- case BO_ShrAssign:
- case BO_Assign:
- // Assign statements have one extra level of indirection
- if (!isa<Loc>(LHSVal)) {
- A = Impossible;
- return;
- }
- LHSVal = state->getSVal(cast<Loc>(LHSVal), LHS->getType());
- }
-
-
- // We now check for various cases which result in an idempotent operation.
-
- // x op x
- switch (Op) {
- default:
- break; // We don't care about any other operators.
-
- // Fall through intentional
- case BO_Assign:
- // x Assign x can be used to silence unused variable warnings intentionally.
- // If this is a self assignment and the variable is referenced elsewhere,
- // and the assignment is not a truncation or extension, then it is a false
- // positive.
- if (isSelfAssign(LHS, RHS)) {
- if (!isUnused(LHS, AC) && !isTruncationExtensionAssignment(LHS, RHS)) {
- UpdateAssumption(A, Equal);
- return;
- }
- else {
- A = Impossible;
- return;
- }
- }
-
- case BO_SubAssign:
- case BO_DivAssign:
- case BO_AndAssign:
- case BO_OrAssign:
- case BO_XorAssign:
- case BO_Sub:
- case BO_Div:
- case BO_And:
- case BO_Or:
- case BO_Xor:
- case BO_LOr:
- case BO_LAnd:
- case BO_EQ:
- case BO_NE:
- if (LHSVal != RHSVal || LHSContainsFalsePositive
- || RHSContainsFalsePositive)
- break;
- UpdateAssumption(A, Equal);
- return;
- }
-
- // x op 1
- switch (Op) {
- default:
- break; // We don't care about any other operators.
-
- // Fall through intentional
- case BO_MulAssign:
- case BO_DivAssign:
- case BO_Mul:
- case BO_Div:
- case BO_LOr:
- case BO_LAnd:
- if (!RHSVal.isConstant(1) || RHSContainsFalsePositive)
- break;
- UpdateAssumption(A, RHSis1);
- return;
- }
-
- // 1 op x
- switch (Op) {
- default:
- break; // We don't care about any other operators.
-
- // Fall through intentional
- case BO_MulAssign:
- case BO_Mul:
- case BO_LOr:
- case BO_LAnd:
- if (!LHSVal.isConstant(1) || LHSContainsFalsePositive)
- break;
- UpdateAssumption(A, LHSis1);
- return;
- }
-
- // x op 0
- switch (Op) {
- default:
- break; // We don't care about any other operators.
-
- // Fall through intentional
- case BO_AddAssign:
- case BO_SubAssign:
- case BO_MulAssign:
- case BO_AndAssign:
- case BO_OrAssign:
- case BO_XorAssign:
- case BO_Add:
- case BO_Sub:
- case BO_Mul:
- case BO_And:
- case BO_Or:
- case BO_Xor:
- case BO_Shl:
- case BO_Shr:
- case BO_LOr:
- case BO_LAnd:
- if (!RHSVal.isConstant(0) || RHSContainsFalsePositive)
- break;
- UpdateAssumption(A, RHSis0);
- return;
- }
-
- // 0 op x
- switch (Op) {
- default:
- break; // We don't care about any other operators.
-
- // Fall through intentional
- //case BO_AddAssign: // Common false positive
- case BO_SubAssign: // Check only if unsigned
- case BO_MulAssign:
- case BO_DivAssign:
- case BO_AndAssign:
- //case BO_OrAssign: // Common false positive
- //case BO_XorAssign: // Common false positive
- case BO_ShlAssign:
- case BO_ShrAssign:
- case BO_Add:
- case BO_Sub:
- case BO_Mul:
- case BO_Div:
- case BO_And:
- case BO_Or:
- case BO_Xor:
- case BO_Shl:
- case BO_Shr:
- case BO_LOr:
- case BO_LAnd:
- if (!LHSVal.isConstant(0) || LHSContainsFalsePositive)
- break;
- UpdateAssumption(A, LHSis0);
- return;
- }
-
- // If we get to this point, there has been a valid use of this operation.
- A = Impossible;
-}
-
-// At the post visit stage, the predecessor ExplodedNode will be the
-// BinaryOperator that was just created. We use this hook to collect the
-// ExplodedNode.
-void IdempotentOperationChecker::PostVisitBinaryOperator(
- CheckerContext &C,
- const BinaryOperator *B) {
- // Add the ExplodedNode we just visited
- BinaryOperatorData &Data = hash[B];
- assert(isa<BinaryOperator>(cast<StmtPoint>(C.getPredecessor()
- ->getLocation()).getStmt()));
- Data.explodedNodes.Add(C.getPredecessor());
-}
-
-void IdempotentOperationChecker::VisitEndAnalysis(ExplodedGraph &G,
- BugReporter &BR,
- ExprEngine &Eng) {
- BugType *BT = new BugType("Idempotent operation", "Dead code");
- // Iterate over the hash to see if we have any paths with definite
- // idempotent operations.
- for (AssumptionMap::const_iterator i = hash.begin(); i != hash.end(); ++i) {
- // Unpack the hash contents
- const BinaryOperatorData &Data = i->second;
- const Assumption &A = Data.assumption;
- AnalysisContext *AC = Data.analysisContext;
- const ExplodedNodeSet &ES = Data.explodedNodes;
-
- const BinaryOperator *B = i->first;
-
- if (A == Impossible)
- continue;
-
- // If the analyzer did not finish, check to see if we can still emit this
- // warning
- if (Eng.hasWorkRemaining()) {
- const CFGStmtMap *CBM = CFGStmtMap::Build(AC->getCFG(),
- &AC->getParentMap());
-
- // If we can trace back
- if (!PathWasCompletelyAnalyzed(AC->getCFG(),
- CBM->getBlock(B), CBM,
- Eng.getCoreEngine()))
- continue;
-
- delete CBM;
- }
-
- // Select the error message and SourceRanges to report.
- llvm::SmallString<128> buf;
- llvm::raw_svector_ostream os(buf);
- bool LHSRelevant = false, RHSRelevant = false;
- switch (A) {
- case Equal:
- LHSRelevant = true;
- RHSRelevant = true;
- if (B->getOpcode() == BO_Assign)
- os << "Assigned value is always the same as the existing value";
- else
- os << "Both operands to '" << B->getOpcodeStr()
- << "' always have the same value";
- break;
- case LHSis1:
- LHSRelevant = true;
- os << "The left operand to '" << B->getOpcodeStr() << "' is always 1";
- break;
- case RHSis1:
- RHSRelevant = true;
- os << "The right operand to '" << B->getOpcodeStr() << "' is always 1";
- break;
- case LHSis0:
- LHSRelevant = true;
- os << "The left operand to '" << B->getOpcodeStr() << "' is always 0";
- break;
- case RHSis0:
- RHSRelevant = true;
- os << "The right operand to '" << B->getOpcodeStr() << "' is always 0";
- break;
- case Possible:
- llvm_unreachable("Operation was never marked with an assumption");
- case Impossible:
- llvm_unreachable(0);
- }
-
- // Add a report for each ExplodedNode
- for (ExplodedNodeSet::iterator I = ES.begin(), E = ES.end(); I != E; ++I) {
- EnhancedBugReport *report = new EnhancedBugReport(*BT, os.str(), *I);
-
- // Add source ranges and visitor hooks
- if (LHSRelevant) {
- const Expr *LHS = i->first->getLHS();
- report->addRange(LHS->getSourceRange());
- report->addVisitorCreator(bugreporter::registerVarDeclsLastStore, LHS);
- }
- if (RHSRelevant) {
- const Expr *RHS = i->first->getRHS();
- report->addRange(i->first->getRHS()->getSourceRange());
- report->addVisitorCreator(bugreporter::registerVarDeclsLastStore, RHS);
- }
-
- BR.EmitReport(report);
- }
- }
-}
-
-// Updates the current assumption given the new assumption
-inline void IdempotentOperationChecker::UpdateAssumption(Assumption &A,
- const Assumption &New) {
-// If the assumption is the same, there is nothing to do
- if (A == New)
- return;
-
- switch (A) {
- // If we don't currently have an assumption, set it
- case Possible:
- A = New;
- return;
-
- // If we have determined that a valid state happened, ignore the new
- // assumption.
- case Impossible:
- return;
-
- // Any other case means that we had a different assumption last time. We don't
- // currently support mixing assumptions for diagnostic reasons, so we set
- // our assumption to be impossible.
- default:
- A = Impossible;
- return;
- }
-}
-
-// Check for a statement where a variable is self assigned to possibly avoid an
-// unused variable warning.
-bool IdempotentOperationChecker::isSelfAssign(const Expr *LHS, const Expr *RHS) {
- LHS = LHS->IgnoreParenCasts();
- RHS = RHS->IgnoreParenCasts();
-
- const DeclRefExpr *LHS_DR = dyn_cast<DeclRefExpr>(LHS);
- if (!LHS_DR)
- return false;
-
- const VarDecl *VD = dyn_cast<VarDecl>(LHS_DR->getDecl());
- if (!VD)
- return false;
-
- const DeclRefExpr *RHS_DR = dyn_cast<DeclRefExpr>(RHS);
- if (!RHS_DR)
- return false;
-
- if (VD != RHS_DR->getDecl())
- return false;
-
- return true;
-}
-
-// Returns true if the Expr points to a VarDecl that is not read anywhere
-// outside of self-assignments.
-bool IdempotentOperationChecker::isUnused(const Expr *E,
- AnalysisContext *AC) {
- if (!E)
- return false;
-
- const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E->IgnoreParenCasts());
- if (!DR)
- return false;
-
- const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl());
- if (!VD)
- return false;
-
- if (AC->getPseudoConstantAnalysis()->wasReferenced(VD))
- return false;
-
- return true;
-}
-
-// Check for self casts truncating/extending a variable
-bool IdempotentOperationChecker::isTruncationExtensionAssignment(
- const Expr *LHS,
- const Expr *RHS) {
-
- const DeclRefExpr *LHS_DR = dyn_cast<DeclRefExpr>(LHS->IgnoreParenCasts());
- if (!LHS_DR)
- return false;
-
- const VarDecl *VD = dyn_cast<VarDecl>(LHS_DR->getDecl());
- if (!VD)
- return false;
-
- const DeclRefExpr *RHS_DR = dyn_cast<DeclRefExpr>(RHS->IgnoreParenCasts());
- if (!RHS_DR)
- return false;
-
- if (VD != RHS_DR->getDecl())
- return false;
-
- return dyn_cast<DeclRefExpr>(RHS->IgnoreParenLValueCasts()) == NULL;
-}
-
-// Returns false if a path to this block was not completely analyzed, or true
-// otherwise.
-bool IdempotentOperationChecker::PathWasCompletelyAnalyzed(
- const CFG *C,
- const CFGBlock *CB,
- const CFGStmtMap *CBM,
- const CoreEngine &CE) {
- // Test for reachability from any aborted blocks to this block
- typedef CoreEngine::BlocksAborted::const_iterator AbortedIterator;
- for (AbortedIterator I = CE.blocks_aborted_begin(),
- E = CE.blocks_aborted_end(); I != E; ++I) {
- const BlockEdge &BE = I->first;
-
- // The destination block on the BlockEdge is the first block that was not
- // analyzed. If we can reach this block from the aborted block, then this
- // block was not completely analyzed.
- if (CRA.isReachable(BE.getDst(), CB))
- return false;
- }
-
- // For the items still on the worklist, see if they are in blocks that
- // can eventually reach 'CB'.
- class VisitWL : public WorkList::Visitor {
- const CFGStmtMap *CBM;
- const CFGBlock *TargetBlock;
- CFGReachabilityAnalysis &CRA;
- public:
- VisitWL(const CFGStmtMap *cbm, const CFGBlock *targetBlock,
- CFGReachabilityAnalysis &cra)
- : CBM(cbm), TargetBlock(targetBlock), CRA(cra) {}
- virtual bool Visit(const WorkListUnit &U) {
- ProgramPoint P = U.getNode()->getLocation();
- const CFGBlock *B = 0;
- if (StmtPoint *SP = dyn_cast<StmtPoint>(&P)) {
- B = CBM->getBlock(SP->getStmt());
- }
- else if (BlockEdge *BE = dyn_cast<BlockEdge>(&P)) {
- B = BE->getDst();
- }
- else if (BlockEntrance *BEnt = dyn_cast<BlockEntrance>(&P)) {
- B = BEnt->getBlock();
- }
- else if (BlockExit *BExit = dyn_cast<BlockExit>(&P)) {
- B = BExit->getBlock();
- }
- if (!B)
- return true;
-
- return CRA.isReachable(B, TargetBlock);
- }
- };
- VisitWL visitWL(CBM, CB, CRA);
- // Were there any items in the worklist that could potentially reach
- // this block?
- if (CE.getWorkList()->VisitItemsInWorkList(visitWL))
- return false;
-
- // Verify that this block is reachable from the entry block
- if (!CRA.isReachable(&C->getEntry(), CB))
- return false;
-
- // If we get to this point, there is no connection to the entry block or an
- // aborted block. This path is unreachable and we can report the error.
- return true;
-}
-
-// Recursive function that determines whether an expression contains any element
-// that varies. This could be due to a compile-time constant like sizeof. An
-// expression may also involve a variable that behaves like a constant. The
-// function returns true if the expression varies, and false otherwise.
-bool IdempotentOperationChecker::CanVary(const Expr *Ex,
- AnalysisContext *AC) {
- // Parentheses and casts are irrelevant here
- Ex = Ex->IgnoreParenCasts();
-
- if (Ex->getLocStart().isMacroID())
- return false;
-
- switch (Ex->getStmtClass()) {
- // Trivially true cases
- case Stmt::ArraySubscriptExprClass:
- case Stmt::MemberExprClass:
- case Stmt::StmtExprClass:
- case Stmt::CallExprClass:
- case Stmt::VAArgExprClass:
- case Stmt::ShuffleVectorExprClass:
- return true;
- default:
- return true;
-
- // Trivially false cases
- case Stmt::IntegerLiteralClass:
- case Stmt::CharacterLiteralClass:
- case Stmt::FloatingLiteralClass:
- case Stmt::PredefinedExprClass:
- case Stmt::ImaginaryLiteralClass:
- case Stmt::StringLiteralClass:
- case Stmt::OffsetOfExprClass:
- case Stmt::CompoundLiteralExprClass:
- case Stmt::AddrLabelExprClass:
- case Stmt::BinaryTypeTraitExprClass:
- case Stmt::GNUNullExprClass:
- case Stmt::InitListExprClass:
- case Stmt::DesignatedInitExprClass:
- case Stmt::BlockExprClass:
- case Stmt::BlockDeclRefExprClass:
- return false;
-
- // Cases requiring custom logic
- case Stmt::SizeOfAlignOfExprClass: {
- const SizeOfAlignOfExpr *SE = cast<const SizeOfAlignOfExpr>(Ex);
- if (!SE->isSizeOf())
- return false;
- return SE->getTypeOfArgument()->isVariableArrayType();
- }
- case Stmt::DeclRefExprClass:
- // Check for constants/pseudoconstants
- return !isConstantOrPseudoConstant(cast<DeclRefExpr>(Ex), AC);
-
- // The next cases require recursion for subexpressions
- case Stmt::BinaryOperatorClass: {
- const BinaryOperator *B = cast<const BinaryOperator>(Ex);
-
- // Exclude cases involving pointer arithmetic. These are usually
- // false positives.
- if (B->getOpcode() == BO_Sub || B->getOpcode() == BO_Add)
- if (B->getLHS()->getType()->getAs<PointerType>())
- return false;
-
- return CanVary(B->getRHS(), AC)
- || CanVary(B->getLHS(), AC);
- }
- case Stmt::UnaryOperatorClass: {
- const UnaryOperator *U = cast<const UnaryOperator>(Ex);
- // Handle trivial case first
- switch (U->getOpcode()) {
- case UO_Extension:
- return false;
- default:
- return CanVary(U->getSubExpr(), AC);
- }
- }
- case Stmt::ChooseExprClass:
- return CanVary(cast<const ChooseExpr>(Ex)->getChosenSubExpr(
- AC->getASTContext()), AC);
- case Stmt::ConditionalOperatorClass:
- return CanVary(cast<const ConditionalOperator>(Ex)->getCond(), AC);
- }
-}
-
-// Returns true if a DeclRefExpr is or behaves like a constant.
-bool IdempotentOperationChecker::isConstantOrPseudoConstant(
- const DeclRefExpr *DR,
- AnalysisContext *AC) {
- // Check if the type of the Decl is const-qualified
- if (DR->getType().isConstQualified())
- return true;
-
- // Check for an enum
- if (isa<EnumConstantDecl>(DR->getDecl()))
- return true;
-
- const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl());
- if (!VD)
- return true;
-
- // Check if the Decl behaves like a constant. This check also takes care of
- // static variables, which can only change between function calls if they are
- // modified in the AST.
- PseudoConstantAnalysis *PCA = AC->getPseudoConstantAnalysis();
- if (PCA->isPseudoConstant(VD))
- return true;
-
- return false;
-}
-
-// Recursively find any substatements containing VarDecl's with storage other
-// than local
-bool IdempotentOperationChecker::containsNonLocalVarDecl(const Stmt *S) {
- const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(S);
-
- if (DR)
- if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()))
- if (!VD->hasLocalStorage())
- return true;
-
- for (Stmt::const_child_iterator I = S->child_begin(); I != S->child_end();
- ++I)
- if (const Stmt *child = *I)
- if (containsNonLocalVarDecl(child))
- return true;
-
- return false;
-}
-
-// Returns the successor nodes of N whose CFGBlocks cannot reach N's CFGBlock.
-// This effectively gives us a set of points in the ExplodedGraph where
-// subsequent execution could not affect the idempotent operation on this path.
-// This is useful for displaying paths after the point of the error, providing
-// an example of how this idempotent operation cannot change.
-const ExplodedNodeSet IdempotentOperationChecker::getLastRelevantNodes(
- const CFGBlock *Begin, const ExplodedNode *N) {
- std::deque<const ExplodedNode *> WorkList;
- llvm::SmallPtrSet<const ExplodedNode *, 32> Visited;
- ExplodedNodeSet Result;
-
- WorkList.push_back(N);
-
- while (!WorkList.empty()) {
- const ExplodedNode *Head = WorkList.front();
- WorkList.pop_front();
- Visited.insert(Head);
-
- const ProgramPoint &PP = Head->getLocation();
- if (const BlockEntrance *BE = dyn_cast<BlockEntrance>(&PP)) {
- // Get the CFGBlock and test the reachability
- const CFGBlock *CB = BE->getBlock();
-
- // If we cannot reach the beginning CFGBlock from this block, then we are
- // finished
- if (!CRA.isReachable(CB, Begin)) {
- Result.Add(const_cast<ExplodedNode *>(Head));
- continue;
- }
- }
-
- // Add unvisited children to the worklist
- for (ExplodedNode::const_succ_iterator I = Head->succ_begin(),
- E = Head->succ_end(); I != E; ++I)
- if (!Visited.count(*I))
- WorkList.push_back(*I);
- }
-
- // Return the ExplodedNodes that were found
- return Result;
-}
-
-bool IdempotentOperationChecker::CFGReachabilityAnalysis::isReachable(
- const CFGBlock *Src,
- const CFGBlock *Dst) {
- const unsigned DstBlockID = Dst->getBlockID();
-
- // If we haven't analyzed the destination node, run the analysis now
- if (!analyzed.count(DstBlockID)) {
- MapReachability(Dst);
- analyzed.insert(DstBlockID);
- }
-
- // Return the cached result
- return reachable[DstBlockID].count(Src->getBlockID());
-}
-
-// Maps reachability to a common node by walking the predecessors of the
-// destination node.
-void IdempotentOperationChecker::CFGReachabilityAnalysis::MapReachability(
- const CFGBlock *Dst) {
- std::deque<const CFGBlock *> WorkList;
- // Maintain a visited list to ensure we don't get stuck on cycles
- llvm::SmallSet<unsigned, 32> Visited;
- ReachableSet &DstReachability = reachable[Dst->getBlockID()];
-
- // Start searching from the destination node, since we commonly will perform
- // multiple queries relating to a destination node.
- WorkList.push_back(Dst);
-
- bool firstRun = true;
- while (!WorkList.empty()) {
- const CFGBlock *Head = WorkList.front();
- WorkList.pop_front();
- Visited.insert(Head->getBlockID());
-
- // Update reachability information for this node -> Dst
- if (!firstRun)
- // Don't insert Dst -> Dst unless it was a predecessor of itself
- DstReachability.insert(Head->getBlockID());
- else
- firstRun = false;
-
- // Add the predecessors to the worklist unless we have already visited them
- for (CFGBlock::const_pred_iterator I = Head->pred_begin();
- I != Head->pred_end(); ++I)
- if (!Visited.count((*I)->getBlockID()))
- WorkList.push_back(*I);
- }
-}
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/LLVMConventionsChecker.cpp b/clang/lib/StaticAnalyzer/EntoSA/Checkers/LLVMConventionsChecker.cpp
deleted file mode 100644
index eefad95f215..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/LLVMConventionsChecker.cpp
+++ /dev/null
@@ -1,313 +0,0 @@
-//=== LLVMConventionsChecker.cpp - Check LLVM codebase conventions ---*- C++ -*-
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This defines LLVMConventionsChecker, a bunch of small little checks
-// for checking specific coding conventions in the LLVM/Clang codebase.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/AST/DeclTemplate.h"
-#include "clang/AST/StmtVisitor.h"
-#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
-#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
-#include <string>
-#include "llvm/ADT/StringRef.h"
-
-using namespace clang;
-using namespace ento;
-
-//===----------------------------------------------------------------------===//
-// Generic type checking routines.
-//===----------------------------------------------------------------------===//
-
-static bool IsLLVMStringRef(QualType T) {
- const RecordType *RT = T->getAs<RecordType>();
- if (!RT)
- return false;
-
- return llvm::StringRef(QualType(RT, 0).getAsString()) ==
- "class llvm::StringRef";
-}
-
-/// Check whether the declaration is semantically inside the top-level
-/// namespace named by ns.
-static bool InNamespace(const Decl *D, llvm::StringRef NS) {
- const DeclContext *DC = D->getDeclContext();
- const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(D->getDeclContext());
- if (!ND)
- return false;
- const IdentifierInfo *II = ND->getIdentifier();
- if (!II || !II->getName().equals(NS))
- return false;
- DC = ND->getDeclContext();
- return isa<TranslationUnitDecl>(DC);
-}
-
-static bool IsStdString(QualType T) {
- if (const ElaboratedType *QT = T->getAs<ElaboratedType>())
- T = QT->getNamedType();
-
- const TypedefType *TT = T->getAs<TypedefType>();
- if (!TT)
- return false;
-
- const TypedefDecl *TD = TT->getDecl();
-
- if (!InNamespace(TD, "std"))
- return false;
-
- return TD->getName() == "string";
-}
-
-static bool IsClangType(const RecordDecl *RD) {
- return RD->getName() == "Type" && InNamespace(RD, "clang");
-}
-
-static bool IsClangDecl(const RecordDecl *RD) {
- return RD->getName() == "Decl" && InNamespace(RD, "clang");
-}
-
-static bool IsClangStmt(const RecordDecl *RD) {
- return RD->getName() == "Stmt" && InNamespace(RD, "clang");
-}
-
-static bool IsClangAttr(const RecordDecl *RD) {
- return RD->getName() == "Attr" && InNamespace(RD, "clang");
-}
-
-static bool IsStdVector(QualType T) {
- const TemplateSpecializationType *TS = T->getAs<TemplateSpecializationType>();
- if (!TS)
- return false;
-
- TemplateName TM = TS->getTemplateName();
- TemplateDecl *TD = TM.getAsTemplateDecl();
-
- if (!TD || !InNamespace(TD, "std"))
- return false;
-
- return TD->getName() == "vector";
-}
-
-static bool IsSmallVector(QualType T) {
- const TemplateSpecializationType *TS = T->getAs<TemplateSpecializationType>();
- if (!TS)
- return false;
-
- TemplateName TM = TS->getTemplateName();
- TemplateDecl *TD = TM.getAsTemplateDecl();
-
- if (!TD || !InNamespace(TD, "llvm"))
- return false;
-
- return TD->getName() == "SmallVector";
-}
-
-//===----------------------------------------------------------------------===//
-// CHECK: a llvm::StringRef should not be bound to a temporary std::string whose
-// lifetime is shorter than the StringRef's.
-//===----------------------------------------------------------------------===//
-
-namespace {
-class StringRefCheckerVisitor : public StmtVisitor<StringRefCheckerVisitor> {
- BugReporter &BR;
-public:
- StringRefCheckerVisitor(BugReporter &br) : BR(br) {}
- void VisitChildren(Stmt *S) {
- for (Stmt::child_iterator I = S->child_begin(), E = S->child_end() ;
- I != E; ++I)
- if (Stmt *child = *I)
- Visit(child);
- }
- void VisitStmt(Stmt *S) { VisitChildren(S); }
- void VisitDeclStmt(DeclStmt *DS);
-private:
- void VisitVarDecl(VarDecl *VD);
-};
-} // end anonymous namespace
-
-static void CheckStringRefAssignedTemporary(const Decl *D, BugReporter &BR) {
- StringRefCheckerVisitor walker(BR);
- walker.Visit(D->getBody());
-}
-
-void StringRefCheckerVisitor::VisitDeclStmt(DeclStmt *S) {
- VisitChildren(S);
-
- for (DeclStmt::decl_iterator I = S->decl_begin(), E = S->decl_end();I!=E; ++I)
- if (VarDecl *VD = dyn_cast<VarDecl>(*I))
- VisitVarDecl(VD);
-}
-
-void StringRefCheckerVisitor::VisitVarDecl(VarDecl *VD) {
- Expr *Init = VD->getInit();
- if (!Init)
- return;
-
- // Pattern match for:
- // llvm::StringRef x = call() (where call returns std::string)
- if (!IsLLVMStringRef(VD->getType()))
- return;
- ExprWithCleanups *Ex1 = dyn_cast<ExprWithCleanups>(Init);
- if (!Ex1)
- return;
- CXXConstructExpr *Ex2 = dyn_cast<CXXConstructExpr>(Ex1->getSubExpr());
- if (!Ex2 || Ex2->getNumArgs() != 1)
- return;
- ImplicitCastExpr *Ex3 = dyn_cast<ImplicitCastExpr>(Ex2->getArg(0));
- if (!Ex3)
- return;
- CXXConstructExpr *Ex4 = dyn_cast<CXXConstructExpr>(Ex3->getSubExpr());
- if (!Ex4 || Ex4->getNumArgs() != 1)
- return;
- ImplicitCastExpr *Ex5 = dyn_cast<ImplicitCastExpr>(Ex4->getArg(0));
- if (!Ex5)
- return;
- CXXBindTemporaryExpr *Ex6 = dyn_cast<CXXBindTemporaryExpr>(Ex5->getSubExpr());
- if (!Ex6 || !IsStdString(Ex6->getType()))
- return;
-
- // Okay, badness! Report an error.
- const char *desc = "StringRef should not be bound to temporary "
- "std::string that it outlives";
-
- BR.EmitBasicReport(desc, "LLVM Conventions", desc,
- VD->getLocStart(), Init->getSourceRange());
-}
-
-//===----------------------------------------------------------------------===//
-// CHECK: Clang AST nodes should not have fields that can allocate
-// memory.
-//===----------------------------------------------------------------------===//
-
-static bool AllocatesMemory(QualType T) {
- return IsStdVector(T) || IsStdString(T) || IsSmallVector(T);
-}
-
-// This type checking could be sped up via dynamic programming.
-static bool IsPartOfAST(const CXXRecordDecl *R) {
- if (IsClangStmt(R) || IsClangType(R) || IsClangDecl(R) || IsClangAttr(R))
- return true;
-
- for (CXXRecordDecl::base_class_const_iterator I = R->bases_begin(),
- E = R->bases_end(); I!=E; ++I) {
- CXXBaseSpecifier BS = *I;
- QualType T = BS.getType();
- if (const RecordType *baseT = T->getAs<RecordType>()) {
- CXXRecordDecl *baseD = cast<CXXRecordDecl>(baseT->getDecl());
- if (IsPartOfAST(baseD))
- return true;
- }
- }
-
- return false;
-}
-
-namespace {
-class ASTFieldVisitor {
- llvm::SmallVector<FieldDecl*, 10> FieldChain;
- CXXRecordDecl *Root;
- BugReporter &BR;
-public:
- ASTFieldVisitor(CXXRecordDecl *root, BugReporter &br)
- : Root(root), BR(br) {}
-
- void Visit(FieldDecl *D);
- void ReportError(QualType T);
-};
-} // end anonymous namespace
-
-static void CheckASTMemory(CXXRecordDecl *R, BugReporter &BR) {
- if (!IsPartOfAST(R))
- return;
-
- for (RecordDecl::field_iterator I = R->field_begin(), E = R->field_end();
- I != E; ++I) {
- ASTFieldVisitor walker(R, BR);
- walker.Visit(*I);
- }
-}
-
-void ASTFieldVisitor::Visit(FieldDecl *D) {
- FieldChain.push_back(D);
-
- QualType T = D->getType();
-
- if (AllocatesMemory(T))
- ReportError(T);
-
- if (const RecordType *RT = T->getAs<RecordType>()) {
- const RecordDecl *RD = RT->getDecl()->getDefinition();
- for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
- I != E; ++I)
- Visit(*I);
- }
-
- FieldChain.pop_back();
-}
-
-void ASTFieldVisitor::ReportError(QualType T) {
- llvm::SmallString<1024> buf;
- llvm::raw_svector_ostream os(buf);
-
- os << "AST class '" << Root->getName() << "' has a field '"
- << FieldChain.front()->getName() << "' that allocates heap memory";
- if (FieldChain.size() > 1) {
- os << " via the following chain: ";
- bool isFirst = true;
- for (llvm::SmallVectorImpl<FieldDecl*>::iterator I=FieldChain.begin(),
- E=FieldChain.end(); I!=E; ++I) {
- if (!isFirst)
- os << '.';
- else
- isFirst = false;
- os << (*I)->getName();
- }
- }
- os << " (type " << FieldChain.back()->getType().getAsString() << ")";
- os.flush();
-
- // Note that this will fire for every translation unit that uses this
- // class. This is suboptimal, but at least scan-build will merge
- // duplicate HTML reports. In the future we need a unified way of merging
- // duplicate reports across translation units. For C++ classes we cannot
- // just report warnings when we see an out-of-line method definition for a
- // class, as that heuristic doesn't always work (the complete definition of
- // the class may be in the header file, for example).
- BR.EmitBasicReport("AST node allocates heap memory", "LLVM Conventions",
- os.str(), FieldChain.front()->getLocStart());
-}
-
-//===----------------------------------------------------------------------===//
-// Entry point for all checks.
-//===----------------------------------------------------------------------===//
-
-static void ScanCodeDecls(DeclContext *DC, BugReporter &BR) {
- for (DeclContext::decl_iterator I=DC->decls_begin(), E=DC->decls_end();
- I!=E ; ++I) {
-
- Decl *D = *I;
-
- if (D->hasBody())
- CheckStringRefAssignedTemporary(D, BR);
-
- if (CXXRecordDecl *R = dyn_cast<CXXRecordDecl>(D))
- if (R->isDefinition())
- CheckASTMemory(R, BR);
-
- if (DeclContext *DC_child = dyn_cast<DeclContext>(D))
- ScanCodeDecls(DC_child, BR);
- }
-}
-
-void ento::CheckLLVMConventions(TranslationUnitDecl &TU,
- BugReporter &BR) {
- ScanCodeDecls(&TU, BR);
-}
-
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/MacOSXAPIChecker.cpp b/clang/lib/StaticAnalyzer/EntoSA/Checkers/MacOSXAPIChecker.cpp
deleted file mode 100644
index 44887fa7690..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/MacOSXAPIChecker.cpp
+++ /dev/null
@@ -1,142 +0,0 @@
-// MacOSXAPIChecker.h - Checks proper use of various MacOS X APIs --*- C++ -*-//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This defines MacOSXAPIChecker, which is an assortment of checks on calls
-// to various, widely used Mac OS X functions.
-//
-// FIXME: What's currently in BasicObjCFoundationChecks.cpp should be migrated
-// to here, using the new Checker interface.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ExprEngineInternalChecks.h"
-#include "clang/Basic/TargetInfo.h"
-#include "clang/StaticAnalyzer/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
-#include "clang/StaticAnalyzer/PathSensitive/GRStateTrait.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/StringSwitch.h"
-#include "llvm/Support/raw_ostream.h"
-
-using namespace clang;
-using namespace ento;
-
-namespace {
-class MacOSXAPIChecker : public CheckerVisitor<MacOSXAPIChecker> {
- enum SubChecks {
- DispatchOnce = 0,
- DispatchOnceF,
- NumChecks
- };
-
- BugType *BTypes[NumChecks];
-
-public:
- MacOSXAPIChecker() { memset(BTypes, 0, sizeof(*BTypes) * NumChecks); }
- static void *getTag() { static unsigned tag = 0; return &tag; }
-
- void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
-};
-} //end anonymous namespace
-
-void ento::RegisterMacOSXAPIChecker(ExprEngine &Eng) {
- if (Eng.getContext().Target.getTriple().getVendor() == llvm::Triple::Apple)
- Eng.registerCheck(new MacOSXAPIChecker());
-}
-
-//===----------------------------------------------------------------------===//
-// dispatch_once and dispatch_once_f
-//===----------------------------------------------------------------------===//
-
-static void CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
- BugType *&BT, const IdentifierInfo *FI) {
-
- if (!BT) {
- llvm::SmallString<128> S;
- llvm::raw_svector_ostream os(S);
- os << "Improper use of '" << FI->getName() << '\'';
- BT = new BugType(os.str(), "Mac OS X API");
- }
-
- if (CE->getNumArgs() < 1)
- return;
-
- // Check if the first argument is stack allocated. If so, issue a warning
- // because that's likely to be bad news.
- const GRState *state = C.getState();
- const MemRegion *R = state->getSVal(CE->getArg(0)).getAsRegion();
- if (!R || !isa<StackSpaceRegion>(R->getMemorySpace()))
- return;
-
- ExplodedNode *N = C.generateSink(state);
- if (!N)
- return;
-
- llvm::SmallString<256> S;
- llvm::raw_svector_ostream os(S);
- os << "Call to '" << FI->getName() << "' uses";
- if (const VarRegion *VR = dyn_cast<VarRegion>(R))
- os << " the local variable '" << VR->getDecl()->getName() << '\'';
- else
- os << " stack allocated memory";
- os << " for the predicate value. Using such transient memory for "
- "the predicate is potentially dangerous.";
- if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getMemorySpace()))
- os << " Perhaps you intended to declare the variable as 'static'?";
-
- EnhancedBugReport *report = new EnhancedBugReport(*BT, os.str(), N);
- report->addRange(CE->getArg(0)->getSourceRange());
- C.EmitReport(report);
-}
-
-//===----------------------------------------------------------------------===//
-// Central dispatch function.
-//===----------------------------------------------------------------------===//
-
-typedef void (*SubChecker)(CheckerContext &C, const CallExpr *CE, BugType *&BT,
- const IdentifierInfo *FI);
-namespace {
- class SubCheck {
- SubChecker SC;
- BugType **BT;
- public:
- SubCheck(SubChecker sc, BugType *& bt) : SC(sc), BT(&bt) {}
- SubCheck() : SC(NULL), BT(NULL) {}
-
- void run(CheckerContext &C, const CallExpr *CE,
- const IdentifierInfo *FI) const {
- if (SC)
- SC(C, CE, *BT, FI);
- }
- };
-} // end anonymous namespace
-
-void MacOSXAPIChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
- // FIXME: Mostly copy and paste from UnixAPIChecker. Should refactor.
- const GRState *state = C.getState();
- const Expr *Callee = CE->getCallee();
- const FunctionTextRegion *Fn =
- dyn_cast_or_null<FunctionTextRegion>(state->getSVal(Callee).getAsRegion());
-
- if (!Fn)
- return;
-
- const IdentifierInfo *FI = Fn->getDecl()->getIdentifier();
- if (!FI)
- return;
-
- const SubCheck &SC =
- llvm::StringSwitch<SubCheck>(FI->getName())
- .Case("dispatch_once", SubCheck(CheckDispatchOnce, BTypes[DispatchOnce]))
- .Case("dispatch_once_f", SubCheck(CheckDispatchOnce,
- BTypes[DispatchOnceF]))
- .Default(SubCheck());
-
- SC.run(C, CE, FI);
-}
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/Makefile b/clang/lib/StaticAnalyzer/EntoSA/Checkers/Makefile
deleted file mode 100644
index d4de35c1f58..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/Makefile
+++ /dev/null
@@ -1,17 +0,0 @@
-##===- clang/lib/Checker/Makefile --------------------------*- Makefile -*-===##
-#
-# The LLVM Compiler Infrastructure
-#
-# This file is distributed under the University of Illinois Open Source
-# License. See LICENSE.TXT for details.
-#
-##===----------------------------------------------------------------------===##
-#
-# This implements analyses built on top of source-level CFGs.
-#
-##===----------------------------------------------------------------------===##
-
-CLANG_LEVEL := ../../..
-LIBRARYNAME := clangStaticAnalyzerCheckers
-
-include $(CLANG_LEVEL)/Makefile
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/EntoSA/Checkers/MallocChecker.cpp
deleted file mode 100644
index 42243cb5251..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/MallocChecker.cpp
+++ /dev/null
@@ -1,733 +0,0 @@
-//=== MallocChecker.cpp - A malloc/free checker -------------------*- C++ -*--//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines malloc/free checker, which checks for potential memory
-// leaks, double free, and use-after-free problems.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ExprEngineExperimentalChecks.h"
-#include "clang/StaticAnalyzer/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
-#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
-#include "clang/StaticAnalyzer/PathSensitive/GRStateTrait.h"
-#include "clang/StaticAnalyzer/PathSensitive/SymbolManager.h"
-#include "llvm/ADT/ImmutableMap.h"
-using namespace clang;
-using namespace ento;
-
-namespace {
-
-class RefState {
- enum Kind { AllocateUnchecked, AllocateFailed, Released, Escaped,
- Relinquished } K;
- const Stmt *S;
-
-public:
- RefState(Kind k, const Stmt *s) : K(k), S(s) {}
-
- bool isAllocated() const { return K == AllocateUnchecked; }
- //bool isFailed() const { return K == AllocateFailed; }
- bool isReleased() const { return K == Released; }
- //bool isEscaped() const { return K == Escaped; }
- //bool isRelinquished() const { return K == Relinquished; }
-
- bool operator==(const RefState &X) const {
- return K == X.K && S == X.S;
- }
-
- static RefState getAllocateUnchecked(const Stmt *s) {
- return RefState(AllocateUnchecked, s);
- }
- static RefState getAllocateFailed() {
- return RefState(AllocateFailed, 0);
- }
- static RefState getReleased(const Stmt *s) { return RefState(Released, s); }
- static RefState getEscaped(const Stmt *s) { return RefState(Escaped, s); }
- static RefState getRelinquished(const Stmt *s) {
- return RefState(Relinquished, s);
- }
-
- void Profile(llvm::FoldingSetNodeID &ID) const {
- ID.AddInteger(K);
- ID.AddPointer(S);
- }
-};
-
-class RegionState {};
-
-class MallocChecker : public CheckerVisitor<MallocChecker> {
- BuiltinBug *BT_DoubleFree;
- BuiltinBug *BT_Leak;
- BuiltinBug *BT_UseFree;
- BuiltinBug *BT_UseRelinquished;
- BuiltinBug *BT_BadFree;
- IdentifierInfo *II_malloc, *II_free, *II_realloc, *II_calloc;
-
-public:
- MallocChecker()
- : BT_DoubleFree(0), BT_Leak(0), BT_UseFree(0), BT_UseRelinquished(0),
- BT_BadFree(0),
- II_malloc(0), II_free(0), II_realloc(0), II_calloc(0) {}
- static void *getTag();
- bool evalCallExpr(CheckerContext &C, const CallExpr *CE);
- void evalDeadSymbols(CheckerContext &C, SymbolReaper &SymReaper);
- void evalEndPath(EndPathNodeBuilder &B, void *tag, ExprEngine &Eng);
- void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S);
- const GRState *evalAssume(const GRState *state, SVal Cond, bool Assumption,
- bool *respondsToCallback);
- void visitLocation(CheckerContext &C, const Stmt *S, SVal l);
- virtual void PreVisitBind(CheckerContext &C, const Stmt *StoreE,
- SVal location, SVal val);
-
-private:
- void MallocMem(CheckerContext &C, const CallExpr *CE);
- void MallocMemReturnsAttr(CheckerContext &C, const CallExpr *CE,
- const OwnershipAttr* Att);
- const GRState *MallocMemAux(CheckerContext &C, const CallExpr *CE,
- const Expr *SizeEx, SVal Init,
- const GRState *state) {
- return MallocMemAux(C, CE, state->getSVal(SizeEx), Init, state);
- }
- const GRState *MallocMemAux(CheckerContext &C, const CallExpr *CE,
- SVal SizeEx, SVal Init,
- const GRState *state);
-
- void FreeMem(CheckerContext &C, const CallExpr *CE);
- void FreeMemAttr(CheckerContext &C, const CallExpr *CE,
- const OwnershipAttr* Att);
- const GRState *FreeMemAux(CheckerContext &C, const CallExpr *CE,
- const GRState *state, unsigned Num, bool Hold);
-
- void ReallocMem(CheckerContext &C, const CallExpr *CE);
- void CallocMem(CheckerContext &C, const CallExpr *CE);
-
- bool SummarizeValue(llvm::raw_ostream& os, SVal V);
- bool SummarizeRegion(llvm::raw_ostream& os, const MemRegion *MR);
- void ReportBadFree(CheckerContext &C, SVal ArgVal, SourceRange range);
-};
-} // end anonymous namespace
-
-typedef llvm::ImmutableMap<SymbolRef, RefState> RegionStateTy;
-
-namespace clang {
-namespace ento {
- template <>
- struct GRStateTrait<RegionState>
- : public GRStatePartialTrait<RegionStateTy> {
- static void *GDMIndex() { return MallocChecker::getTag(); }
- };
-}
-}
-
-void ento::RegisterMallocChecker(ExprEngine &Eng) {
- Eng.registerCheck(new MallocChecker());
-}
-
-void *MallocChecker::getTag() {
- static int x;
- return &x;
-}
-
-bool MallocChecker::evalCallExpr(CheckerContext &C, const CallExpr *CE) {
- const GRState *state = C.getState();
- const Expr *Callee = CE->getCallee();
- SVal L = state->getSVal(Callee);
-
- const FunctionDecl *FD = L.getAsFunctionDecl();
- if (!FD)
- return false;
-
- ASTContext &Ctx = C.getASTContext();
- if (!II_malloc)
- II_malloc = &Ctx.Idents.get("malloc");
- if (!II_free)
- II_free = &Ctx.Idents.get("free");
- if (!II_realloc)
- II_realloc = &Ctx.Idents.get("realloc");
- if (!II_calloc)
- II_calloc = &Ctx.Idents.get("calloc");
-
- if (FD->getIdentifier() == II_malloc) {
- MallocMem(C, CE);
- return true;
- }
-
- if (FD->getIdentifier() == II_free) {
- FreeMem(C, CE);
- return true;
- }
-
- if (FD->getIdentifier() == II_realloc) {
- ReallocMem(C, CE);
- return true;
- }
-
- if (FD->getIdentifier() == II_calloc) {
- CallocMem(C, CE);
- return true;
- }
-
- // Check all the attributes, if there are any.
- // There can be multiple of these attributes.
- bool rv = false;
- if (FD->hasAttrs()) {
- for (specific_attr_iterator<OwnershipAttr>
- i = FD->specific_attr_begin<OwnershipAttr>(),
- e = FD->specific_attr_end<OwnershipAttr>();
- i != e; ++i) {
- switch ((*i)->getOwnKind()) {
- case OwnershipAttr::Returns: {
- MallocMemReturnsAttr(C, CE, *i);
- rv = true;
- break;
- }
- case OwnershipAttr::Takes:
- case OwnershipAttr::Holds: {
- FreeMemAttr(C, CE, *i);
- rv = true;
- break;
- }
- default:
- break;
- }
- }
- }
- return rv;
-}
-
-void MallocChecker::MallocMem(CheckerContext &C, const CallExpr *CE) {
- const GRState *state = MallocMemAux(C, CE, CE->getArg(0), UndefinedVal(),
- C.getState());
- C.addTransition(state);
-}
-
-void MallocChecker::MallocMemReturnsAttr(CheckerContext &C, const CallExpr *CE,
- const OwnershipAttr* Att) {
- if (Att->getModule() != "malloc")
- return;
-
- OwnershipAttr::args_iterator I = Att->args_begin(), E = Att->args_end();
- if (I != E) {
- const GRState *state =
- MallocMemAux(C, CE, CE->getArg(*I), UndefinedVal(), C.getState());
- C.addTransition(state);
- return;
- }
- const GRState *state = MallocMemAux(C, CE, UnknownVal(), UndefinedVal(),
- C.getState());
- C.addTransition(state);
-}
-
-const GRState *MallocChecker::MallocMemAux(CheckerContext &C,
- const CallExpr *CE,
- SVal Size, SVal Init,
- const GRState *state) {
- unsigned Count = C.getNodeBuilder().getCurrentBlockCount();
- SValBuilder &svalBuilder = C.getSValBuilder();
-
- // Set the return value.
- SVal retVal = svalBuilder.getConjuredSymbolVal(NULL, CE, CE->getType(), Count);
- state = state->BindExpr(CE, retVal);
-
- // Fill the region with the initialization value.
- state = state->bindDefault(retVal, Init);
-
- // Set the region's extent equal to the Size parameter.
- const SymbolicRegion *R = cast<SymbolicRegion>(retVal.getAsRegion());
- DefinedOrUnknownSVal Extent = R->getExtent(svalBuilder);
- DefinedOrUnknownSVal DefinedSize = cast<DefinedOrUnknownSVal>(Size);
- DefinedOrUnknownSVal extentMatchesSize =
- svalBuilder.evalEQ(state, Extent, DefinedSize);
-
- state = state->assume(extentMatchesSize, true);
- assert(state);
-
- SymbolRef Sym = retVal.getAsLocSymbol();
- assert(Sym);
-
- // Set the symbol's state to Allocated.
- return state->set<RegionState>(Sym, RefState::getAllocateUnchecked(CE));
-}
-
-void MallocChecker::FreeMem(CheckerContext &C, const CallExpr *CE) {
- const GRState *state = FreeMemAux(C, CE, C.getState(), 0, false);
-
- if (state)
- C.addTransition(state);
-}
-
-void MallocChecker::FreeMemAttr(CheckerContext &C, const CallExpr *CE,
- const OwnershipAttr* Att) {
- if (Att->getModule() != "malloc")
- return;
-
- for (OwnershipAttr::args_iterator I = Att->args_begin(), E = Att->args_end();
- I != E; ++I) {
- const GRState *state = FreeMemAux(C, CE, C.getState(), *I,
- Att->getOwnKind() == OwnershipAttr::Holds);
- if (state)
- C.addTransition(state);
- }
-}
-
-const GRState *MallocChecker::FreeMemAux(CheckerContext &C, const CallExpr *CE,
- const GRState *state, unsigned Num,
- bool Hold) {
- const Expr *ArgExpr = CE->getArg(Num);
- SVal ArgVal = state->getSVal(ArgExpr);
-
- DefinedOrUnknownSVal location = cast<DefinedOrUnknownSVal>(ArgVal);
-
- // Check for null dereferences.
- if (!isa<Loc>(location))
- return state;
-
- // FIXME: Technically using 'Assume' here can result in a path
- // bifurcation. In such cases we need to return two states, not just one.
- const GRState *notNullState, *nullState;
- llvm::tie(notNullState, nullState) = state->assume(location);
-
- // The explicit NULL case, no operation is performed.
- if (nullState && !notNullState)
- return nullState;
-
- assert(notNullState);
-
- // Unknown values could easily be okay
- // Undefined values are handled elsewhere
- if (ArgVal.isUnknownOrUndef())
- return notNullState;
-
- const MemRegion *R = ArgVal.getAsRegion();
-
- // Nonlocs can't be freed, of course.
- // Non-region locations (labels and fixed addresses) also shouldn't be freed.
- if (!R) {
- ReportBadFree(C, ArgVal, ArgExpr->getSourceRange());
- return NULL;
- }
-
- R = R->StripCasts();
-
- // Blocks might show up as heap data, but should not be free()d
- if (isa<BlockDataRegion>(R)) {
- ReportBadFree(C, ArgVal, ArgExpr->getSourceRange());
- return NULL;
- }
-
- const MemSpaceRegion *MS = R->getMemorySpace();
-
- // Parameters, locals, statics, and globals shouldn't be freed.
- if (!(isa<UnknownSpaceRegion>(MS) || isa<HeapSpaceRegion>(MS))) {
- // FIXME: at the time this code was written, malloc() regions were
- // represented by conjured symbols, which are all in UnknownSpaceRegion.
- // This means that there isn't actually anything from HeapSpaceRegion
- // that should be freed, even though we allow it here.
- // Of course, free() can work on memory allocated outside the current
- // function, so UnknownSpaceRegion is always a possibility.
- // False negatives are better than false positives.
-
- ReportBadFree(C, ArgVal, ArgExpr->getSourceRange());
- return NULL;
- }
-
- const SymbolicRegion *SR = dyn_cast<SymbolicRegion>(R);
- // Various cases could lead to non-symbol values here.
- // For now, ignore them.
- if (!SR)
- return notNullState;
-
- SymbolRef Sym = SR->getSymbol();
- const RefState *RS = state->get<RegionState>(Sym);
-
- // If the symbol has not been tracked, return. This is possible when free() is
- // called on a pointer that does not get its pointee directly from malloc().
- // Full support of this requires inter-procedural analysis.
- if (!RS)
- return notNullState;
-
- // Check double free.
- if (RS->isReleased()) {
- if (ExplodedNode *N = C.generateSink()) {
- if (!BT_DoubleFree)
- BT_DoubleFree
- = new BuiltinBug("Double free",
- "Try to free a memory block that has been released");
- // FIXME: should find where it's freed last time.
- BugReport *R = new BugReport(*BT_DoubleFree,
- BT_DoubleFree->getDescription(), N);
- C.EmitReport(R);
- }
- return NULL;
- }
-
- // Normal free.
- if (Hold)
- return notNullState->set<RegionState>(Sym, RefState::getRelinquished(CE));
- return notNullState->set<RegionState>(Sym, RefState::getReleased(CE));
-}
-
-bool MallocChecker::SummarizeValue(llvm::raw_ostream& os, SVal V) {
- if (nonloc::ConcreteInt *IntVal = dyn_cast<nonloc::ConcreteInt>(&V))
- os << "an integer (" << IntVal->getValue() << ")";
- else if (loc::ConcreteInt *ConstAddr = dyn_cast<loc::ConcreteInt>(&V))
- os << "a constant address (" << ConstAddr->getValue() << ")";
- else if (loc::GotoLabel *Label = dyn_cast<loc::GotoLabel>(&V))
- os << "the address of the label '"
- << Label->getLabel()->getID()->getName()
- << "'";
- else
- return false;
-
- return true;
-}
-
-bool MallocChecker::SummarizeRegion(llvm::raw_ostream& os,
- const MemRegion *MR) {
- switch (MR->getKind()) {
- case MemRegion::FunctionTextRegionKind: {
- const FunctionDecl *FD = cast<FunctionTextRegion>(MR)->getDecl();
- if (FD)
- os << "the address of the function '" << FD << "'";
- else
- os << "the address of a function";
- return true;
- }
- case MemRegion::BlockTextRegionKind:
- os << "block text";
- return true;
- case MemRegion::BlockDataRegionKind:
- // FIXME: where the block came from?
- os << "a block";
- return true;
- default: {
- const MemSpaceRegion *MS = MR->getMemorySpace();
-
- switch (MS->getKind()) {
- case MemRegion::StackLocalsSpaceRegionKind: {
- const VarRegion *VR = dyn_cast<VarRegion>(MR);
- const VarDecl *VD;
- if (VR)
- VD = VR->getDecl();
- else
- VD = NULL;
-
- if (VD)
- os << "the address of the local variable '" << VD->getName() << "'";
- else
- os << "the address of a local stack variable";
- return true;
- }
- case MemRegion::StackArgumentsSpaceRegionKind: {
- const VarRegion *VR = dyn_cast<VarRegion>(MR);
- const VarDecl *VD;
- if (VR)
- VD = VR->getDecl();
- else
- VD = NULL;
-
- if (VD)
- os << "the address of the parameter '" << VD->getName() << "'";
- else
- os << "the address of a parameter";
- return true;
- }
- case MemRegion::NonStaticGlobalSpaceRegionKind:
- case MemRegion::StaticGlobalSpaceRegionKind: {
- const VarRegion *VR = dyn_cast<VarRegion>(MR);
- const VarDecl *VD;
- if (VR)
- VD = VR->getDecl();
- else
- VD = NULL;
-
- if (VD) {
- if (VD->isStaticLocal())
- os << "the address of the static variable '" << VD->getName() << "'";
- else
- os << "the address of the global variable '" << VD->getName() << "'";
- } else
- os << "the address of a global variable";
- return true;
- }
- default:
- return false;
- }
- }
- }
-}
-
-void MallocChecker::ReportBadFree(CheckerContext &C, SVal ArgVal,
- SourceRange range) {
- if (ExplodedNode *N = C.generateSink()) {
- if (!BT_BadFree)
- BT_BadFree = new BuiltinBug("Bad free");
-
- llvm::SmallString<100> buf;
- llvm::raw_svector_ostream os(buf);
-
- const MemRegion *MR = ArgVal.getAsRegion();
- if (MR) {
- while (const ElementRegion *ER = dyn_cast<ElementRegion>(MR))
- MR = ER->getSuperRegion();
-
- // Special case for alloca()
- if (isa<AllocaRegion>(MR))
- os << "Argument to free() was allocated by alloca(), not malloc()";
- else {
- os << "Argument to free() is ";
- if (SummarizeRegion(os, MR))
- os << ", which is not memory allocated by malloc()";
- else
- os << "not memory allocated by malloc()";
- }
- } else {
- os << "Argument to free() is ";
- if (SummarizeValue(os, ArgVal))
- os << ", which is not memory allocated by malloc()";
- else
- os << "not memory allocated by malloc()";
- }
-
- EnhancedBugReport *R = new EnhancedBugReport(*BT_BadFree, os.str(), N);
- R->addRange(range);
- C.EmitReport(R);
- }
-}
-
-void MallocChecker::ReallocMem(CheckerContext &C, const CallExpr *CE) {
- const GRState *state = C.getState();
- const Expr *arg0Expr = CE->getArg(0);
- DefinedOrUnknownSVal arg0Val
- = cast<DefinedOrUnknownSVal>(state->getSVal(arg0Expr));
-
- SValBuilder &svalBuilder = C.getSValBuilder();
-
- DefinedOrUnknownSVal PtrEQ =
- svalBuilder.evalEQ(state, arg0Val, svalBuilder.makeNull());
-
- // If the ptr is NULL, the call is equivalent to malloc(size).
- if (const GRState *stateEqual = state->assume(PtrEQ, true)) {
- // Hack: set the NULL symbolic region to released to suppress false warning.
- // In the future we should add more states for allocated regions, e.g.,
- // CheckedNull, CheckedNonNull.
-
- SymbolRef Sym = arg0Val.getAsLocSymbol();
- if (Sym)
- stateEqual = stateEqual->set<RegionState>(Sym, RefState::getReleased(CE));
-
- const GRState *stateMalloc = MallocMemAux(C, CE, CE->getArg(1),
- UndefinedVal(), stateEqual);
- C.addTransition(stateMalloc);
- }
-
- if (const GRState *stateNotEqual = state->assume(PtrEQ, false)) {
- const Expr *Arg1 = CE->getArg(1);
- DefinedOrUnknownSVal Arg1Val =
- cast<DefinedOrUnknownSVal>(stateNotEqual->getSVal(Arg1));
- DefinedOrUnknownSVal SizeZero =
- svalBuilder.evalEQ(stateNotEqual, Arg1Val,
- svalBuilder.makeIntValWithPtrWidth(0, false));
-
- if (const GRState *stateSizeZero = stateNotEqual->assume(SizeZero, true))
- if (const GRState *stateFree = FreeMemAux(C, CE, stateSizeZero, 0, false))
- C.addTransition(stateFree->BindExpr(CE, UndefinedVal(), true));
-
- if (const GRState *stateSizeNotZero = stateNotEqual->assume(SizeZero,false))
- if (const GRState *stateFree = FreeMemAux(C, CE, stateSizeNotZero,
- 0, false)) {
- // FIXME: We should copy the content of the original buffer.
- const GRState *stateRealloc = MallocMemAux(C, CE, CE->getArg(1),
- UnknownVal(), stateFree);
- C.addTransition(stateRealloc);
- }
- }
-}
-
-void MallocChecker::CallocMem(CheckerContext &C, const CallExpr *CE) {
- const GRState *state = C.getState();
- SValBuilder &svalBuilder = C.getSValBuilder();
-
- SVal count = state->getSVal(CE->getArg(0));
- SVal elementSize = state->getSVal(CE->getArg(1));
- SVal TotalSize = svalBuilder.evalBinOp(state, BO_Mul, count, elementSize,
- svalBuilder.getContext().getSizeType());
- SVal zeroVal = svalBuilder.makeZeroVal(svalBuilder.getContext().CharTy);
-
- C.addTransition(MallocMemAux(C, CE, TotalSize, zeroVal, state));
-}
-
-void MallocChecker::evalDeadSymbols(CheckerContext &C, SymbolReaper &SymReaper)
-{
- if (!SymReaper.hasDeadSymbols())
- return;
-
- const GRState *state = C.getState();
- RegionStateTy RS = state->get<RegionState>();
- RegionStateTy::Factory &F = state->get_context<RegionState>();
-
- for (RegionStateTy::iterator I = RS.begin(), E = RS.end(); I != E; ++I) {
- if (SymReaper.isDead(I->first)) {
- if (I->second.isAllocated()) {
- if (ExplodedNode *N = C.generateNode()) {
- if (!BT_Leak)
- BT_Leak = new BuiltinBug("Memory leak",
- "Allocated memory never released. Potential memory leak.");
- // FIXME: where it is allocated.
- BugReport *R = new BugReport(*BT_Leak, BT_Leak->getDescription(), N);
- C.EmitReport(R);
- }
- }
-
- // Remove the dead symbol from the map.
- RS = F.remove(RS, I->first);
- }
- }
- C.generateNode(state->set<RegionState>(RS));
-}
-
-void MallocChecker::evalEndPath(EndPathNodeBuilder &B, void *tag,
- ExprEngine &Eng) {
- SaveAndRestore<bool> OldHasGen(B.HasGeneratedNode);
- const GRState *state = B.getState();
- RegionStateTy M = state->get<RegionState>();
-
- for (RegionStateTy::iterator I = M.begin(), E = M.end(); I != E; ++I) {
- RefState RS = I->second;
- if (RS.isAllocated()) {
- ExplodedNode *N = B.generateNode(state, tag, B.getPredecessor());
- if (N) {
- if (!BT_Leak)
- BT_Leak = new BuiltinBug("Memory leak",
- "Allocated memory never released. Potential memory leak.");
- BugReport *R = new BugReport(*BT_Leak, BT_Leak->getDescription(), N);
- Eng.getBugReporter().EmitReport(R);
- }
- }
- }
-}
-
-void MallocChecker::PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S) {
- const Expr *retExpr = S->getRetValue();
- if (!retExpr)
- return;
-
- const GRState *state = C.getState();
-
- SymbolRef Sym = state->getSVal(retExpr).getAsSymbol();
- if (!Sym)
- return;
-
- const RefState *RS = state->get<RegionState>(Sym);
- if (!RS)
- return;
-
- // FIXME: check other cases.
- if (RS->isAllocated())
- state = state->set<RegionState>(Sym, RefState::getEscaped(S));
-
- C.addTransition(state);
-}
-
-const GRState *MallocChecker::evalAssume(const GRState *state, SVal Cond,
- bool Assumption,
- bool * /* respondsToCallback */) {
- // If a symblic region is assumed to NULL, set its state to AllocateFailed.
- // FIXME: should also check symbols assumed to non-null.
-
- RegionStateTy RS = state->get<RegionState>();
-
- for (RegionStateTy::iterator I = RS.begin(), E = RS.end(); I != E; ++I) {
- if (state->getSymVal(I.getKey()))
- state = state->set<RegionState>(I.getKey(),RefState::getAllocateFailed());
- }
-
- return state;
-}
-
-// Check if the location is a freed symbolic region.
-void MallocChecker::visitLocation(CheckerContext &C, const Stmt *S, SVal l) {
- SymbolRef Sym = l.getLocSymbolInBase();
- if (Sym) {
- const RefState *RS = C.getState()->get<RegionState>(Sym);
- if (RS && RS->isReleased()) {
- if (ExplodedNode *N = C.generateNode()) {
- if (!BT_UseFree)
- BT_UseFree = new BuiltinBug("Use dynamically allocated memory after"
- " it is freed.");
-
- BugReport *R = new BugReport(*BT_UseFree, BT_UseFree->getDescription(),
- N);
- C.EmitReport(R);
- }
- }
- }
-}
-
-void MallocChecker::PreVisitBind(CheckerContext &C,
- const Stmt *StoreE,
- SVal location,
- SVal val) {
- // The PreVisitBind implements the same algorithm as already used by the
- // Objective C ownership checker: if the pointer escaped from this scope by
- // assignment, let it go. However, assigning to fields of a stack-storage
- // structure does not transfer ownership.
-
- const GRState *state = C.getState();
- DefinedOrUnknownSVal l = cast<DefinedOrUnknownSVal>(location);
-
- // Check for null dereferences.
- if (!isa<Loc>(l))
- return;
-
- // Before checking if the state is null, check if 'val' has a RefState.
- // Only then should we check for null and bifurcate the state.
- SymbolRef Sym = val.getLocSymbolInBase();
- if (Sym) {
- if (const RefState *RS = state->get<RegionState>(Sym)) {
- // If ptr is NULL, no operation is performed.
- const GRState *notNullState, *nullState;
- llvm::tie(notNullState, nullState) = state->assume(l);
-
- // Generate a transition for 'nullState' to record the assumption
- // that the state was null.
- if (nullState)
- C.addTransition(nullState);
-
- if (!notNullState)
- return;
-
- if (RS->isAllocated()) {
- // Something we presently own is being assigned somewhere.
- const MemRegion *AR = location.getAsRegion();
- if (!AR)
- return;
- AR = AR->StripCasts()->getBaseRegion();
- do {
- // If it is on the stack, we still own it.
- if (AR->hasStackNonParametersStorage())
- break;
-
- // If the state can't represent this binding, we still own it.
- if (notNullState == (notNullState->bindLoc(cast<Loc>(location),
- UnknownVal())))
- break;
-
- // We no longer own this pointer.
- notNullState =
- notNullState->set<RegionState>(Sym,
- RefState::getRelinquished(StoreE));
- }
- while (false);
- }
- C.addTransition(notNullState);
- }
- }
-}
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/NSAutoreleasePoolChecker.cpp b/clang/lib/StaticAnalyzer/EntoSA/Checkers/NSAutoreleasePoolChecker.cpp
deleted file mode 100644
index 6ef242ba427..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/NSAutoreleasePoolChecker.cpp
+++ /dev/null
@@ -1,87 +0,0 @@
-//=- NSAutoreleasePoolChecker.cpp --------------------------------*- C++ -*-==//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines a NSAutoreleasePoolChecker, a small checker that warns
-// about subpar uses of NSAutoreleasePool. Note that while the check itself
-// (in it's current form) could be written as a flow-insensitive check, in
-// can be potentially enhanced in the future with flow-sensitive information.
-// It is also a good example of the CheckerVisitor interface.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
-#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
-#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
-#include "BasicObjCFoundationChecks.h"
-#include "clang/AST/DeclObjC.h"
-#include "clang/AST/Decl.h"
-
-using namespace clang;
-using namespace ento;
-
-namespace {
-class NSAutoreleasePoolChecker
- : public CheckerVisitor<NSAutoreleasePoolChecker> {
-
- Selector releaseS;
-
-public:
- NSAutoreleasePoolChecker(Selector release_s) : releaseS(release_s) {}
-
- static void *getTag() {
- static int x = 0;
- return &x;
- }
-
- void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME);
-};
-
-} // end anonymous namespace
-
-
-void ento::RegisterNSAutoreleasePoolChecks(ExprEngine &Eng) {
- ASTContext &Ctx = Eng.getContext();
- if (Ctx.getLangOptions().getGCMode() != LangOptions::NonGC) {
- Eng.registerCheck(new NSAutoreleasePoolChecker(GetNullarySelector("release",
- Ctx)));
- }
-}
-
-void
-NSAutoreleasePoolChecker::PreVisitObjCMessageExpr(CheckerContext &C,
- const ObjCMessageExpr *ME) {
-
- const Expr *receiver = ME->getInstanceReceiver();
- if (!receiver)
- return;
-
- // FIXME: Enhance with value-tracking information instead of consulting
- // the type of the expression.
- const ObjCObjectPointerType* PT =
- receiver->getType()->getAs<ObjCObjectPointerType>();
-
- if (!PT)
- return;
- const ObjCInterfaceDecl* OD = PT->getInterfaceDecl();
- if (!OD)
- return;
- if (!OD->getIdentifier()->getName().equals("NSAutoreleasePool"))
- return;
-
- // Sending 'release' message?
- if (ME->getSelector() != releaseS)
- return;
-
- SourceRange R = ME->getSourceRange();
-
- C.getBugReporter().EmitBasicReport("Use -drain instead of -release",
- "API Upgrade (Apple)",
- "Use -drain instead of -release when using NSAutoreleasePool "
- "and garbage collection", ME->getLocStart(), &R, 1);
-}
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/NSErrorChecker.cpp b/clang/lib/StaticAnalyzer/EntoSA/Checkers/NSErrorChecker.cpp
deleted file mode 100644
index 54e61188932..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/NSErrorChecker.cpp
+++ /dev/null
@@ -1,238 +0,0 @@
-//=- NSErrorCheckerer.cpp - Coding conventions for uses of NSError -*- C++ -*-==//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines a CheckNSError, a flow-insenstive check
-// that determines if an Objective-C class interface correctly returns
-// a non-void return type.
-//
-// File under feature request PR 2600.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
-#include "clang/StaticAnalyzer/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
-#include "clang/StaticAnalyzer/Checkers/DereferenceChecker.h"
-#include "BasicObjCFoundationChecks.h"
-#include "clang/AST/DeclObjC.h"
-#include "clang/AST/Decl.h"
-#include "llvm/ADT/SmallVector.h"
-
-using namespace clang;
-using namespace ento;
-
-namespace {
-class NSErrorChecker : public BugType {
- const Decl &CodeDecl;
- const bool isNSErrorWarning;
- IdentifierInfo * const II;
- ExprEngine &Eng;
-
- void CheckSignature(const ObjCMethodDecl& MD, QualType& ResultTy,
- llvm::SmallVectorImpl<VarDecl*>& ErrorParams);
-
- void CheckSignature(const FunctionDecl& MD, QualType& ResultTy,
- llvm::SmallVectorImpl<VarDecl*>& ErrorParams);
-
- bool CheckNSErrorArgument(QualType ArgTy);
- bool CheckCFErrorArgument(QualType ArgTy);
-
- void CheckParamDeref(const VarDecl *V, const LocationContext *LC,
- const GRState *state, BugReporter& BR);
-
- void EmitRetTyWarning(BugReporter& BR, const Decl& CodeDecl);
-
-public:
- NSErrorChecker(const Decl &D, bool isNSError, ExprEngine& eng)
- : BugType(isNSError ? "NSError** null dereference"
- : "CFErrorRef* null dereference",
- "Coding conventions (Apple)"),
- CodeDecl(D),
- isNSErrorWarning(isNSError),
- II(&eng.getContext().Idents.get(isNSErrorWarning ? "NSError":"CFErrorRef")),
- Eng(eng) {}
-
- void FlushReports(BugReporter& BR);
-};
-
-} // end anonymous namespace
-
-void ento::RegisterNSErrorChecks(BugReporter& BR, ExprEngine &Eng,
- const Decl &D) {
- BR.Register(new NSErrorChecker(D, true, Eng));
- BR.Register(new NSErrorChecker(D, false, Eng));
-}
-
-void NSErrorChecker::FlushReports(BugReporter& BR) {
- // Get the analysis engine and the exploded analysis graph.
- ExplodedGraph& G = Eng.getGraph();
-
- // Get the ASTContext, which is useful for querying type information.
- ASTContext &Ctx = BR.getContext();
-
- QualType ResultTy;
- llvm::SmallVector<VarDecl*, 5> ErrorParams;
-
- if (const ObjCMethodDecl* MD = dyn_cast<ObjCMethodDecl>(&CodeDecl))
- CheckSignature(*MD, ResultTy, ErrorParams);
- else if (const FunctionDecl* FD = dyn_cast<FunctionDecl>(&CodeDecl))
- CheckSignature(*FD, ResultTy, ErrorParams);
- else
- return;
-
- if (ErrorParams.empty())
- return;
-
- if (ResultTy == Ctx.VoidTy) EmitRetTyWarning(BR, CodeDecl);
-
- for (ExplodedGraph::roots_iterator RI=G.roots_begin(), RE=G.roots_end();
- RI!=RE; ++RI) {
- // Scan the parameters for an implicit null dereference.
- for (llvm::SmallVectorImpl<VarDecl*>::iterator I=ErrorParams.begin(),
- E=ErrorParams.end(); I!=E; ++I)
- CheckParamDeref(*I, (*RI)->getLocationContext(), (*RI)->getState(), BR);
- }
-}
-
-void NSErrorChecker::EmitRetTyWarning(BugReporter& BR, const Decl& CodeDecl) {
- std::string sbuf;
- llvm::raw_string_ostream os(sbuf);
-
- if (isa<ObjCMethodDecl>(CodeDecl))
- os << "Method";
- else
- os << "Function";
-
- os << " accepting ";
- os << (isNSErrorWarning ? "NSError**" : "CFErrorRef*");
- os << " should have a non-void return value to indicate whether or not an "
- "error occurred";
-
- BR.EmitBasicReport(isNSErrorWarning
- ? "Bad return type when passing NSError**"
- : "Bad return type when passing CFError*",
- getCategory(), os.str(),
- CodeDecl.getLocation());
-}
-
-void
-NSErrorChecker::CheckSignature(const ObjCMethodDecl& M, QualType& ResultTy,
- llvm::SmallVectorImpl<VarDecl*>& ErrorParams) {
-
- ResultTy = M.getResultType();
-
- for (ObjCMethodDecl::param_iterator I=M.param_begin(),
- E=M.param_end(); I!=E; ++I) {
-
- QualType T = (*I)->getType();
-
- if (isNSErrorWarning) {
- if (CheckNSErrorArgument(T)) ErrorParams.push_back(*I);
- }
- else if (CheckCFErrorArgument(T))
- ErrorParams.push_back(*I);
- }
-}
-
-void
-NSErrorChecker::CheckSignature(const FunctionDecl& F, QualType& ResultTy,
- llvm::SmallVectorImpl<VarDecl*>& ErrorParams) {
-
- ResultTy = F.getResultType();
-
- for (FunctionDecl::param_const_iterator I = F.param_begin(),
- E = F.param_end(); I != E; ++I) {
-
- QualType T = (*I)->getType();
-
- if (isNSErrorWarning) {
- if (CheckNSErrorArgument(T)) ErrorParams.push_back(*I);
- }
- else if (CheckCFErrorArgument(T))
- ErrorParams.push_back(*I);
- }
-}
-
-
-bool NSErrorChecker::CheckNSErrorArgument(QualType ArgTy) {
-
- const PointerType* PPT = ArgTy->getAs<PointerType>();
- if (!PPT)
- return false;
-
- const ObjCObjectPointerType* PT =
- PPT->getPointeeType()->getAs<ObjCObjectPointerType>();
-
- if (!PT)
- return false;
-
- const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
-
- // FIXME: Can ID ever be NULL?
- if (ID)
- return II == ID->getIdentifier();
-
- return false;
-}
-
-bool NSErrorChecker::CheckCFErrorArgument(QualType ArgTy) {
-
- const PointerType* PPT = ArgTy->getAs<PointerType>();
- if (!PPT) return false;
-
- const TypedefType* TT = PPT->getPointeeType()->getAs<TypedefType>();
- if (!TT) return false;
-
- return TT->getDecl()->getIdentifier() == II;
-}
-
-void NSErrorChecker::CheckParamDeref(const VarDecl *Param,
- const LocationContext *LC,
- const GRState *rootState,
- BugReporter& BR) {
-
- SVal ParamL = rootState->getLValue(Param, LC);
- const MemRegion* ParamR = cast<loc::MemRegionVal>(ParamL).getRegionAs<VarRegion>();
- assert (ParamR && "Parameters always have VarRegions.");
- SVal ParamSVal = rootState->getSVal(ParamR);
-
- // FIXME: For now assume that ParamSVal is symbolic. We need to generalize
- // this later.
- SymbolRef ParamSym = ParamSVal.getAsLocSymbol();
- if (!ParamSym)
- return;
-
- // Iterate over the implicit-null dereferences.
- ExplodedNode *const* I, *const* E;
- llvm::tie(I, E) = GetImplicitNullDereferences(Eng);
- for ( ; I != E; ++I) {
- const GRState *state = (*I)->getState();
- SVal location = state->getSVal((*I)->getLocationAs<StmtPoint>()->getStmt());
- if (location.getAsSymbol() != ParamSym)
- continue;
-
- // Emit an error.
- std::string sbuf;
- llvm::raw_string_ostream os(sbuf);
- os << "Potential null dereference. According to coding standards ";
-
- if (isNSErrorWarning)
- os << "in 'Creating and Returning NSError Objects' the parameter '";
- else
- os << "documented in CoreFoundation/CFError.h the parameter '";
-
- os << Param << "' may be null.";
-
- BugReport *report = new BugReport(*this, os.str(), *I);
- // FIXME: Notable symbols are now part of the report. We should
- // add support for notable symbols in BugReport.
- // BR.addNotableSymbol(SV->getSymbol());
- BR.EmitReport(report);
- }
-}
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/NoReturnFunctionChecker.cpp b/clang/lib/StaticAnalyzer/EntoSA/Checkers/NoReturnFunctionChecker.cpp
deleted file mode 100644
index 8cdc04f9ff7..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/NoReturnFunctionChecker.cpp
+++ /dev/null
@@ -1,80 +0,0 @@
-//=== NoReturnFunctionChecker.cpp -------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This defines NoReturnFunctionChecker, which evaluates functions that do not
-// return to the caller.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ExprEngineInternalChecks.h"
-#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
-#include "llvm/ADT/StringSwitch.h"
-
-using namespace clang;
-using namespace ento;
-
-namespace {
-
-class NoReturnFunctionChecker : public CheckerVisitor<NoReturnFunctionChecker> {
-public:
- static void *getTag() { static int tag = 0; return &tag; }
- void PostVisitCallExpr(CheckerContext &C, const CallExpr *CE);
-};
-
-}
-
-void ento::RegisterNoReturnFunctionChecker(ExprEngine &Eng) {
- Eng.registerCheck(new NoReturnFunctionChecker());
-}
-
-void NoReturnFunctionChecker::PostVisitCallExpr(CheckerContext &C,
- const CallExpr *CE) {
- const GRState *state = C.getState();
- const Expr *Callee = CE->getCallee();
-
- bool BuildSinks = getFunctionExtInfo(Callee->getType()).getNoReturn();
-
- if (!BuildSinks) {
- SVal L = state->getSVal(Callee);
- const FunctionDecl *FD = L.getAsFunctionDecl();
- if (!FD)
- return;
-
- if (FD->getAttr<AnalyzerNoReturnAttr>())
- BuildSinks = true;
- else if (const IdentifierInfo *II = FD->getIdentifier()) {
- // HACK: Some functions are not marked noreturn, and don't return.
- // Here are a few hardwired ones. If this takes too long, we can
- // potentially cache these results.
- BuildSinks
- = llvm::StringSwitch<bool>(llvm::StringRef(II->getName()))
- .Case("exit", true)
- .Case("panic", true)
- .Case("error", true)
- .Case("Assert", true)
- // FIXME: This is just a wrapper around throwing an exception.
- // Eventually inter-procedural analysis should handle this easily.
- .Case("ziperr", true)
- .Case("assfail", true)
- .Case("db_error", true)
- .Case("__assert", true)
- .Case("__assert_rtn", true)
- .Case("__assert_fail", true)
- .Case("dtrace_assfail", true)
- .Case("yy_fatal_error", true)
- .Case("_XCAssertionFailureHandler", true)
- .Case("_DTAssertionFailureHandler", true)
- .Case("_TSAssertionFailureHandler", true)
- .Default(false);
- }
- }
-
- if (BuildSinks)
- C.generateSink(CE);
-}
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/OSAtomicChecker.cpp b/clang/lib/StaticAnalyzer/EntoSA/Checkers/OSAtomicChecker.cpp
deleted file mode 100644
index 99317348421..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/OSAtomicChecker.cpp
+++ /dev/null
@@ -1,203 +0,0 @@
-//=== OSAtomicChecker.cpp - OSAtomic functions evaluator --------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This checker evaluates OSAtomic functions.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ExprEngineInternalChecks.h"
-#include "clang/StaticAnalyzer/PathSensitive/Checker.h"
-#include "clang/Basic/Builtins.h"
-
-using namespace clang;
-using namespace ento;
-
-namespace {
-
-class OSAtomicChecker : public Checker {
-public:
- static void *getTag() { static int tag = 0; return &tag; }
- virtual bool evalCallExpr(CheckerContext &C, const CallExpr *CE);
-
-private:
- bool evalOSAtomicCompareAndSwap(CheckerContext &C, const CallExpr *CE);
-};
-
-}
-
-void ento::RegisterOSAtomicChecker(ExprEngine &Eng) {
- Eng.registerCheck(new OSAtomicChecker());
-}
-
-bool OSAtomicChecker::evalCallExpr(CheckerContext &C,const CallExpr *CE) {
- const GRState *state = C.getState();
- const Expr *Callee = CE->getCallee();
- SVal L = state->getSVal(Callee);
-
- const FunctionDecl* FD = L.getAsFunctionDecl();
- if (!FD)
- return false;
-
- const IdentifierInfo *II = FD->getIdentifier();
- if (!II)
- return false;
-
- llvm::StringRef FName(II->getName());
-
- // Check for compare and swap.
- if (FName.startswith("OSAtomicCompareAndSwap") ||
- FName.startswith("objc_atomicCompareAndSwap"))
- return evalOSAtomicCompareAndSwap(C, CE);
-
- // FIXME: Other atomics.
- return false;
-}
-
-bool OSAtomicChecker::evalOSAtomicCompareAndSwap(CheckerContext &C,
- const CallExpr *CE) {
- // Not enough arguments to match OSAtomicCompareAndSwap?
- if (CE->getNumArgs() != 3)
- return false;
-
- ASTContext &Ctx = C.getASTContext();
- const Expr *oldValueExpr = CE->getArg(0);
- QualType oldValueType = Ctx.getCanonicalType(oldValueExpr->getType());
-
- const Expr *newValueExpr = CE->getArg(1);
- QualType newValueType = Ctx.getCanonicalType(newValueExpr->getType());
-
- // Do the types of 'oldValue' and 'newValue' match?
- if (oldValueType != newValueType)
- return false;
-
- const Expr *theValueExpr = CE->getArg(2);
- const PointerType *theValueType=theValueExpr->getType()->getAs<PointerType>();
-
- // theValueType not a pointer?
- if (!theValueType)
- return false;
-
- QualType theValueTypePointee =
- Ctx.getCanonicalType(theValueType->getPointeeType()).getUnqualifiedType();
-
- // The pointee must match newValueType and oldValueType.
- if (theValueTypePointee != newValueType)
- return false;
-
- static unsigned magic_load = 0;
- static unsigned magic_store = 0;
-
- const void *OSAtomicLoadTag = &magic_load;
- const void *OSAtomicStoreTag = &magic_store;
-
- // Load 'theValue'.
- ExprEngine &Engine = C.getEngine();
- const GRState *state = C.getState();
- ExplodedNodeSet Tmp;
- SVal location = state->getSVal(theValueExpr);
- // Here we should use the value type of the region as the load type, because
- // we are simulating the semantics of the function, not the semantics of
- // passing argument. So the type of theValue expr is not we are loading.
- // But usually the type of the varregion is not the type we want either,
- // we still need to do a CastRetrievedVal in store manager. So actually this
- // LoadTy specifying can be omitted. But we put it here to emphasize the
- // semantics.
- QualType LoadTy;
- if (const TypedRegion *TR =
- dyn_cast_or_null<TypedRegion>(location.getAsRegion())) {
- LoadTy = TR->getValueType();
- }
- Engine.evalLoad(Tmp, theValueExpr, C.getPredecessor(),
- state, location, OSAtomicLoadTag, LoadTy);
-
- if (Tmp.empty()) {
- // If no nodes were generated, other checkers must generated sinks. But
- // since the builder state was restored, we set it manually to prevent
- // auto transition.
- // FIXME: there should be a better approach.
- C.getNodeBuilder().BuildSinks = true;
- return true;
- }
-
- for (ExplodedNodeSet::iterator I = Tmp.begin(), E = Tmp.end();
- I != E; ++I) {
-
- ExplodedNode *N = *I;
- const GRState *stateLoad = N->getState();
- SVal theValueVal_untested = stateLoad->getSVal(theValueExpr);
- SVal oldValueVal_untested = stateLoad->getSVal(oldValueExpr);
-
- // FIXME: Issue an error.
- if (theValueVal_untested.isUndef() || oldValueVal_untested.isUndef()) {
- return false;
- }
-
- DefinedOrUnknownSVal theValueVal =
- cast<DefinedOrUnknownSVal>(theValueVal_untested);
- DefinedOrUnknownSVal oldValueVal =
- cast<DefinedOrUnknownSVal>(oldValueVal_untested);
-
- SValBuilder &svalBuilder = Engine.getSValBuilder();
-
- // Perform the comparison.
- DefinedOrUnknownSVal Cmp = svalBuilder.evalEQ(stateLoad,theValueVal,oldValueVal);
-
- const GRState *stateEqual = stateLoad->assume(Cmp, true);
-
- // Were they equal?
- if (stateEqual) {
- // Perform the store.
- ExplodedNodeSet TmpStore;
- SVal val = stateEqual->getSVal(newValueExpr);
-
- // Handle implicit value casts.
- if (const TypedRegion *R =
- dyn_cast_or_null<TypedRegion>(location.getAsRegion())) {
- val = svalBuilder.evalCast(val,R->getValueType(), newValueExpr->getType());
- }
-
- Engine.evalStore(TmpStore, NULL, theValueExpr, N,
- stateEqual, location, val, OSAtomicStoreTag);
-
- if (TmpStore.empty()) {
- // If no nodes were generated, other checkers must generated sinks. But
- // since the builder state was restored, we set it manually to prevent
- // auto transition.
- // FIXME: there should be a better approach.
- C.getNodeBuilder().BuildSinks = true;
- return true;
- }
-
- // Now bind the result of the comparison.
- for (ExplodedNodeSet::iterator I2 = TmpStore.begin(),
- E2 = TmpStore.end(); I2 != E2; ++I2) {
- ExplodedNode *predNew = *I2;
- const GRState *stateNew = predNew->getState();
- // Check for 'void' return type if we have a bogus function prototype.
- SVal Res = UnknownVal();
- QualType T = CE->getType();
- if (!T->isVoidType())
- Res = Engine.getSValBuilder().makeTruthVal(true, T);
- C.generateNode(stateNew->BindExpr(CE, Res), predNew);
- }
- }
-
- // Were they not equal?
- if (const GRState *stateNotEqual = stateLoad->assume(Cmp, false)) {
- // Check for 'void' return type if we have a bogus function prototype.
- SVal Res = UnknownVal();
- QualType T = CE->getType();
- if (!T->isVoidType())
- Res = Engine.getSValBuilder().makeTruthVal(false, CE->getType());
- C.generateNode(stateNotEqual->BindExpr(CE, Res), N);
- }
- }
-
- return true;
-}
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/ObjCAtSyncChecker.cpp b/clang/lib/StaticAnalyzer/EntoSA/Checkers/ObjCAtSyncChecker.cpp
deleted file mode 100644
index 2d94e8ce910..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/ObjCAtSyncChecker.cpp
+++ /dev/null
@@ -1,95 +0,0 @@
-//== ObjCAtSyncChecker.cpp - nil mutex checker for @synchronized -*- C++ -*--=//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This defines ObjCAtSyncChecker, a builtin check that checks for null pointers
-// used as mutexes for @synchronized.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ExprEngineInternalChecks.h"
-#include "clang/StaticAnalyzer/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/Checkers/DereferenceChecker.h"
-#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
-#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
-
-using namespace clang;
-using namespace ento;
-
-namespace {
-class ObjCAtSyncChecker : public CheckerVisitor<ObjCAtSyncChecker> {
- BuiltinBug *BT_null;
- BuiltinBug *BT_undef;
-public:
- ObjCAtSyncChecker() : BT_null(0), BT_undef(0) {}
- static void *getTag() { static int tag = 0; return &tag; }
- void PreVisitObjCAtSynchronizedStmt(CheckerContext &C,
- const ObjCAtSynchronizedStmt *S);
-};
-} // end anonymous namespace
-
-void ento::RegisterObjCAtSyncChecker(ExprEngine &Eng) {
- // @synchronized is an Objective-C 2 feature.
- if (Eng.getContext().getLangOptions().ObjC2)
- Eng.registerCheck(new ObjCAtSyncChecker());
-}
-
-void ObjCAtSyncChecker::PreVisitObjCAtSynchronizedStmt(CheckerContext &C,
- const ObjCAtSynchronizedStmt *S) {
-
- const Expr *Ex = S->getSynchExpr();
- const GRState *state = C.getState();
- SVal V = state->getSVal(Ex);
-
- // Uninitialized value used for the mutex?
- if (isa<UndefinedVal>(V)) {
- if (ExplodedNode *N = C.generateSink()) {
- if (!BT_undef)
- BT_undef = new BuiltinBug("Uninitialized value used as mutex "
- "for @synchronized");
- EnhancedBugReport *report =
- new EnhancedBugReport(*BT_undef, BT_undef->getDescription(), N);
- report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Ex);
- C.EmitReport(report);
- }
- return;
- }
-
- if (V.isUnknown())
- return;
-
- // Check for null mutexes.
- const GRState *notNullState, *nullState;
- llvm::tie(notNullState, nullState) = state->assume(cast<DefinedSVal>(V));
-
- if (nullState) {
- if (!notNullState) {
- // Generate an error node. This isn't a sink since
- // a null mutex just means no synchronization occurs.
- if (ExplodedNode *N = C.generateNode(nullState)) {
- if (!BT_null)
- BT_null = new BuiltinBug("Nil value used as mutex for @synchronized() "
- "(no synchronization will occur)");
- EnhancedBugReport *report =
- new EnhancedBugReport(*BT_null, BT_null->getDescription(), N);
- report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
- Ex);
-
- C.EmitReport(report);
- return;
- }
- }
- // Don't add a transition for 'nullState'. If the value is
- // under-constrained to be null or non-null, assume it is non-null
- // afterwards.
- }
-
- if (notNullState)
- C.addTransition(notNullState);
-}
-
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/ObjCUnusedIVarsChecker.cpp b/clang/lib/StaticAnalyzer/EntoSA/Checkers/ObjCUnusedIVarsChecker.cpp
deleted file mode 100644
index 799da332b95..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/ObjCUnusedIVarsChecker.cpp
+++ /dev/null
@@ -1,164 +0,0 @@
-//==- ObjCUnusedIVarsChecker.cpp - Check for unused ivars --------*- C++ -*-==//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines a CheckObjCUnusedIvars, a checker that
-// analyzes an Objective-C class's interface/implementation to determine if it
-// has any ivars that are never accessed.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h"
-#include "clang/StaticAnalyzer/BugReporter/PathDiagnostic.h"
-#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
-#include "clang/AST/ExprObjC.h"
-#include "clang/AST/Expr.h"
-#include "clang/AST/DeclObjC.h"
-#include "clang/Basic/LangOptions.h"
-#include "clang/Basic/SourceManager.h"
-
-using namespace clang;
-using namespace ento;
-
-enum IVarState { Unused, Used };
-typedef llvm::DenseMap<const ObjCIvarDecl*,IVarState> IvarUsageMap;
-
-static void Scan(IvarUsageMap& M, const Stmt* S) {
- if (!S)
- return;
-
- if (const ObjCIvarRefExpr *Ex = dyn_cast<ObjCIvarRefExpr>(S)) {
- const ObjCIvarDecl *D = Ex->getDecl();
- IvarUsageMap::iterator I = M.find(D);
- if (I != M.end())
- I->second = Used;
- return;
- }
-
- // Blocks can reference an instance variable of a class.
- if (const BlockExpr *BE = dyn_cast<BlockExpr>(S)) {
- Scan(M, BE->getBody());
- return;
- }
-
- for (Stmt::const_child_iterator I=S->child_begin(),E=S->child_end(); I!=E;++I)
- Scan(M, *I);
-}
-
-static void Scan(IvarUsageMap& M, const ObjCPropertyImplDecl* D) {
- if (!D)
- return;
-
- const ObjCIvarDecl* ID = D->getPropertyIvarDecl();
-
- if (!ID)
- return;
-
- IvarUsageMap::iterator I = M.find(ID);
- if (I != M.end())
- I->second = Used;
-}
-
-static void Scan(IvarUsageMap& M, const ObjCContainerDecl* D) {
- // Scan the methods for accesses.
- for (ObjCContainerDecl::instmeth_iterator I = D->instmeth_begin(),
- E = D->instmeth_end(); I!=E; ++I)
- Scan(M, (*I)->getBody());
-
- if (const ObjCImplementationDecl *ID = dyn_cast<ObjCImplementationDecl>(D)) {
- // Scan for @synthesized property methods that act as setters/getters
- // to an ivar.
- for (ObjCImplementationDecl::propimpl_iterator I = ID->propimpl_begin(),
- E = ID->propimpl_end(); I!=E; ++I)
- Scan(M, *I);
-
- // Scan the associated categories as well.
- for (const ObjCCategoryDecl *CD =
- ID->getClassInterface()->getCategoryList(); CD ;
- CD = CD->getNextClassCategory()) {
- if (const ObjCCategoryImplDecl *CID = CD->getImplementation())
- Scan(M, CID);
- }
- }
-}
-
-static void Scan(IvarUsageMap &M, const DeclContext *C, const FileID FID,
- SourceManager &SM) {
- for (DeclContext::decl_iterator I=C->decls_begin(), E=C->decls_end();
- I!=E; ++I)
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(*I)) {
- SourceLocation L = FD->getLocStart();
- if (SM.getFileID(L) == FID)
- Scan(M, FD->getBody());
- }
-}
-
-void ento::CheckObjCUnusedIvar(const ObjCImplementationDecl *D,
- BugReporter &BR) {
-
- const ObjCInterfaceDecl* ID = D->getClassInterface();
- IvarUsageMap M;
-
- // Iterate over the ivars.
- for (ObjCInterfaceDecl::ivar_iterator I=ID->ivar_begin(),
- E=ID->ivar_end(); I!=E; ++I) {
-
- const ObjCIvarDecl* ID = *I;
-
- // Ignore ivars that...
- // (a) aren't private
- // (b) explicitly marked unused
- // (c) are iboutlets
- // (d) are unnamed bitfields
- if (ID->getAccessControl() != ObjCIvarDecl::Private ||
- ID->getAttr<UnusedAttr>() || ID->getAttr<IBOutletAttr>() ||
- ID->getAttr<IBOutletCollectionAttr>() ||
- ID->isUnnamedBitfield())
- continue;
-
- M[ID] = Unused;
- }
-
- if (M.empty())
- return;
-
- // Now scan the implementation declaration.
- Scan(M, D);
-
- // Any potentially unused ivars?
- bool hasUnused = false;
- for (IvarUsageMap::iterator I = M.begin(), E = M.end(); I!=E; ++I)
- if (I->second == Unused) {
- hasUnused = true;
- break;
- }
-
- if (!hasUnused)
- return;
-
- // We found some potentially unused ivars. Scan the entire translation unit
- // for functions inside the @implementation that reference these ivars.
- // FIXME: In the future hopefully we can just use the lexical DeclContext
- // to go from the ObjCImplementationDecl to the lexically "nested"
- // C functions.
- SourceManager &SM = BR.getSourceManager();
- Scan(M, D->getDeclContext(), SM.getFileID(D->getLocation()), SM);
-
- // Find ivars that are unused.
- for (IvarUsageMap::iterator I = M.begin(), E = M.end(); I!=E; ++I)
- if (I->second == Unused) {
- std::string sbuf;
- llvm::raw_string_ostream os(sbuf);
- os << "Instance variable '" << I->first << "' in class '" << ID
- << "' is never used by the methods in its @implementation "
- "(although it may be used by category methods).";
-
- BR.EmitBasicReport("Unused instance variable", "Optimization",
- os.str(), I->first->getLocation());
- }
-}
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/PointerArithChecker.cpp b/clang/lib/StaticAnalyzer/EntoSA/Checkers/PointerArithChecker.cpp
deleted file mode 100644
index 2b03dbcd9c2..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/PointerArithChecker.cpp
+++ /dev/null
@@ -1,72 +0,0 @@
-//=== PointerArithChecker.cpp - Pointer arithmetic checker -----*- C++ -*--===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This files defines PointerArithChecker, a builtin checker that checks for
-// pointer arithmetic on locations other than array elements.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ExprEngineInternalChecks.h"
-#include "clang/StaticAnalyzer/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
-
-using namespace clang;
-using namespace ento;
-
-namespace {
-class PointerArithChecker
- : public CheckerVisitor<PointerArithChecker> {
- BuiltinBug *BT;
-public:
- PointerArithChecker() : BT(0) {}
- static void *getTag();
- void PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B);
-};
-}
-
-void *PointerArithChecker::getTag() {
- static int x;
- return &x;
-}
-
-void PointerArithChecker::PreVisitBinaryOperator(CheckerContext &C,
- const BinaryOperator *B) {
- if (B->getOpcode() != BO_Sub && B->getOpcode() != BO_Add)
- return;
-
- const GRState *state = C.getState();
- SVal LV = state->getSVal(B->getLHS());
- SVal RV = state->getSVal(B->getRHS());
-
- const MemRegion *LR = LV.getAsRegion();
-
- if (!LR || !RV.isConstant())
- return;
-
- // If pointer arithmetic is done on variables of non-array type, this often
- // means behavior rely on memory organization, which is dangerous.
- if (isa<VarRegion>(LR) || isa<CodeTextRegion>(LR) ||
- isa<CompoundLiteralRegion>(LR)) {
-
- if (ExplodedNode *N = C.generateNode()) {
- if (!BT)
- BT = new BuiltinBug("Dangerous pointer arithmetic",
- "Pointer arithmetic done on non-array variables "
- "means reliance on memory layout, which is "
- "dangerous.");
- RangedBugReport *R = new RangedBugReport(*BT, BT->getDescription(), N);
- R->addRange(B->getSourceRange());
- C.EmitReport(R);
- }
- }
-}
-
-void ento::RegisterPointerArithChecker(ExprEngine &Eng) {
- Eng.registerCheck(new PointerArithChecker());
-}
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/PointerSubChecker.cpp b/clang/lib/StaticAnalyzer/EntoSA/Checkers/PointerSubChecker.cpp
deleted file mode 100644
index 1ba60f7541d..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/PointerSubChecker.cpp
+++ /dev/null
@@ -1,79 +0,0 @@
-//=== PointerSubChecker.cpp - Pointer subtraction checker ------*- C++ -*--===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This files defines PointerSubChecker, a builtin checker that checks for
-// pointer subtractions on two pointers pointing to different memory chunks.
-// This check corresponds to CWE-469.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ExprEngineInternalChecks.h"
-#include "clang/StaticAnalyzer/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
-
-using namespace clang;
-using namespace ento;
-
-namespace {
-class PointerSubChecker
- : public CheckerVisitor<PointerSubChecker> {
- BuiltinBug *BT;
-public:
- PointerSubChecker() : BT(0) {}
- static void *getTag();
- void PreVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B);
-};
-}
-
-void *PointerSubChecker::getTag() {
- static int x;
- return &x;
-}
-
-void PointerSubChecker::PreVisitBinaryOperator(CheckerContext &C,
- const BinaryOperator *B) {
- // When doing pointer subtraction, if the two pointers do not point to the
- // same memory chunk, emit a warning.
- if (B->getOpcode() != BO_Sub)
- return;
-
- const GRState *state = C.getState();
- SVal LV = state->getSVal(B->getLHS());
- SVal RV = state->getSVal(B->getRHS());
-
- const MemRegion *LR = LV.getAsRegion();
- const MemRegion *RR = RV.getAsRegion();
-
- if (!(LR && RR))
- return;
-
- const MemRegion *BaseLR = LR->getBaseRegion();
- const MemRegion *BaseRR = RR->getBaseRegion();
-
- if (BaseLR == BaseRR)
- return;
-
- // Allow arithmetic on different symbolic regions.
- if (isa<SymbolicRegion>(BaseLR) || isa<SymbolicRegion>(BaseRR))
- return;
-
- if (ExplodedNode *N = C.generateNode()) {
- if (!BT)
- BT = new BuiltinBug("Pointer subtraction",
- "Subtraction of two pointers that do not point to "
- "the same memory chunk may cause incorrect result.");
- RangedBugReport *R = new RangedBugReport(*BT, BT->getDescription(), N);
- R->addRange(B->getSourceRange());
- C.EmitReport(R);
- }
-}
-
-void ento::RegisterPointerSubChecker(ExprEngine &Eng) {
- Eng.registerCheck(new PointerSubChecker());
-}
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/PthreadLockChecker.cpp b/clang/lib/StaticAnalyzer/EntoSA/Checkers/PthreadLockChecker.cpp
deleted file mode 100644
index 7a91696c92c..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/PthreadLockChecker.cpp
+++ /dev/null
@@ -1,147 +0,0 @@
-//===--- PthreadLockChecker.h - Undefined arguments checker ----*- C++ -*--===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This defines PthreadLockChecker, a simple lock -> unlock checker. Eventually
-// this shouldn't be registered with ExprEngineInternalChecks.
-//
-//===----------------------------------------------------------------------===//
-
-#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
-#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
-#include "clang/StaticAnalyzer/PathSensitive/GRStateTrait.h"
-#include "ExprEngineExperimentalChecks.h"
-#include "llvm/ADT/ImmutableSet.h"
-
-using namespace clang;
-using namespace ento;
-
-namespace {
-class PthreadLockChecker
- : public CheckerVisitor<PthreadLockChecker> {
- BugType *BT;
-public:
- PthreadLockChecker() : BT(0) {}
- static void *getTag() {
- static int x = 0;
- return &x;
- }
- void PostVisitCallExpr(CheckerContext &C, const CallExpr *CE);
-
- void AcquireLock(CheckerContext &C, const CallExpr *CE,
- SVal lock, bool isTryLock);
-
- void ReleaseLock(CheckerContext &C, const CallExpr *CE,
- SVal lock);
-
-};
-} // end anonymous namespace
-
-// GDM Entry for tracking lock state.
-namespace { class LockSet {}; }
-namespace clang {
-namespace ento {
-template <> struct GRStateTrait<LockSet> :
- public GRStatePartialTrait<llvm::ImmutableSet<const MemRegion*> > {
- static void* GDMIndex() { return PthreadLockChecker::getTag(); }
-};
-} // end GR namespace
-} // end clang namespace
-
-void ento::RegisterPthreadLockChecker(ExprEngine &Eng) {
- Eng.registerCheck(new PthreadLockChecker());
-}
-
-
-void PthreadLockChecker::PostVisitCallExpr(CheckerContext &C,
- const CallExpr *CE) {
- const GRState *state = C.getState();
- const Expr *Callee = CE->getCallee();
- const FunctionTextRegion *R =
- dyn_cast_or_null<FunctionTextRegion>(state->getSVal(Callee).getAsRegion());
-
- if (!R)
- return;
-
- IdentifierInfo *II = R->getDecl()->getIdentifier();
- if (!II) // if no identifier, not a simple C function
- return;
- llvm::StringRef FName = II->getName();
-
- if (FName == "pthread_mutex_lock") {
- if (CE->getNumArgs() != 1)
- return;
- AcquireLock(C, CE, state->getSVal(CE->getArg(0)), false);
- }
- else if (FName == "pthread_mutex_trylock") {
- if (CE->getNumArgs() != 1)
- return;
- AcquireLock(C, CE, state->getSVal(CE->getArg(0)), true);
- }
- else if (FName == "pthread_mutex_unlock") {
- if (CE->getNumArgs() != 1)
- return;
- ReleaseLock(C, CE, state->getSVal(CE->getArg(0)));
- }
-}
-
-void PthreadLockChecker::AcquireLock(CheckerContext &C, const CallExpr *CE,
- SVal lock, bool isTryLock) {
-
- const MemRegion *lockR = lock.getAsRegion();
- if (!lockR)
- return;
-
- const GRState *state = C.getState();
-
- SVal X = state->getSVal(CE);
- if (X.isUnknownOrUndef())
- return;
-
- DefinedSVal retVal = cast<DefinedSVal>(X);
- const GRState *lockSucc = state;
-
- if (isTryLock) {
- // Bifurcate the state, and allow a mode where the lock acquisition fails.
- const GRState *lockFail;
- llvm::tie(lockFail, lockSucc) = state->assume(retVal);
- assert(lockFail && lockSucc);
- C.addTransition(C.generateNode(CE, lockFail));
- }
- else {
- // Assume that the return value was 0.
- lockSucc = state->assume(retVal, false);
- assert(lockSucc);
- }
-
- // Record that the lock was acquired.
- lockSucc = lockSucc->add<LockSet>(lockR);
-
- C.addTransition(lockSucc != state ? C.generateNode(CE, lockSucc) :
- C.getPredecessor());
-}
-
-void PthreadLockChecker::ReleaseLock(CheckerContext &C, const CallExpr *CE,
- SVal lock) {
-
- const MemRegion *lockR = lock.getAsRegion();
- if (!lockR)
- return;
-
- const GRState *state = C.getState();
-
- // Record that the lock was released.
- // FIXME: Handle unlocking locks that were never acquired. This may
- // require IPA for wrappers.
- const GRState *unlockState = state->remove<LockSet>(lockR);
-
- if (state == unlockState)
- return;
-
- C.addTransition(C.generateNode(CE, unlockState));
-}
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/ReturnPointerRangeChecker.cpp b/clang/lib/StaticAnalyzer/EntoSA/Checkers/ReturnPointerRangeChecker.cpp
deleted file mode 100644
index a56c1b65846..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/ReturnPointerRangeChecker.cpp
+++ /dev/null
@@ -1,95 +0,0 @@
-//== ReturnPointerRangeChecker.cpp ------------------------------*- C++ -*--==//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines ReturnPointerRangeChecker, which is a path-sensitive check
-// which looks for an out-of-bound pointer being returned to callers.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ExprEngineInternalChecks.h"
-#include "clang/StaticAnalyzer/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
-#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
-
-using namespace clang;
-using namespace ento;
-
-namespace {
-class ReturnPointerRangeChecker :
- public CheckerVisitor<ReturnPointerRangeChecker> {
- BuiltinBug *BT;
-public:
- ReturnPointerRangeChecker() : BT(0) {}
- static void *getTag();
- void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *RS);
-};
-}
-
-void ento::RegisterReturnPointerRangeChecker(ExprEngine &Eng) {
- Eng.registerCheck(new ReturnPointerRangeChecker());
-}
-
-void *ReturnPointerRangeChecker::getTag() {
- static int x = 0; return &x;
-}
-
-void ReturnPointerRangeChecker::PreVisitReturnStmt(CheckerContext &C,
- const ReturnStmt *RS) {
- const GRState *state = C.getState();
-
- const Expr *RetE = RS->getRetValue();
- if (!RetE)
- return;
-
- SVal V = state->getSVal(RetE);
- const MemRegion *R = V.getAsRegion();
-
- const ElementRegion *ER = dyn_cast_or_null<ElementRegion>(R);
- if (!ER)
- return;
-
- DefinedOrUnknownSVal Idx = cast<DefinedOrUnknownSVal>(ER->getIndex());
- // Zero index is always in bound, this also passes ElementRegions created for
- // pointer casts.
- if (Idx.isZeroConstant())
- return;
- // FIXME: All of this out-of-bounds checking should eventually be refactored
- // into a common place.
-
- DefinedOrUnknownSVal NumElements
- = C.getStoreManager().getSizeInElements(state, ER->getSuperRegion(),
- ER->getValueType());
-
- const GRState *StInBound = state->assumeInBound(Idx, NumElements, true);
- const GRState *StOutBound = state->assumeInBound(Idx, NumElements, false);
- if (StOutBound && !StInBound) {
- ExplodedNode *N = C.generateSink(StOutBound);
-
- if (!N)
- return;
-
- // FIXME: This bug correspond to CWE-466. Eventually we should have bug
- // types explicitly reference such exploit categories (when applicable).
- if (!BT)
- BT = new BuiltinBug("Return of pointer value outside of expected range",
- "Returned pointer value points outside the original object "
- "(potential buffer overflow)");
-
- // FIXME: It would be nice to eventually make this diagnostic more clear,
- // e.g., by referencing the original declaration or by saying *why* this
- // reference is outside the range.
-
- // Generate a report for this bug.
- RangedBugReport *report =
- new RangedBugReport(*BT, BT->getDescription(), N);
-
- report->addRange(RetE->getSourceRange());
- C.EmitReport(report);
- }
-}
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/ReturnUndefChecker.cpp b/clang/lib/StaticAnalyzer/EntoSA/Checkers/ReturnUndefChecker.cpp
deleted file mode 100644
index 50ffd322db1..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/ReturnUndefChecker.cpp
+++ /dev/null
@@ -1,69 +0,0 @@
-//== ReturnUndefChecker.cpp -------------------------------------*- C++ -*--==//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines ReturnUndefChecker, which is a path-sensitive
-// check which looks for undefined or garbage values being returned to the
-// caller.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ExprEngineInternalChecks.h"
-#include "clang/StaticAnalyzer/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
-#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
-
-using namespace clang;
-using namespace ento;
-
-namespace {
-class ReturnUndefChecker :
- public CheckerVisitor<ReturnUndefChecker> {
- BuiltinBug *BT;
-public:
- ReturnUndefChecker() : BT(0) {}
- static void *getTag();
- void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *RS);
-};
-}
-
-void ento::RegisterReturnUndefChecker(ExprEngine &Eng) {
- Eng.registerCheck(new ReturnUndefChecker());
-}
-
-void *ReturnUndefChecker::getTag() {
- static int x = 0; return &x;
-}
-
-void ReturnUndefChecker::PreVisitReturnStmt(CheckerContext &C,
- const ReturnStmt *RS) {
-
- const Expr *RetE = RS->getRetValue();
- if (!RetE)
- return;
-
- if (!C.getState()->getSVal(RetE).isUndef())
- return;
-
- ExplodedNode *N = C.generateSink();
-
- if (!N)
- return;
-
- if (!BT)
- BT = new BuiltinBug("Garbage return value",
- "Undefined or garbage value returned to caller");
-
- EnhancedBugReport *report =
- new EnhancedBugReport(*BT, BT->getDescription(), N);
-
- report->addRange(RetE->getSourceRange());
- report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, RetE);
-
- C.EmitReport(report);
-}
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/StackAddrLeakChecker.cpp b/clang/lib/StaticAnalyzer/EntoSA/Checkers/StackAddrLeakChecker.cpp
deleted file mode 100644
index 1ec5c32aff0..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/StackAddrLeakChecker.cpp
+++ /dev/null
@@ -1,205 +0,0 @@
-//=== StackAddrLeakChecker.cpp ------------------------------------*- C++ -*--//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines stack address leak checker, which checks if an invalid
-// stack address is stored into a global or heap location. See CERT DCL30-C.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ExprEngineInternalChecks.h"
-#include "clang/StaticAnalyzer/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
-#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
-#include "clang/Basic/SourceManager.h"
-#include "llvm/ADT/SmallString.h"
-using namespace clang;
-using namespace ento;
-
-namespace {
-class StackAddrLeakChecker : public CheckerVisitor<StackAddrLeakChecker> {
- BuiltinBug *BT_stackleak;
- BuiltinBug *BT_returnstack;
-
-public:
- StackAddrLeakChecker() : BT_stackleak(0), BT_returnstack(0) {}
- static void *getTag() {
- static int x;
- return &x;
- }
- void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *RS);
- void evalEndPath(EndPathNodeBuilder &B, void *tag, ExprEngine &Eng);
-private:
- void EmitStackError(CheckerContext &C, const MemRegion *R, const Expr *RetE);
- SourceRange GenName(llvm::raw_ostream &os, const MemRegion *R,
- SourceManager &SM);
-};
-}
-
-void ento::RegisterStackAddrLeakChecker(ExprEngine &Eng) {
- Eng.registerCheck(new StackAddrLeakChecker());
-}
-
-SourceRange StackAddrLeakChecker::GenName(llvm::raw_ostream &os,
- const MemRegion *R,
- SourceManager &SM) {
- // Get the base region, stripping away fields and elements.
- R = R->getBaseRegion();
- SourceRange range;
- os << "Address of ";
-
- // Check if the region is a compound literal.
- if (const CompoundLiteralRegion* CR = dyn_cast<CompoundLiteralRegion>(R)) {
- const CompoundLiteralExpr* CL = CR->getLiteralExpr();
- os << "stack memory associated with a compound literal "
- "declared on line "
- << SM.getInstantiationLineNumber(CL->getLocStart())
- << " returned to caller";
- range = CL->getSourceRange();
- }
- else if (const AllocaRegion* AR = dyn_cast<AllocaRegion>(R)) {
- const Expr* ARE = AR->getExpr();
- SourceLocation L = ARE->getLocStart();
- range = ARE->getSourceRange();
- os << "stack memory allocated by call to alloca() on line "
- << SM.getInstantiationLineNumber(L);
- }
- else if (const BlockDataRegion *BR = dyn_cast<BlockDataRegion>(R)) {
- const BlockDecl *BD = BR->getCodeRegion()->getDecl();
- SourceLocation L = BD->getLocStart();
- range = BD->getSourceRange();
- os << "stack-allocated block declared on line "
- << SM.getInstantiationLineNumber(L);
- }
- else if (const VarRegion *VR = dyn_cast<VarRegion>(R)) {
- os << "stack memory associated with local variable '"
- << VR->getString() << '\'';
- range = VR->getDecl()->getSourceRange();
- }
- else {
- assert(false && "Invalid region in ReturnStackAddressChecker.");
- }
-
- return range;
-}
-
-void StackAddrLeakChecker::EmitStackError(CheckerContext &C, const MemRegion *R,
- const Expr *RetE) {
- ExplodedNode *N = C.generateSink();
-
- if (!N)
- return;
-
- if (!BT_returnstack)
- BT_returnstack=new BuiltinBug("Return of address to stack-allocated memory");
-
- // Generate a report for this bug.
- llvm::SmallString<512> buf;
- llvm::raw_svector_ostream os(buf);
- SourceRange range = GenName(os, R, C.getSourceManager());
- os << " returned to caller";
- RangedBugReport *report = new RangedBugReport(*BT_returnstack, os.str(), N);
- report->addRange(RetE->getSourceRange());
- if (range.isValid())
- report->addRange(range);
-
- C.EmitReport(report);
-}
-
-void StackAddrLeakChecker::PreVisitReturnStmt(CheckerContext &C,
- const ReturnStmt *RS) {
-
- const Expr *RetE = RS->getRetValue();
- if (!RetE)
- return;
-
- SVal V = C.getState()->getSVal(RetE);
- const MemRegion *R = V.getAsRegion();
-
- if (!R || !R->hasStackStorage())
- return;
-
- if (R->hasStackStorage()) {
- EmitStackError(C, R, RetE);
- return;
- }
-}
-
-void StackAddrLeakChecker::evalEndPath(EndPathNodeBuilder &B, void *tag,
- ExprEngine &Eng) {
- SaveAndRestore<bool> OldHasGen(B.HasGeneratedNode);
- const GRState *state = B.getState();
-
- // Iterate over all bindings to global variables and see if it contains
- // a memory region in the stack space.
- class CallBack : public StoreManager::BindingsHandler {
- private:
- const StackFrameContext *CurSFC;
- public:
- llvm::SmallVector<std::pair<const MemRegion*, const MemRegion*>, 10> V;
-
- CallBack(const LocationContext *LCtx)
- : CurSFC(LCtx->getCurrentStackFrame()) {}
-
- bool HandleBinding(StoreManager &SMgr, Store store,
- const MemRegion *region, SVal val) {
-
- if (!isa<GlobalsSpaceRegion>(region->getMemorySpace()))
- return true;
-
- const MemRegion *vR = val.getAsRegion();
- if (!vR)
- return true;
-
- if (const StackSpaceRegion *SSR =
- dyn_cast<StackSpaceRegion>(vR->getMemorySpace())) {
- // If the global variable holds a location in the current stack frame,
- // record the binding to emit a warning.
- if (SSR->getStackFrame() == CurSFC)
- V.push_back(std::make_pair(region, vR));
- }
-
- return true;
- }
- };
-
- CallBack cb(B.getPredecessor()->getLocationContext());
- state->getStateManager().getStoreManager().iterBindings(state->getStore(),cb);
-
- if (cb.V.empty())
- return;
-
- // Generate an error node.
- ExplodedNode *N = B.generateNode(state, tag, B.getPredecessor());
- if (!N)
- return;
-
- if (!BT_stackleak)
- BT_stackleak =
- new BuiltinBug("Stack address stored into global variable",
- "Stack address was saved into a global variable. "
- "This is dangerous because the address will become "
- "invalid after returning from the function");
-
- for (unsigned i = 0, e = cb.V.size(); i != e; ++i) {
- // Generate a report for this bug.
- llvm::SmallString<512> buf;
- llvm::raw_svector_ostream os(buf);
- SourceRange range = GenName(os, cb.V[i].second,
- Eng.getContext().getSourceManager());
- os << " is still referred to by the global variable '";
- const VarRegion *VR = cast<VarRegion>(cb.V[i].first->getBaseRegion());
- os << VR->getDecl()->getNameAsString()
- << "' upon returning to the caller. This will be a dangling reference";
- RangedBugReport *report = new RangedBugReport(*BT_stackleak, os.str(), N);
- if (range.isValid())
- report->addRange(range);
-
- Eng.getBugReporter().EmitReport(report);
- }
-}
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/StreamChecker.cpp b/clang/lib/StaticAnalyzer/EntoSA/Checkers/StreamChecker.cpp
deleted file mode 100644
index a6d1e079c48..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/StreamChecker.cpp
+++ /dev/null
@@ -1,466 +0,0 @@
-//===-- StreamChecker.cpp -----------------------------------------*- C++ -*--//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines checkers that model and check stream handling functions.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ExprEngineExperimentalChecks.h"
-#include "clang/StaticAnalyzer/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
-#include "clang/StaticAnalyzer/PathSensitive/GRState.h"
-#include "clang/StaticAnalyzer/PathSensitive/GRStateTrait.h"
-#include "clang/StaticAnalyzer/PathSensitive/SymbolManager.h"
-#include "llvm/ADT/ImmutableMap.h"
-
-using namespace clang;
-using namespace ento;
-
-namespace {
-
-struct StreamState {
- enum Kind { Opened, Closed, OpenFailed, Escaped } K;
- const Stmt *S;
-
- StreamState(Kind k, const Stmt *s) : K(k), S(s) {}
-
- bool isOpened() const { return K == Opened; }
- bool isClosed() const { return K == Closed; }
- //bool isOpenFailed() const { return K == OpenFailed; }
- //bool isEscaped() const { return K == Escaped; }
-
- bool operator==(const StreamState &X) const {
- return K == X.K && S == X.S;
- }
-
- static StreamState getOpened(const Stmt *s) { return StreamState(Opened, s); }
- static StreamState getClosed(const Stmt *s) { return StreamState(Closed, s); }
- static StreamState getOpenFailed(const Stmt *s) {
- return StreamState(OpenFailed, s);
- }
- static StreamState getEscaped(const Stmt *s) {
- return StreamState(Escaped, s);
- }
-
- void Profile(llvm::FoldingSetNodeID &ID) const {
- ID.AddInteger(K);
- ID.AddPointer(S);
- }
-};
-
-class StreamChecker : public CheckerVisitor<StreamChecker> {
- IdentifierInfo *II_fopen, *II_tmpfile, *II_fclose, *II_fread, *II_fwrite,
- *II_fseek, *II_ftell, *II_rewind, *II_fgetpos, *II_fsetpos,
- *II_clearerr, *II_feof, *II_ferror, *II_fileno;
- BuiltinBug *BT_nullfp, *BT_illegalwhence, *BT_doubleclose, *BT_ResourceLeak;
-
-public:
- StreamChecker()
- : II_fopen(0), II_tmpfile(0) ,II_fclose(0), II_fread(0), II_fwrite(0),
- II_fseek(0), II_ftell(0), II_rewind(0), II_fgetpos(0), II_fsetpos(0),
- II_clearerr(0), II_feof(0), II_ferror(0), II_fileno(0),
- BT_nullfp(0), BT_illegalwhence(0), BT_doubleclose(0),
- BT_ResourceLeak(0) {}
-
- static void *getTag() {
- static int x;
- return &x;
- }
-
- virtual bool evalCallExpr(CheckerContext &C, const CallExpr *CE);
- void evalDeadSymbols(CheckerContext &C, SymbolReaper &SymReaper);
- void evalEndPath(EndPathNodeBuilder &B, void *tag, ExprEngine &Eng);
- void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S);
-
-private:
- void Fopen(CheckerContext &C, const CallExpr *CE);
- void Tmpfile(CheckerContext &C, const CallExpr *CE);
- void Fclose(CheckerContext &C, const CallExpr *CE);
- void Fread(CheckerContext &C, const CallExpr *CE);
- void Fwrite(CheckerContext &C, const CallExpr *CE);
- void Fseek(CheckerContext &C, const CallExpr *CE);
- void Ftell(CheckerContext &C, const CallExpr *CE);
- void Rewind(CheckerContext &C, const CallExpr *CE);
- void Fgetpos(CheckerContext &C, const CallExpr *CE);
- void Fsetpos(CheckerContext &C, const CallExpr *CE);
- void Clearerr(CheckerContext &C, const CallExpr *CE);
- void Feof(CheckerContext &C, const CallExpr *CE);
- void Ferror(CheckerContext &C, const CallExpr *CE);
- void Fileno(CheckerContext &C, const CallExpr *CE);
-
- void OpenFileAux(CheckerContext &C, const CallExpr *CE);
-
- const GRState *CheckNullStream(SVal SV, const GRState *state,
- CheckerContext &C);
- const GRState *CheckDoubleClose(const CallExpr *CE, const GRState *state,
- CheckerContext &C);
-};
-
-} // end anonymous namespace
-
-namespace clang {
-namespace ento {
- template <>
- struct GRStateTrait<StreamState>
- : public GRStatePartialTrait<llvm::ImmutableMap<SymbolRef, StreamState> > {
- static void *GDMIndex() { return StreamChecker::getTag(); }
- };
-}
-}
-
-void ento::RegisterStreamChecker(ExprEngine &Eng) {
- Eng.registerCheck(new StreamChecker());
-}
-
-bool StreamChecker::evalCallExpr(CheckerContext &C, const CallExpr *CE) {
- const GRState *state = C.getState();
- const Expr *Callee = CE->getCallee();
- SVal L = state->getSVal(Callee);
- const FunctionDecl *FD = L.getAsFunctionDecl();
- if (!FD)
- return false;
-
- ASTContext &Ctx = C.getASTContext();
- if (!II_fopen)
- II_fopen = &Ctx.Idents.get("fopen");
- if (!II_tmpfile)
- II_tmpfile = &Ctx.Idents.get("tmpfile");
- if (!II_fclose)
- II_fclose = &Ctx.Idents.get("fclose");
- if (!II_fread)
- II_fread = &Ctx.Idents.get("fread");
- if (!II_fwrite)
- II_fwrite = &Ctx.Idents.get("fwrite");
- if (!II_fseek)
- II_fseek = &Ctx.Idents.get("fseek");
- if (!II_ftell)
- II_ftell = &Ctx.Idents.get("ftell");
- if (!II_rewind)
- II_rewind = &Ctx.Idents.get("rewind");
- if (!II_fgetpos)
- II_fgetpos = &Ctx.Idents.get("fgetpos");
- if (!II_fsetpos)
- II_fsetpos = &Ctx.Idents.get("fsetpos");
- if (!II_clearerr)
- II_clearerr = &Ctx.Idents.get("clearerr");
- if (!II_feof)
- II_feof = &Ctx.Idents.get("feof");
- if (!II_ferror)
- II_ferror = &Ctx.Idents.get("ferror");
- if (!II_fileno)
- II_fileno = &Ctx.Idents.get("fileno");
-
- if (FD->getIdentifier() == II_fopen) {
- Fopen(C, CE);
- return true;
- }
- if (FD->getIdentifier() == II_tmpfile) {
- Tmpfile(C, CE);
- return true;
- }
- if (FD->getIdentifier() == II_fclose) {
- Fclose(C, CE);
- return true;
- }
- if (FD->getIdentifier() == II_fread) {
- Fread(C, CE);
- return true;
- }
- if (FD->getIdentifier() == II_fwrite) {
- Fwrite(C, CE);
- return true;
- }
- if (FD->getIdentifier() == II_fseek) {
- Fseek(C, CE);
- return true;
- }
- if (FD->getIdentifier() == II_ftell) {
- Ftell(C, CE);
- return true;
- }
- if (FD->getIdentifier() == II_rewind) {
- Rewind(C, CE);
- return true;
- }
- if (FD->getIdentifier() == II_fgetpos) {
- Fgetpos(C, CE);
- return true;
- }
- if (FD->getIdentifier() == II_fsetpos) {
- Fsetpos(C, CE);
- return true;
- }
- if (FD->getIdentifier() == II_clearerr) {
- Clearerr(C, CE);
- return true;
- }
- if (FD->getIdentifier() == II_feof) {
- Feof(C, CE);
- return true;
- }
- if (FD->getIdentifier() == II_ferror) {
- Ferror(C, CE);
- return true;
- }
- if (FD->getIdentifier() == II_fileno) {
- Fileno(C, CE);
- return true;
- }
-
- return false;
-}
-
-void StreamChecker::Fopen(CheckerContext &C, const CallExpr *CE) {
- OpenFileAux(C, CE);
-}
-
-void StreamChecker::Tmpfile(CheckerContext &C, const CallExpr *CE) {
- OpenFileAux(C, CE);
-}
-
-void StreamChecker::OpenFileAux(CheckerContext &C, const CallExpr *CE) {
- const GRState *state = C.getState();
- unsigned Count = C.getNodeBuilder().getCurrentBlockCount();
- SValBuilder &svalBuilder = C.getSValBuilder();
- DefinedSVal RetVal =
- cast<DefinedSVal>(svalBuilder.getConjuredSymbolVal(0, CE, Count));
- state = state->BindExpr(CE, RetVal);
-
- ConstraintManager &CM = C.getConstraintManager();
- // Bifurcate the state into two: one with a valid FILE* pointer, the other
- // with a NULL.
- const GRState *stateNotNull, *stateNull;
- llvm::tie(stateNotNull, stateNull) = CM.assumeDual(state, RetVal);
-
- if (SymbolRef Sym = RetVal.getAsSymbol()) {
- // if RetVal is not NULL, set the symbol's state to Opened.
- stateNotNull =
- stateNotNull->set<StreamState>(Sym,StreamState::getOpened(CE));
- stateNull =
- stateNull->set<StreamState>(Sym, StreamState::getOpenFailed(CE));
-
- C.addTransition(stateNotNull);
- C.addTransition(stateNull);
- }
-}
-
-void StreamChecker::Fclose(CheckerContext &C, const CallExpr *CE) {
- const GRState *state = CheckDoubleClose(CE, C.getState(), C);
- if (state)
- C.addTransition(state);
-}
-
-void StreamChecker::Fread(CheckerContext &C, const CallExpr *CE) {
- const GRState *state = C.getState();
- if (!CheckNullStream(state->getSVal(CE->getArg(3)), state, C))
- return;
-}
-
-void StreamChecker::Fwrite(CheckerContext &C, const CallExpr *CE) {
- const GRState *state = C.getState();
- if (!CheckNullStream(state->getSVal(CE->getArg(3)), state, C))
- return;
-}
-
-void StreamChecker::Fseek(CheckerContext &C, const CallExpr *CE) {
- const GRState *state = C.getState();
- if (!(state = CheckNullStream(state->getSVal(CE->getArg(0)), state, C)))
- return;
- // Check the legality of the 'whence' argument of 'fseek'.
- SVal Whence = state->getSVal(CE->getArg(2));
- const nonloc::ConcreteInt *CI = dyn_cast<nonloc::ConcreteInt>(&Whence);
-
- if (!CI)
- return;
-
- int64_t x = CI->getValue().getSExtValue();
- if (x >= 0 && x <= 2)
- return;
-
- if (ExplodedNode *N = C.generateNode(state)) {
- if (!BT_illegalwhence)
- BT_illegalwhence = new BuiltinBug("Illegal whence argument",
- "The whence argument to fseek() should be "
- "SEEK_SET, SEEK_END, or SEEK_CUR.");
- BugReport *R = new BugReport(*BT_illegalwhence,
- BT_illegalwhence->getDescription(), N);
- C.EmitReport(R);
- }
-}
-
-void StreamChecker::Ftell(CheckerContext &C, const CallExpr *CE) {
- const GRState *state = C.getState();
- if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
- return;
-}
-
-void StreamChecker::Rewind(CheckerContext &C, const CallExpr *CE) {
- const GRState *state = C.getState();
- if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
- return;
-}
-
-void StreamChecker::Fgetpos(CheckerContext &C, const CallExpr *CE) {
- const GRState *state = C.getState();
- if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
- return;
-}
-
-void StreamChecker::Fsetpos(CheckerContext &C, const CallExpr *CE) {
- const GRState *state = C.getState();
- if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
- return;
-}
-
-void StreamChecker::Clearerr(CheckerContext &C, const CallExpr *CE) {
- const GRState *state = C.getState();
- if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
- return;
-}
-
-void StreamChecker::Feof(CheckerContext &C, const CallExpr *CE) {
- const GRState *state = C.getState();
- if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
- return;
-}
-
-void StreamChecker::Ferror(CheckerContext &C, const CallExpr *CE) {
- const GRState *state = C.getState();
- if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
- return;
-}
-
-void StreamChecker::Fileno(CheckerContext &C, const CallExpr *CE) {
- const GRState *state = C.getState();
- if (!CheckNullStream(state->getSVal(CE->getArg(0)), state, C))
- return;
-}
-
-const GRState *StreamChecker::CheckNullStream(SVal SV, const GRState *state,
- CheckerContext &C) {
- const DefinedSVal *DV = dyn_cast<DefinedSVal>(&SV);
- if (!DV)
- return 0;
-
- ConstraintManager &CM = C.getConstraintManager();
- const GRState *stateNotNull, *stateNull;
- llvm::tie(stateNotNull, stateNull) = CM.assumeDual(state, *DV);
-
- if (!stateNotNull && stateNull) {
- if (ExplodedNode *N = C.generateSink(stateNull)) {
- if (!BT_nullfp)
- BT_nullfp = new BuiltinBug("NULL stream pointer",
- "Stream pointer might be NULL.");
- BugReport *R =new BugReport(*BT_nullfp, BT_nullfp->getDescription(), N);
- C.EmitReport(R);
- }
- return 0;
- }
- return stateNotNull;
-}
-
-const GRState *StreamChecker::CheckDoubleClose(const CallExpr *CE,
- const GRState *state,
- CheckerContext &C) {
- SymbolRef Sym = state->getSVal(CE->getArg(0)).getAsSymbol();
- if (!Sym)
- return state;
-
- const StreamState *SS = state->get<StreamState>(Sym);
-
- // If the file stream is not tracked, return.
- if (!SS)
- return state;
-
- // Check: Double close a File Descriptor could cause undefined behaviour.
- // Conforming to man-pages
- if (SS->isClosed()) {
- ExplodedNode *N = C.generateSink();
- if (N) {
- if (!BT_doubleclose)
- BT_doubleclose = new BuiltinBug("Double fclose",
- "Try to close a file Descriptor already"
- " closed. Cause undefined behaviour.");
- BugReport *R = new BugReport(*BT_doubleclose,
- BT_doubleclose->getDescription(), N);
- C.EmitReport(R);
- }
- return NULL;
- }
-
- // Close the File Descriptor.
- return state->set<StreamState>(Sym, StreamState::getClosed(CE));
-}
-
-void StreamChecker::evalDeadSymbols(CheckerContext &C,SymbolReaper &SymReaper) {
- for (SymbolReaper::dead_iterator I = SymReaper.dead_begin(),
- E = SymReaper.dead_end(); I != E; ++I) {
- SymbolRef Sym = *I;
- const GRState *state = C.getState();
- const StreamState *SS = state->get<StreamState>(Sym);
- if (!SS)
- return;
-
- if (SS->isOpened()) {
- ExplodedNode *N = C.generateSink();
- if (N) {
- if (!BT_ResourceLeak)
- BT_ResourceLeak = new BuiltinBug("Resource Leak",
- "Opened File never closed. Potential Resource leak.");
- BugReport *R = new BugReport(*BT_ResourceLeak,
- BT_ResourceLeak->getDescription(), N);
- C.EmitReport(R);
- }
- }
- }
-}
-
-void StreamChecker::evalEndPath(EndPathNodeBuilder &B, void *tag,
- ExprEngine &Eng) {
- SaveAndRestore<bool> OldHasGen(B.HasGeneratedNode);
- const GRState *state = B.getState();
- typedef llvm::ImmutableMap<SymbolRef, StreamState> SymMap;
- SymMap M = state->get<StreamState>();
-
- for (SymMap::iterator I = M.begin(), E = M.end(); I != E; ++I) {
- StreamState SS = I->second;
- if (SS.isOpened()) {
- ExplodedNode *N = B.generateNode(state, tag, B.getPredecessor());
- if (N) {
- if (!BT_ResourceLeak)
- BT_ResourceLeak = new BuiltinBug("Resource Leak",
- "Opened File never closed. Potential Resource leak.");
- BugReport *R = new BugReport(*BT_ResourceLeak,
- BT_ResourceLeak->getDescription(), N);
- Eng.getBugReporter().EmitReport(R);
- }
- }
- }
-}
-
-void StreamChecker::PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S) {
- const Expr *RetE = S->getRetValue();
- if (!RetE)
- return;
-
- const GRState *state = C.getState();
- SymbolRef Sym = state->getSVal(RetE).getAsSymbol();
-
- if (!Sym)
- return;
-
- const StreamState *SS = state->get<StreamState>(Sym);
- if(!SS)
- return;
-
- if (SS->isOpened())
- state = state->set<StreamState>(Sym, StreamState::getEscaped(S));
-
- C.addTransition(state);
-}
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/UndefBranchChecker.cpp b/clang/lib/StaticAnalyzer/EntoSA/Checkers/UndefBranchChecker.cpp
deleted file mode 100644
index c0b3b7afec7..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/UndefBranchChecker.cpp
+++ /dev/null
@@ -1,120 +0,0 @@
-//=== UndefBranchChecker.cpp -----------------------------------*- C++ -*--===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines UndefBranchChecker, which checks for undefined branch
-// condition.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ExprEngineInternalChecks.h"
-#include "clang/StaticAnalyzer/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/PathSensitive/Checker.h"
-
-using namespace clang;
-using namespace ento;
-
-namespace {
-
-class UndefBranchChecker : public Checker {
- BuiltinBug *BT;
-
- struct FindUndefExpr {
- GRStateManager& VM;
- const GRState* St;
-
- FindUndefExpr(GRStateManager& V, const GRState* S) : VM(V), St(S) {}
-
- const Expr* FindExpr(const Expr* Ex) {
- if (!MatchesCriteria(Ex))
- return 0;
-
- for (Stmt::const_child_iterator I = Ex->child_begin(),
- E = Ex->child_end();I!=E;++I)
- if (const Expr* ExI = dyn_cast_or_null<Expr>(*I)) {
- const Expr* E2 = FindExpr(ExI);
- if (E2) return E2;
- }
-
- return Ex;
- }
-
- bool MatchesCriteria(const Expr* Ex) { return St->getSVal(Ex).isUndef(); }
- };
-
-public:
- UndefBranchChecker() : BT(0) {}
- static void *getTag();
- void VisitBranchCondition(BranchNodeBuilder &Builder, ExprEngine &Eng,
- const Stmt *Condition, void *tag);
-};
-
-}
-
-void ento::RegisterUndefBranchChecker(ExprEngine &Eng) {
- Eng.registerCheck(new UndefBranchChecker());
-}
-
-void *UndefBranchChecker::getTag() {
- static int x;
- return &x;
-}
-
-void UndefBranchChecker::VisitBranchCondition(BranchNodeBuilder &Builder,
- ExprEngine &Eng,
- const Stmt *Condition, void *tag){
- const GRState *state = Builder.getState();
- SVal X = state->getSVal(Condition);
- if (X.isUndef()) {
- ExplodedNode *N = Builder.generateNode(state, true);
- if (N) {
- N->markAsSink();
- if (!BT)
- BT = new BuiltinBug("Branch condition evaluates to a garbage value");
-
- // What's going on here: we want to highlight the subexpression of the
- // condition that is the most likely source of the "uninitialized
- // branch condition." We do a recursive walk of the condition's
- // subexpressions and roughly look for the most nested subexpression
- // that binds to Undefined. We then highlight that expression's range.
- BlockEdge B = cast<BlockEdge>(N->getLocation());
- const Expr* Ex = cast<Expr>(B.getSrc()->getTerminatorCondition());
- assert (Ex && "Block must have a terminator.");
-
- // Get the predecessor node and check if is a PostStmt with the Stmt
- // being the terminator condition. We want to inspect the state
- // of that node instead because it will contain main information about
- // the subexpressions.
- assert (!N->pred_empty());
-
- // Note: any predecessor will do. They should have identical state,
- // since all the BlockEdge did was act as an error sink since the value
- // had to already be undefined.
- ExplodedNode *PrevN = *N->pred_begin();
- ProgramPoint P = PrevN->getLocation();
- const GRState* St = N->getState();
-
- if (PostStmt* PS = dyn_cast<PostStmt>(&P))
- if (PS->getStmt() == Ex)
- St = PrevN->getState();
-
- FindUndefExpr FindIt(Eng.getStateManager(), St);
- Ex = FindIt.FindExpr(Ex);
-
- // Emit the bug report.
- EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getDescription(),N);
- R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Ex);
- R->addRange(Ex->getSourceRange());
-
- Eng.getBugReporter().EmitReport(R);
- }
-
- Builder.markInfeasible(true);
- Builder.markInfeasible(false);
- }
-}
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/UndefCapturedBlockVarChecker.cpp b/clang/lib/StaticAnalyzer/EntoSA/Checkers/UndefCapturedBlockVarChecker.cpp
deleted file mode 100644
index 57e698bb7c2..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/UndefCapturedBlockVarChecker.cpp
+++ /dev/null
@@ -1,102 +0,0 @@
-// UndefCapturedBlockVarChecker.cpp - Uninitialized captured vars -*- C++ -*-=//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This checker detects blocks that capture uninitialized values.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ExprEngineInternalChecks.h"
-#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
-#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
-#include "clang/StaticAnalyzer/BugReporter/BugType.h"
-#include "llvm/Support/raw_ostream.h"
-
-using namespace clang;
-using namespace ento;
-
-namespace {
-class UndefCapturedBlockVarChecker
- : public CheckerVisitor<UndefCapturedBlockVarChecker> {
- BugType *BT;
-
-public:
- UndefCapturedBlockVarChecker() : BT(0) {}
- static void *getTag() { static int tag = 0; return &tag; }
- void PostVisitBlockExpr(CheckerContext &C, const BlockExpr *BE);
-};
-} // end anonymous namespace
-
-void ento::RegisterUndefCapturedBlockVarChecker(ExprEngine &Eng) {
- Eng.registerCheck(new UndefCapturedBlockVarChecker());
-}
-
-static const BlockDeclRefExpr *FindBlockDeclRefExpr(const Stmt *S,
- const VarDecl *VD){
- if (const BlockDeclRefExpr *BR = dyn_cast<BlockDeclRefExpr>(S))
- if (BR->getDecl() == VD)
- return BR;
-
- for (Stmt::const_child_iterator I = S->child_begin(), E = S->child_end();
- I!=E; ++I)
- if (const Stmt *child = *I) {
- const BlockDeclRefExpr *BR = FindBlockDeclRefExpr(child, VD);
- if (BR)
- return BR;
- }
-
- return NULL;
-}
-
-void
-UndefCapturedBlockVarChecker::PostVisitBlockExpr(CheckerContext &C,
- const BlockExpr *BE) {
- if (!BE->hasBlockDeclRefExprs())
- return;
-
- const GRState *state = C.getState();
- const BlockDataRegion *R =
- cast<BlockDataRegion>(state->getSVal(BE).getAsRegion());
-
- BlockDataRegion::referenced_vars_iterator I = R->referenced_vars_begin(),
- E = R->referenced_vars_end();
-
- for (; I != E; ++I) {
- // This VarRegion is the region associated with the block; we need
- // the one associated with the encompassing context.
- const VarRegion *VR = *I;
- const VarDecl *VD = VR->getDecl();
-
- if (VD->getAttr<BlocksAttr>() || !VD->hasLocalStorage())
- continue;
-
- // Get the VarRegion associated with VD in the local stack frame.
- const LocationContext *LC = C.getPredecessor()->getLocationContext();
- VR = C.getSValBuilder().getRegionManager().getVarRegion(VD, LC);
-
- if (state->getSVal(VR).isUndef())
- if (ExplodedNode *N = C.generateSink()) {
- if (!BT)
- BT = new BuiltinBug("Captured block variable is uninitialized");
-
- // Generate a bug report.
- llvm::SmallString<128> buf;
- llvm::raw_svector_ostream os(buf);
-
- os << "Variable '" << VD->getName() << "' is captured by block with "
- "a garbage value";
-
- EnhancedBugReport *R = new EnhancedBugReport(*BT, os.str(), N);
- if (const Expr *Ex = FindBlockDeclRefExpr(BE->getBody(), VD))
- R->addRange(Ex->getSourceRange());
- R->addVisitorCreator(bugreporter::registerFindLastStore, VR);
- // need location of block
- C.EmitReport(R);
- }
- }
-}
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/UndefResultChecker.cpp b/clang/lib/StaticAnalyzer/EntoSA/Checkers/UndefResultChecker.cpp
deleted file mode 100644
index 91e489bd2a4..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/UndefResultChecker.cpp
+++ /dev/null
@@ -1,87 +0,0 @@
-//=== UndefResultChecker.cpp ------------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This defines UndefResultChecker, a builtin check in ExprEngine that
-// performs checks for undefined results of non-assignment binary operators.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ExprEngineInternalChecks.h"
-#include "clang/StaticAnalyzer/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
-#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
-
-using namespace clang;
-using namespace ento;
-
-namespace {
-class UndefResultChecker
- : public CheckerVisitor<UndefResultChecker> {
-
- BugType *BT;
-
-public:
- UndefResultChecker() : BT(0) {}
- static void *getTag() { static int tag = 0; return &tag; }
- void PostVisitBinaryOperator(CheckerContext &C, const BinaryOperator *B);
-};
-} // end anonymous namespace
-
-void ento::RegisterUndefResultChecker(ExprEngine &Eng) {
- Eng.registerCheck(new UndefResultChecker());
-}
-
-void UndefResultChecker::PostVisitBinaryOperator(CheckerContext &C,
- const BinaryOperator *B) {
- const GRState *state = C.getState();
- if (state->getSVal(B).isUndef()) {
- // Generate an error node.
- ExplodedNode *N = C.generateSink();
- if (!N)
- return;
-
- if (!BT)
- BT = new BuiltinBug("Result of operation is garbage or undefined");
-
- llvm::SmallString<256> sbuf;
- llvm::raw_svector_ostream OS(sbuf);
- const Expr *Ex = NULL;
- bool isLeft = true;
-
- if (state->getSVal(B->getLHS()).isUndef()) {
- Ex = B->getLHS()->IgnoreParenCasts();
- isLeft = true;
- }
- else if (state->getSVal(B->getRHS()).isUndef()) {
- Ex = B->getRHS()->IgnoreParenCasts();
- isLeft = false;
- }
-
- if (Ex) {
- OS << "The " << (isLeft ? "left" : "right")
- << " operand of '"
- << BinaryOperator::getOpcodeStr(B->getOpcode())
- << "' is a garbage value";
- }
- else {
- // Neither operand was undefined, but the result is undefined.
- OS << "The result of the '"
- << BinaryOperator::getOpcodeStr(B->getOpcode())
- << "' expression is undefined";
- }
- EnhancedBugReport *report = new EnhancedBugReport(*BT, OS.str(), N);
- if (Ex) {
- report->addRange(Ex->getSourceRange());
- report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Ex);
- }
- else
- report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, B);
- C.EmitReport(report);
- }
-}
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/UndefinedArraySubscriptChecker.cpp b/clang/lib/StaticAnalyzer/EntoSA/Checkers/UndefinedArraySubscriptChecker.cpp
deleted file mode 100644
index 2cd293b2f42..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/UndefinedArraySubscriptChecker.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-//===--- UndefinedArraySubscriptChecker.h ----------------------*- C++ -*--===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This defines UndefinedArraySubscriptChecker, a builtin check in ExprEngine
-// that performs checks for undefined array subscripts.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ExprEngineInternalChecks.h"
-#include "clang/StaticAnalyzer/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
-
-using namespace clang;
-using namespace ento;
-
-namespace {
-class UndefinedArraySubscriptChecker
- : public CheckerVisitor<UndefinedArraySubscriptChecker> {
- BugType *BT;
-public:
- UndefinedArraySubscriptChecker() : BT(0) {}
- static void *getTag() {
- static int x = 0;
- return &x;
- }
- void PreVisitArraySubscriptExpr(CheckerContext &C,
- const ArraySubscriptExpr *A);
-};
-} // end anonymous namespace
-
-void ento::RegisterUndefinedArraySubscriptChecker(ExprEngine &Eng) {
- Eng.registerCheck(new UndefinedArraySubscriptChecker());
-}
-
-void
-UndefinedArraySubscriptChecker::PreVisitArraySubscriptExpr(CheckerContext &C,
- const ArraySubscriptExpr *A) {
- if (C.getState()->getSVal(A->getIdx()).isUndef()) {
- if (ExplodedNode *N = C.generateSink()) {
- if (!BT)
- BT = new BuiltinBug("Array subscript is undefined");
-
- // Generate a report for this bug.
- EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N);
- R->addRange(A->getIdx()->getSourceRange());
- R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
- A->getIdx());
- C.EmitReport(R);
- }
- }
-}
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/UndefinedAssignmentChecker.cpp b/clang/lib/StaticAnalyzer/EntoSA/Checkers/UndefinedAssignmentChecker.cpp
deleted file mode 100644
index 3146bbda41e..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/UndefinedAssignmentChecker.cpp
+++ /dev/null
@@ -1,94 +0,0 @@
-//===--- UndefinedAssignmentChecker.h ---------------------------*- C++ -*--==//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This defines UndefinedAssginmentChecker, a builtin check in ExprEngine that
-// checks for assigning undefined values.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ExprEngineInternalChecks.h"
-#include "clang/StaticAnalyzer/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
-
-using namespace clang;
-using namespace ento;
-
-namespace {
-class UndefinedAssignmentChecker
- : public CheckerVisitor<UndefinedAssignmentChecker> {
- BugType *BT;
-public:
- UndefinedAssignmentChecker() : BT(0) {}
- static void *getTag();
- virtual void PreVisitBind(CheckerContext &C, const Stmt *StoreE,
- SVal location, SVal val);
-};
-}
-
-void ento::RegisterUndefinedAssignmentChecker(ExprEngine &Eng){
- Eng.registerCheck(new UndefinedAssignmentChecker());
-}
-
-void *UndefinedAssignmentChecker::getTag() {
- static int x = 0;
- return &x;
-}
-
-void UndefinedAssignmentChecker::PreVisitBind(CheckerContext &C,
- const Stmt *StoreE,
- SVal location,
- SVal val) {
- if (!val.isUndef())
- return;
-
- ExplodedNode *N = C.generateSink();
-
- if (!N)
- return;
-
- const char *str = "Assigned value is garbage or undefined";
-
- if (!BT)
- BT = new BuiltinBug(str);
-
- // Generate a report for this bug.
- const Expr *ex = 0;
-
- while (StoreE) {
- if (const BinaryOperator *B = dyn_cast<BinaryOperator>(StoreE)) {
- if (B->isCompoundAssignmentOp()) {
- const GRState *state = C.getState();
- if (state->getSVal(B->getLHS()).isUndef()) {
- str = "The left expression of the compound assignment is an "
- "uninitialized value. The computed value will also be garbage";
- ex = B->getLHS();
- break;
- }
- }
-
- ex = B->getRHS();
- break;
- }
-
- if (const DeclStmt *DS = dyn_cast<DeclStmt>(StoreE)) {
- const VarDecl* VD = dyn_cast<VarDecl>(DS->getSingleDecl());
- ex = VD->getInit();
- }
-
- break;
- }
-
- EnhancedBugReport *R = new EnhancedBugReport(*BT, str, N);
- if (ex) {
- R->addRange(ex->getSourceRange());
- R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, ex);
- }
- C.EmitReport(R);
-}
-
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/UnixAPIChecker.cpp b/clang/lib/StaticAnalyzer/EntoSA/Checkers/UnixAPIChecker.cpp
deleted file mode 100644
index 9092f93ba72..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/UnixAPIChecker.cpp
+++ /dev/null
@@ -1,277 +0,0 @@
-//= UnixAPIChecker.h - Checks preconditions for various Unix APIs --*- C++ -*-//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This defines UnixAPIChecker, which is an assortment of checks on calls
-// to various, widely used UNIX/Posix functions.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ExprEngineInternalChecks.h"
-#include "clang/Basic/TargetInfo.h"
-#include "clang/StaticAnalyzer/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
-#include "llvm/ADT/Optional.h"
-#include "llvm/ADT/StringSwitch.h"
-#include <fcntl.h>
-
-using namespace clang;
-using namespace ento;
-using llvm::Optional;
-
-namespace {
-class UnixAPIChecker : public CheckerVisitor<UnixAPIChecker> {
- enum SubChecks {
- OpenFn = 0,
- PthreadOnceFn = 1,
- MallocZero = 2,
- NumChecks
- };
-
- BugType *BTypes[NumChecks];
-
-public:
- Optional<uint64_t> Val_O_CREAT;
-
-public:
- UnixAPIChecker() { memset(BTypes, 0, sizeof(*BTypes) * NumChecks); }
- static void *getTag() { static unsigned tag = 0; return &tag; }
-
- void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
-};
-} //end anonymous namespace
-
-void ento::RegisterUnixAPIChecker(ExprEngine &Eng) {
- Eng.registerCheck(new UnixAPIChecker());
-}
-
-//===----------------------------------------------------------------------===//
-// Utility functions.
-//===----------------------------------------------------------------------===//
-
-static inline void LazyInitialize(BugType *&BT, const char *name) {
- if (BT)
- return;
- BT = new BugType(name, "Unix API");
-}
-
-//===----------------------------------------------------------------------===//
-// "open" (man 2 open)
-//===----------------------------------------------------------------------===//
-
-static void CheckOpen(CheckerContext &C, UnixAPIChecker &UC,
- const CallExpr *CE, BugType *&BT) {
- // The definition of O_CREAT is platform specific. We need a better way
- // of querying this information from the checking environment.
- if (!UC.Val_O_CREAT.hasValue()) {
- if (C.getASTContext().Target.getTriple().getVendor() == llvm::Triple::Apple)
- UC.Val_O_CREAT = 0x0200;
- else {
- // FIXME: We need a more general way of getting the O_CREAT value.
- // We could possibly grovel through the preprocessor state, but
- // that would require passing the Preprocessor object to the ExprEngine.
- return;
- }
- }
-
- LazyInitialize(BT, "Improper use of 'open'");
-
- // Look at the 'oflags' argument for the O_CREAT flag.
- const GRState *state = C.getState();
-
- if (CE->getNumArgs() < 2) {
- // The frontend should issue a warning for this case, so this is a sanity
- // check.
- return;
- }
-
- // Now check if oflags has O_CREAT set.
- const Expr *oflagsEx = CE->getArg(1);
- const SVal V = state->getSVal(oflagsEx);
- if (!isa<NonLoc>(V)) {
- // The case where 'V' can be a location can only be due to a bad header,
- // so in this case bail out.
- return;
- }
- NonLoc oflags = cast<NonLoc>(V);
- NonLoc ocreateFlag =
- cast<NonLoc>(C.getSValBuilder().makeIntVal(UC.Val_O_CREAT.getValue(),
- oflagsEx->getType()));
- SVal maskedFlagsUC = C.getSValBuilder().evalBinOpNN(state, BO_And,
- oflags, ocreateFlag,
- oflagsEx->getType());
- if (maskedFlagsUC.isUnknownOrUndef())
- return;
- DefinedSVal maskedFlags = cast<DefinedSVal>(maskedFlagsUC);
-
- // Check if maskedFlags is non-zero.
- const GRState *trueState, *falseState;
- llvm::tie(trueState, falseState) = state->assume(maskedFlags);
-
- // Only emit an error if the value of 'maskedFlags' is properly
- // constrained;
- if (!(trueState && !falseState))
- return;
-
- if (CE->getNumArgs() < 3) {
- ExplodedNode *N = C.generateSink(trueState);
- if (!N)
- return;
-
- EnhancedBugReport *report =
- new EnhancedBugReport(*BT,
- "Call to 'open' requires a third argument when "
- "the 'O_CREAT' flag is set", N);
- report->addRange(oflagsEx->getSourceRange());
- C.EmitReport(report);
- }
-}
-
-//===----------------------------------------------------------------------===//
-// pthread_once
-//===----------------------------------------------------------------------===//
-
-static void CheckPthreadOnce(CheckerContext &C, UnixAPIChecker &,
- const CallExpr *CE, BugType *&BT) {
-
- // This is similar to 'CheckDispatchOnce' in the MacOSXAPIChecker.
- // They can possibly be refactored.
-
- LazyInitialize(BT, "Improper use of 'pthread_once'");
-
- if (CE->getNumArgs() < 1)
- return;
-
- // Check if the first argument is stack allocated. If so, issue a warning
- // because that's likely to be bad news.
- const GRState *state = C.getState();
- const MemRegion *R = state->getSVal(CE->getArg(0)).getAsRegion();
- if (!R || !isa<StackSpaceRegion>(R->getMemorySpace()))
- return;
-
- ExplodedNode *N = C.generateSink(state);
- if (!N)
- return;
-
- llvm::SmallString<256> S;
- llvm::raw_svector_ostream os(S);
- os << "Call to 'pthread_once' uses";
- if (const VarRegion *VR = dyn_cast<VarRegion>(R))
- os << " the local variable '" << VR->getDecl()->getName() << '\'';
- else
- os << " stack allocated memory";
- os << " for the \"control\" value. Using such transient memory for "
- "the control value is potentially dangerous.";
- if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getMemorySpace()))
- os << " Perhaps you intended to declare the variable as 'static'?";
-
- EnhancedBugReport *report = new EnhancedBugReport(*BT, os.str(), N);
- report->addRange(CE->getArg(0)->getSourceRange());
- C.EmitReport(report);
-}
-
-//===----------------------------------------------------------------------===//
-// "malloc" with allocation size 0
-//===----------------------------------------------------------------------===//
-
-// FIXME: Eventually this should be rolled into the MallocChecker, but this
-// check is more basic and is valuable for widespread use.
-static void CheckMallocZero(CheckerContext &C, UnixAPIChecker &UC,
- const CallExpr *CE, BugType *&BT) {
-
- // Sanity check that malloc takes one argument.
- if (CE->getNumArgs() != 1)
- return;
-
- // Check if the allocation size is 0.
- const GRState *state = C.getState();
- SVal argVal = state->getSVal(CE->getArg(0));
-
- if (argVal.isUnknownOrUndef())
- return;
-
- const GRState *trueState, *falseState;
- llvm::tie(trueState, falseState) = state->assume(cast<DefinedSVal>(argVal));
-
- // Is the value perfectly constrained to zero?
- if (falseState && !trueState) {
- ExplodedNode *N = C.generateSink(falseState);
- if (!N)
- return;
-
- // FIXME: Add reference to CERT advisory, and/or C99 standard in bug
- // output.
-
- LazyInitialize(BT, "Undefined allocation of 0 bytes");
-
- EnhancedBugReport *report =
- new EnhancedBugReport(*BT, "Call to 'malloc' has an allocation size"
- " of 0 bytes", N);
- report->addRange(CE->getArg(0)->getSourceRange());
- report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
- CE->getArg(0));
- C.EmitReport(report);
- return;
- }
- // Assume the the value is non-zero going forward.
- assert(trueState);
- if (trueState != state) {
- C.addTransition(trueState);
- }
-}
-
-//===----------------------------------------------------------------------===//
-// Central dispatch function.
-//===----------------------------------------------------------------------===//
-
-typedef void (*SubChecker)(CheckerContext &C, UnixAPIChecker &UC,
- const CallExpr *CE, BugType *&BT);
-namespace {
- class SubCheck {
- SubChecker SC;
- UnixAPIChecker *UC;
- BugType **BT;
- public:
- SubCheck(SubChecker sc, UnixAPIChecker *uc, BugType *& bt) : SC(sc), UC(uc),
- BT(&bt) {}
- SubCheck() : SC(NULL), UC(NULL), BT(NULL) {}
-
- void run(CheckerContext &C, const CallExpr *CE) const {
- if (SC)
- SC(C, *UC, CE, *BT);
- }
- };
-} // end anonymous namespace
-
-void UnixAPIChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
- // Get the callee. All the functions we care about are C functions
- // with simple identifiers.
- const GRState *state = C.getState();
- const Expr *Callee = CE->getCallee();
- const FunctionTextRegion *Fn =
- dyn_cast_or_null<FunctionTextRegion>(state->getSVal(Callee).getAsRegion());
-
- if (!Fn)
- return;
-
- const IdentifierInfo *FI = Fn->getDecl()->getIdentifier();
- if (!FI)
- return;
-
- const SubCheck &SC =
- llvm::StringSwitch<SubCheck>(FI->getName())
- .Case("open",
- SubCheck(CheckOpen, this, BTypes[OpenFn]))
- .Case("pthread_once",
- SubCheck(CheckPthreadOnce, this, BTypes[PthreadOnceFn]))
- .Case("malloc",
- SubCheck(CheckMallocZero, this, BTypes[MallocZero]))
- .Default(SubCheck());
-
- SC.run(C, CE);
-}
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/UnreachableCodeChecker.cpp b/clang/lib/StaticAnalyzer/EntoSA/Checkers/UnreachableCodeChecker.cpp
deleted file mode 100644
index 98834485eba..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/UnreachableCodeChecker.cpp
+++ /dev/null
@@ -1,223 +0,0 @@
-//==- UnreachableCodeChecker.cpp - Generalized dead code checker -*- C++ -*-==//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-// This file implements a generalized unreachable code checker using a
-// path-sensitive analysis. We mark any path visited, and then walk the CFG as a
-// post-analysis to determine what was never visited.
-//
-// A similar flow-sensitive only check exists in Analysis/ReachableCode.cpp
-//===----------------------------------------------------------------------===//
-
-#include "clang/AST/ParentMap.h"
-#include "clang/Basic/Builtins.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
-#include "clang/StaticAnalyzer/PathSensitive/ExplodedGraph.h"
-#include "clang/StaticAnalyzer/PathSensitive/SVals.h"
-#include "clang/StaticAnalyzer/PathSensitive/CheckerHelpers.h"
-#include "clang/StaticAnalyzer/BugReporter/BugReporter.h"
-#include "ExprEngineExperimentalChecks.h"
-#include "llvm/ADT/SmallPtrSet.h"
-
-// The number of CFGBlock pointers we want to reserve memory for. This is used
-// once for each function we analyze.
-#define DEFAULT_CFGBLOCKS 256
-
-using namespace clang;
-using namespace ento;
-
-namespace {
-class UnreachableCodeChecker : public Checker {
-public:
- static void *getTag();
- void VisitEndAnalysis(ExplodedGraph &G,
- BugReporter &B,
- ExprEngine &Eng);
-private:
- static inline const Stmt *getUnreachableStmt(const CFGBlock *CB);
- void FindUnreachableEntryPoints(const CFGBlock *CB);
- static bool isInvalidPath(const CFGBlock *CB, const ParentMap &PM);
- static inline bool isEmptyCFGBlock(const CFGBlock *CB);
-
- llvm::SmallSet<unsigned, DEFAULT_CFGBLOCKS> reachable;
- llvm::SmallSet<unsigned, DEFAULT_CFGBLOCKS> visited;
-};
-}
-
-void *UnreachableCodeChecker::getTag() {
- static int x = 0;
- return &x;
-}
-
-void ento::RegisterUnreachableCodeChecker(ExprEngine &Eng) {
- Eng.registerCheck(new UnreachableCodeChecker());
-}
-
-void UnreachableCodeChecker::VisitEndAnalysis(ExplodedGraph &G,
- BugReporter &B,
- ExprEngine &Eng) {
- // Bail out if we didn't cover all paths
- if (Eng.hasWorkRemaining())
- return;
-
- CFG *C = 0;
- ParentMap *PM = 0;
- // Iterate over ExplodedGraph
- for (ExplodedGraph::node_iterator I = G.nodes_begin(), E = G.nodes_end();
- I != E; ++I) {
- const ProgramPoint &P = I->getLocation();
- const LocationContext *LC = P.getLocationContext();
-
- // Save the CFG if we don't have it already
- if (!C)
- C = LC->getAnalysisContext()->getUnoptimizedCFG();
- if (!PM)
- PM = &LC->getParentMap();
-
- if (const BlockEntrance *BE = dyn_cast<BlockEntrance>(&P)) {
- const CFGBlock *CB = BE->getBlock();
- reachable.insert(CB->getBlockID());
- }
- }
-
- // Bail out if we didn't get the CFG or the ParentMap.
- if (!C || !PM)
- return;
-
- ASTContext &Ctx = B.getContext();
-
- // Find CFGBlocks that were not covered by any node
- for (CFG::const_iterator I = C->begin(), E = C->end(); I != E; ++I) {
- const CFGBlock *CB = *I;
- // Check if the block is unreachable
- if (reachable.count(CB->getBlockID()))
- continue;
-
- // Check if the block is empty (an artificial block)
- if (isEmptyCFGBlock(CB))
- continue;
-
- // Find the entry points for this block
- if (!visited.count(CB->getBlockID()))
- FindUnreachableEntryPoints(CB);
-
- // This block may have been pruned; check if we still want to report it
- if (reachable.count(CB->getBlockID()))
- continue;
-
- // Check for false positives
- if (CB->size() > 0 && isInvalidPath(CB, *PM))
- continue;
-
- // Special case for __builtin_unreachable.
- // FIXME: This should be extended to include other unreachable markers,
- // such as llvm_unreachable.
- if (!CB->empty()) {
- CFGElement First = CB->front();
- if (CFGStmt S = First.getAs<CFGStmt>()) {
- if (const CallExpr *CE = dyn_cast<CallExpr>(S.getStmt())) {
- if (CE->isBuiltinCall(Ctx) == Builtin::BI__builtin_unreachable)
- continue;
- }
- }
- }
-
- // We found a block that wasn't covered - find the statement to report
- SourceRange SR;
- SourceLocation SL;
- if (const Stmt *S = getUnreachableStmt(CB)) {
- SR = S->getSourceRange();
- SL = S->getLocStart();
- if (SR.isInvalid() || SL.isInvalid())
- continue;
- }
- else
- continue;
-
- // Check if the SourceLocation is in a system header
- const SourceManager &SM = B.getSourceManager();
- if (SM.isInSystemHeader(SL) || SM.isInExternCSystemHeader(SL))
- continue;
-
- B.EmitBasicReport("Unreachable code", "Dead code", "This statement is never"
- " executed", SL, SR);
- }
-}
-
-// Recursively finds the entry point(s) for this dead CFGBlock.
-void UnreachableCodeChecker::FindUnreachableEntryPoints(const CFGBlock *CB) {
- visited.insert(CB->getBlockID());
-
- for (CFGBlock::const_pred_iterator I = CB->pred_begin(), E = CB->pred_end();
- I != E; ++I) {
- if (!reachable.count((*I)->getBlockID())) {
- // If we find an unreachable predecessor, mark this block as reachable so
- // we don't report this block
- reachable.insert(CB->getBlockID());
- if (!visited.count((*I)->getBlockID()))
- // If we haven't previously visited the unreachable predecessor, recurse
- FindUnreachableEntryPoints(*I);
- }
- }
-}
-
-// Find the Stmt* in a CFGBlock for reporting a warning
-const Stmt *UnreachableCodeChecker::getUnreachableStmt(const CFGBlock *CB) {
- for (CFGBlock::const_iterator I = CB->begin(), E = CB->end(); I != E; ++I) {
- if (CFGStmt S = I->getAs<CFGStmt>())
- return S;
- }
- if (const Stmt *S = CB->getTerminator())
- return S;
- else
- return 0;
-}
-
-// Determines if the path to this CFGBlock contained an element that infers this
-// block is a false positive. We assume that FindUnreachableEntryPoints has
-// already marked only the entry points to any dead code, so we need only to
-// find the condition that led to this block (the predecessor of this block.)
-// There will never be more than one predecessor.
-bool UnreachableCodeChecker::isInvalidPath(const CFGBlock *CB,
- const ParentMap &PM) {
- // We only expect a predecessor size of 0 or 1. If it is >1, then an external
- // condition has broken our assumption (for example, a sink being placed by
- // another check). In these cases, we choose not to report.
- if (CB->pred_size() > 1)
- return true;
-
- // If there are no predecessors, then this block is trivially unreachable
- if (CB->pred_size() == 0)
- return false;
-
- const CFGBlock *pred = *CB->pred_begin();
-
- // Get the predecessor block's terminator conditon
- const Stmt *cond = pred->getTerminatorCondition();
-
- //assert(cond && "CFGBlock's predecessor has a terminator condition");
- // The previous assertion is invalid in some cases (eg do/while). Leaving
- // reporting of these situations on at the moment to help triage these cases.
- if (!cond)
- return false;
-
- // Run each of the checks on the conditions
- if (containsMacro(cond) || containsEnum(cond)
- || containsStaticLocal(cond) || containsBuiltinOffsetOf(cond)
- || containsStmt<SizeOfAlignOfExpr>(cond))
- return true;
-
- return false;
-}
-
-// Returns true if the given CFGBlock is empty
-bool UnreachableCodeChecker::isEmptyCFGBlock(const CFGBlock *CB) {
- return CB->getLabel() == 0 // No labels
- && CB->size() == 0 // No statements
- && CB->getTerminator() == 0; // No terminator
-}
diff --git a/clang/lib/StaticAnalyzer/EntoSA/Checkers/VLASizeChecker.cpp b/clang/lib/StaticAnalyzer/EntoSA/Checkers/VLASizeChecker.cpp
deleted file mode 100644
index e24521af536..00000000000
--- a/clang/lib/StaticAnalyzer/EntoSA/Checkers/VLASizeChecker.cpp
+++ /dev/null
@@ -1,138 +0,0 @@
-//=== VLASizeChecker.cpp - Undefined dereference checker --------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// This defines VLASizeChecker, a builtin check in ExprEngine that
-// performs checks for declaration of VLA of undefined or zero size.
-// In addition, VLASizeChecker is responsible for defining the extent
-// of the MemRegion that represents a VLA.
-//
-//===----------------------------------------------------------------------===//
-
-#include "ExprEngineInternalChecks.h"
-#include "clang/AST/CharUnits.h"
-#include "clang/StaticAnalyzer/BugReporter/BugType.h"
-#include "clang/StaticAnalyzer/PathSensitive/CheckerVisitor.h"
-#include "clang/StaticAnalyzer/PathSensitive/ExprEngine.h"
-
-using namespace clang;
-using namespace ento;
-
-namespace {
-class VLASizeChecker : public CheckerVisitor<VLASizeChecker> {
- BugType *BT_zero;
- BugType *BT_undef;
-
-public:
- VLASizeChecker() : BT_zero(0), BT_undef(0) {}
- static void *getTag() { static int tag = 0; return &tag; }
- void PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS);
-};
-} // end anonymous namespace
-
-void ento::RegisterVLASizeChecker(ExprEngine &Eng) {
- Eng.registerCheck(new VLASizeChecker());
-}
-
-void VLASizeChecker::PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS) {
- if (!DS->isSingleDecl())
- return;
-
- const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl());
- if (!VD)
- return;
-
- ASTContext &Ctx = C.getASTContext();
- const VariableArrayType *VLA = Ctx.getAsVariableArrayType(VD->getType());
- if (!VLA)
- return;
-
- // FIXME: Handle multi-dimensional VLAs.
- const Expr* SE = VLA->getSizeExpr();
- const GRState *state = C.getState();
- SVal sizeV = state->getSVal(SE);
-
- if (sizeV.isUndef()) {
- // Generate an error node.
- ExplodedNode *N = C.generateSink();
- if (!N)
- return;
-
- if (!BT_undef)
- BT_undef = new BuiltinBug("Declared variable-length array (VLA) uses a "
- "garbage value as its size");
-
- EnhancedBugReport *report =
- new EnhancedBugReport(*BT_undef, BT_undef->getName(), N);
- report->addRange(SE->getSourceRange());
- report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, SE);
- C.EmitReport(report);
- return;
- }
-
- // See if the size value is known. It can't be undefined because we would have
- // warned about that already.
- if (sizeV.isUnknown())
- return;
-
- // Check if the size is zero.
- DefinedSVal sizeD = cast<DefinedSVal>(sizeV);
-
- const GRState *stateNotZero, *stateZero;
- llvm::tie(stateNotZero, stateZero) = state->assume(sizeD);
-
- if (stateZero && !stateNotZero) {
- ExplodedNode* N = C.generateSink(stateZero);
- if (!BT_zero)
- BT_zero = new BuiltinBug("Declared variable-length array (VLA) has zero "
- "size");
-
- EnhancedBugReport *report =
- new EnhancedBugReport(*BT_zero, BT_zero->getName(), N);
- report->addRange(SE->getSourceRange());
- report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, SE);
- C.EmitReport(report);
- return;
- }
-
- // From this point on, assume that the size is not zero.
- state = stateNotZero;
-
- // VLASizeChecker is responsible for defining the extent of the array being
- // declared. We do this by multiplying the array length by the element size,
- // then matching that with the array region's extent symbol.
-
- // Convert the array length to size_t.
- SValBuilder &svalBuilder = C.getSValBuilder();
- QualType SizeTy = Ctx.getSizeType();
- NonLoc ArrayLength = cast<NonLoc>(svalBuilder.evalCast(sizeD, SizeTy,
- SE->getType()));
-
- // Get the element size.
- CharUnits EleSize = Ctx.getTypeSizeInChars(VLA->getElementType());
- SVal EleSizeVal = svalBuilder.makeIntVal(EleSize.getQuantity(), SizeTy);
-
- // Multiply the array length by the element size.
- SVal ArraySizeVal = svalBuilder.evalBinOpNN(state, BO_Mul, ArrayLength,
- cast<NonLoc>(EleSizeVal), SizeTy);
-
- // Finally, assume that the array's extent matches the given size.
- const LocationContext *LC = C.getPredecessor()->getLocationContext();
- DefinedOrUnknownSVal Extent =
- state->getRegion(VD, LC)->getExtent(svalBuilder);
- DefinedOrUnknownSVal ArraySize = cast<DefinedOrUnknownSVal>(ArraySizeVal);
- DefinedOrUnknownSVal sizeIsKnown =
- svalBuilder.evalEQ(state, Extent, ArraySize);
- state = state->assume(sizeIsKnown, true);
-
- // Assume should not fail at this point.
- assert(state);
-
- // Remember our assumptions!
- C.addTransition(state);
-}
OpenPOWER on IntegriCloud