diff options
author | Ted Kremenek <kremenek@apple.com> | 2012-09-21 00:09:11 +0000 |
---|---|---|
committer | Ted Kremenek <kremenek@apple.com> | 2012-09-21 00:09:11 +0000 |
commit | a43df9539644bf1c258e12710cd69d79b0b078cd (patch) | |
tree | 1c77ba3f0325a80410c1568dc939c1306e80491a /lib/Analysis | |
parent | 445895a97ae3f1d7bad3480839d31ed3ebcc9c83 (diff) |
Implement faux-body-synthesis of well-known functions in the static analyzer when
their implementations are unavailable. Start by simulating dispatch_sync().
This change is largely a bunch of plumbing around something very simple. We
use AnalysisDeclContext to conjure up a fake function body (using the
current ASTContext) when one does not exist. This is controlled
under the analyzer-config option "faux-bodies", which is off by default.
The plumbing in this patch is largely to pass the necessary machinery
around. CallEvent needs the AnalysisDeclContextManager to get
the function definition, as one may get conjured up lazily.
BugReporter and PathDiagnosticLocation needed to be relaxed to handle
invalid locations, as the conjured body has no real source locations.
We do some primitive recovery in diagnostic generation to generate
some reasonable locations (for arrows and events), but it can be
improved.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@164339 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Analysis')
-rw-r--r-- | lib/Analysis/AnalysisDeclContext.cpp | 31 | ||||
-rw-r--r-- | lib/Analysis/BodyFarm.cpp | 91 | ||||
-rw-r--r-- | lib/Analysis/BodyFarm.h | 43 | ||||
-rw-r--r-- | lib/Analysis/CMakeLists.txt | 1 |
4 files changed, 160 insertions, 6 deletions
diff --git a/lib/Analysis/AnalysisDeclContext.cpp b/lib/Analysis/AnalysisDeclContext.cpp index f2ef0defd7..a4bf8d19b1 100644 --- a/lib/Analysis/AnalysisDeclContext.cpp +++ b/lib/Analysis/AnalysisDeclContext.cpp @@ -29,13 +29,15 @@ #include "llvm/ADT/SmallPtrSet.h" #include "llvm/Support/ErrorHandling.h" +#include "BodyFarm.h" + using namespace clang; typedef llvm::DenseMap<const void *, ManagedAnalysis *> ManagedAnalysisMap; AnalysisDeclContext::AnalysisDeclContext(AnalysisDeclContextManager *Mgr, - const Decl *d, - const CFG::BuildOptions &buildOptions) + const Decl *d, + const CFG::BuildOptions &buildOptions) : Manager(Mgr), D(d), cfgBuildOptions(buildOptions), @@ -49,7 +51,7 @@ AnalysisDeclContext::AnalysisDeclContext(AnalysisDeclContextManager *Mgr, } AnalysisDeclContext::AnalysisDeclContext(AnalysisDeclContextManager *Mgr, - const Decl *d) + const Decl *d) : Manager(Mgr), D(d), forcedBlkExprs(0), @@ -64,7 +66,10 @@ AnalysisDeclContext::AnalysisDeclContext(AnalysisDeclContextManager *Mgr, AnalysisDeclContextManager::AnalysisDeclContextManager(bool useUnoptimizedCFG, bool addImplicitDtors, bool addInitializers, - bool addTemporaryDtors) { + bool addTemporaryDtors, + bool synthesizeBodies) + : SynthesizeBodies(synthesizeBodies) +{ cfgBuildOptions.PruneTriviallyFalseEdges = !useUnoptimizedCFG; cfgBuildOptions.AddImplicitDtors = addImplicitDtors; cfgBuildOptions.AddInitializers = addInitializers; @@ -77,9 +82,18 @@ void AnalysisDeclContextManager::clear() { Contexts.clear(); } +static BodyFarm &getBodyFarm(ASTContext &C) { + static BodyFarm *BF = new BodyFarm(C); + return *BF; +} + Stmt *AnalysisDeclContext::getBody() const { - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) - return FD->getBody(); + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + Stmt *Body = FD->getBody(); + if (!Body && Manager && Manager->synthesizeBodies()) + return getBodyFarm(getASTContext()).getBody(FD); + return Body; + } else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) return MD->getBody(); else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) @@ -203,6 +217,11 @@ PseudoConstantAnalysis *AnalysisDeclContext::getPseudoConstantAnalysis() { } AnalysisDeclContext *AnalysisDeclContextManager::getContext(const Decl *D) { + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + FD->hasBody(FD); + D = FD; + } + AnalysisDeclContext *&AC = Contexts[D]; if (!AC) AC = new AnalysisDeclContext(this, D, cfgBuildOptions); diff --git a/lib/Analysis/BodyFarm.cpp b/lib/Analysis/BodyFarm.cpp new file mode 100644 index 0000000000..217f607d56 --- /dev/null +++ b/lib/Analysis/BodyFarm.cpp @@ -0,0 +1,91 @@ +//== BodyFarm.cpp - Factory for conjuring up fake bodies ----------*- C++ -*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// BodyFarm is a factory for creating faux implementations for functions/methods +// for analysis purposes. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/StringSwitch.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/Expr.h" +#include "clang/AST/Decl.h" +#include "BodyFarm.h" + +using namespace clang; + +typedef Stmt *(*FunctionFarmer)(ASTContext &C, const FunctionDecl *D); + + +/// Create a fake body for dispatch_sync. +static Stmt *create_dispatch_sync(ASTContext &C, const FunctionDecl *D) { + // Check if we have at least two parameters. + if (D->param_size() != 2) + return 0; + + // Check if the second parameter is a block. + const ParmVarDecl *PV = D->getParamDecl(1); + QualType Ty = PV->getType(); + const BlockPointerType *BPT = Ty->getAs<BlockPointerType>(); + if (!BPT) + return 0; + + // Check if the block pointer type takes no arguments and + // returns void. + const FunctionProtoType *FT = + BPT->getPointeeType()->getAs<FunctionProtoType>(); + if (!FT || !FT->getResultType()->isVoidType() || + FT->getNumArgs() != 0) + return 0; + + // Everything checks out. Create a fake body that just calls the block. + // This is basically just an AST dump of: + // + // void dispatch_sync(dispatch_queue_t queue, void (^block)(void)) { + // block(); + // } + // + DeclRefExpr *DR = DeclRefExpr::CreateEmpty(C, false, false, false, false); + DR->setDecl(const_cast<ParmVarDecl*>(PV)); + DR->setValueKind(VK_LValue); + ImplicitCastExpr *ICE = ImplicitCastExpr::Create(C, Ty, CK_LValueToRValue, + DR, 0, VK_RValue); + CallExpr *CE = new (C) CallExpr(C, ICE, ArrayRef<Expr*>(), C.VoidTy, + VK_RValue, SourceLocation()); + return CE; +} + +Stmt *BodyFarm::getBody(const FunctionDecl *D) { + D = D->getCanonicalDecl(); + + llvm::Optional<Stmt *> &Val = Bodies[D]; + if (Val.hasValue()) + return Val.getValue(); + + Val = 0; + + if (D->getIdentifier() == 0) + return 0; + + StringRef Name = D->getName(); + if (Name.empty()) + return 0; + + FunctionFarmer FF = + llvm::StringSwitch<FunctionFarmer>(Name) + .Case("dispatch_sync", create_dispatch_sync) + .Default(NULL); + + if (FF) { + Val = FF(C, D); + } + + return Val.getValue(); +} + diff --git a/lib/Analysis/BodyFarm.h b/lib/Analysis/BodyFarm.h new file mode 100644 index 0000000000..d503cc1bcd --- /dev/null +++ b/lib/Analysis/BodyFarm.h @@ -0,0 +1,43 @@ +//== BodyFarm.h - Factory for conjuring up fake bodies -------------*- C++ -*-// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// BodyFarm is a factory for creating faux implementations for functions/methods +// for analysis purposes. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_BODYFARM_H +#define LLVM_CLANG_ANALYSIS_BODYFARM_H + +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/DenseMap.h" + +namespace clang { + +class ASTContext; +class Decl; +class FunctionDecl; +class Stmt; + +class BodyFarm { +public: + BodyFarm(ASTContext &C) : C(C) {} + + /// Factory method for creating bodies for ordinary functions. + Stmt *getBody(const FunctionDecl *D); + +private: + typedef llvm::DenseMap<const Decl *, llvm::Optional<Stmt *> > BodyMap; + + ASTContext &C; + BodyMap Bodies; +}; +} + +#endif diff --git a/lib/Analysis/CMakeLists.txt b/lib/Analysis/CMakeLists.txt index 7c33d73714..ca166669fc 100644 --- a/lib/Analysis/CMakeLists.txt +++ b/lib/Analysis/CMakeLists.txt @@ -1,5 +1,6 @@ add_clang_library(clangAnalysis AnalysisDeclContext.cpp + BodyFarm.cpp CFG.cpp CFGReachabilityAnalysis.cpp CFGStmtMap.cpp |