diff options
Diffstat (limited to 'clang/lib/StaticAnalyzer/EntoSA/Checkers')
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); -} |

