Imported Upstream version 6.10.0.49

Former-commit-id: 1d6753294b2993e1fbf92de9366bb9544db4189b
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2020-01-16 16:38:04 +00:00
parent d94e79959b
commit 468663ddbb
48518 changed files with 2789335 additions and 61176 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1 @@
714b85d3a9fff835e1891d6f388c6f0b372d5e7e

View File

@ -0,0 +1,76 @@
//==- CFGReachabilityAnalysis.cpp - Basic reachability analysis --*- 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 flow-sensitive, (mostly) path-insensitive reachability
// analysis based on Clang's CFGs. Clients can query if a given basic block
// is reachable within the CFG.
//
//===----------------------------------------------------------------------===//
#include "llvm/ADT/SmallVector.h"
#include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h"
#include "clang/Analysis/CFG.h"
using namespace clang;
CFGReverseBlockReachabilityAnalysis::CFGReverseBlockReachabilityAnalysis(const CFG &cfg)
: analyzed(cfg.getNumBlockIDs(), false) {}
bool CFGReverseBlockReachabilityAnalysis::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[DstBlockID]) {
mapReachability(Dst);
analyzed[DstBlockID] = true;
}
// Return the cached result
return reachable[DstBlockID][Src->getBlockID()];
}
// Maps reachability to a common node by walking the predecessors of the
// destination node.
void CFGReverseBlockReachabilityAnalysis::mapReachability(const CFGBlock *Dst) {
SmallVector<const CFGBlock *, 11> worklist;
llvm::BitVector visited(analyzed.size());
ReachableSet &DstReachability = reachable[Dst->getBlockID()];
DstReachability.resize(analyzed.size(), false);
// 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 *block = worklist.pop_back_val();
if (visited[block->getBlockID()])
continue;
visited[block->getBlockID()] = true;
// Update reachability information for this node -> Dst
if (!firstRun) {
// Don't insert Dst -> Dst unless it was a predecessor of itself
DstReachability[block->getBlockID()] = true;
}
else
firstRun = false;
// Add the predecessors to the worklist.
for (CFGBlock::const_pred_iterator i = block->pred_begin(),
e = block->pred_end(); i != e; ++i) {
if (*i)
worklist.push_back(*i);
}
}
}

View File

@ -0,0 +1,91 @@
//===--- CFGStmtMap.h - Map from Stmt* to CFGBlock* -----------*- 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 the CFGStmtMap class, which defines a mapping from
// Stmt* to CFGBlock*
//
//===----------------------------------------------------------------------===//
#include "llvm/ADT/DenseMap.h"
#include "clang/AST/ParentMap.h"
#include "clang/Analysis/CFG.h"
#include "clang/Analysis/CFGStmtMap.h"
using namespace clang;
typedef llvm::DenseMap<const Stmt*, CFGBlock*> SMap;
static SMap *AsMap(void *m) { return (SMap*) m; }
CFGStmtMap::~CFGStmtMap() { delete AsMap(M); }
CFGBlock *CFGStmtMap::getBlock(Stmt *S) {
SMap *SM = AsMap(M);
Stmt *X = S;
// If 'S' isn't in the map, walk the ParentMap to see if one of its ancestors
// is in the map.
while (X) {
SMap::iterator I = SM->find(X);
if (I != SM->end()) {
CFGBlock *B = I->second;
// Memoize this lookup.
if (X != S)
(*SM)[X] = B;
return B;
}
X = PM->getParentIgnoreParens(X);
}
return nullptr;
}
static void Accumulate(SMap &SM, CFGBlock *B) {
// First walk the block-level expressions.
for (CFGBlock::iterator I = B->begin(), E = B->end(); I != E; ++I) {
const CFGElement &CE = *I;
Optional<CFGStmt> CS = CE.getAs<CFGStmt>();
if (!CS)
continue;
CFGBlock *&Entry = SM[CS->getStmt()];
// If 'Entry' is already initialized (e.g., a terminator was already),
// skip.
if (Entry)
continue;
Entry = B;
}
// Look at the label of the block.
if (Stmt *Label = B->getLabel())
SM[Label] = B;
// Finally, look at the terminator. If the terminator was already added
// because it is a block-level expression in another block, overwrite
// that mapping.
if (Stmt *Term = B->getTerminator())
SM[Term] = B;
}
CFGStmtMap *CFGStmtMap::Build(CFG *C, ParentMap *PM) {
if (!C || !PM)
return nullptr;
SMap *SM = new SMap();
// Walk all blocks, accumulating the block-level expressions, labels,
// and terminators.
for (CFG::iterator I = C->begin(), E = C->end(); I != E; ++I)
Accumulate(*SM, *I);
return new CFGStmtMap(PM, SM);
}

View File

@ -0,0 +1,37 @@
set(LLVM_LINK_COMPONENTS
Support
)
add_clang_library(clangAnalysis
AnalysisDeclContext.cpp
BodyFarm.cpp
CFG.cpp
CFGReachabilityAnalysis.cpp
CFGStmtMap.cpp
CallGraph.cpp
CloneDetection.cpp
CocoaConventions.cpp
Consumed.cpp
CodeInjector.cpp
Dominators.cpp
FormatString.cpp
LiveVariables.cpp
OSLog.cpp
ObjCNoReturn.cpp
PostOrderCFGView.cpp
PrintfFormatString.cpp
ProgramPoint.cpp
PseudoConstantAnalysis.cpp
ReachableCode.cpp
ScanfFormatString.cpp
ThreadSafety.cpp
ThreadSafetyCommon.cpp
ThreadSafetyLogical.cpp
ThreadSafetyTIL.cpp
UninitializedValues.cpp
LINK_LIBS
clangAST
clangBasic
clangLex
)

View File

@ -0,0 +1,241 @@
//===- CallGraph.cpp - AST-based Call graph -------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the AST-based CallGraph.
//
//===----------------------------------------------------------------------===//
#include "clang/Analysis/CallGraph.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclBase.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/DOTGraphTraits.h"
#include "llvm/Support/GraphWriter.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
#include <memory>
#include <string>
using namespace clang;
#define DEBUG_TYPE "CallGraph"
STATISTIC(NumObjCCallEdges, "Number of Objective-C method call edges");
STATISTIC(NumBlockCallEdges, "Number of block call edges");
namespace {
/// A helper class, which walks the AST and locates all the call sites in the
/// given function body.
class CGBuilder : public StmtVisitor<CGBuilder> {
CallGraph *G;
CallGraphNode *CallerNode;
public:
CGBuilder(CallGraph *g, CallGraphNode *N) : G(g), CallerNode(N) {}
void VisitStmt(Stmt *S) { VisitChildren(S); }
Decl *getDeclFromCall(CallExpr *CE) {
if (FunctionDecl *CalleeDecl = CE->getDirectCallee())
return CalleeDecl;
// Simple detection of a call through a block.
Expr *CEE = CE->getCallee()->IgnoreParenImpCasts();
if (BlockExpr *Block = dyn_cast<BlockExpr>(CEE)) {
NumBlockCallEdges++;
return Block->getBlockDecl();
}
return nullptr;
}
void addCalledDecl(Decl *D) {
if (G->includeInGraph(D)) {
CallGraphNode *CalleeNode = G->getOrInsertNode(D);
CallerNode->addCallee(CalleeNode);
}
}
void VisitCallExpr(CallExpr *CE) {
if (Decl *D = getDeclFromCall(CE))
addCalledDecl(D);
VisitChildren(CE);
}
// Adds may-call edges for the ObjC message sends.
void VisitObjCMessageExpr(ObjCMessageExpr *ME) {
if (ObjCInterfaceDecl *IDecl = ME->getReceiverInterface()) {
Selector Sel = ME->getSelector();
// Find the callee definition within the same translation unit.
Decl *D = nullptr;
if (ME->isInstanceMessage())
D = IDecl->lookupPrivateMethod(Sel);
else
D = IDecl->lookupPrivateClassMethod(Sel);
if (D) {
addCalledDecl(D);
NumObjCCallEdges++;
}
}
}
void VisitChildren(Stmt *S) {
for (Stmt *SubStmt : S->children())
if (SubStmt)
this->Visit(SubStmt);
}
};
} // namespace
void CallGraph::addNodesForBlocks(DeclContext *D) {
if (BlockDecl *BD = dyn_cast<BlockDecl>(D))
addNodeForDecl(BD, true);
for (auto *I : D->decls())
if (auto *DC = dyn_cast<DeclContext>(I))
addNodesForBlocks(DC);
}
CallGraph::CallGraph() {
Root = getOrInsertNode(nullptr);
}
CallGraph::~CallGraph() = default;
bool CallGraph::includeInGraph(const Decl *D) {
assert(D);
if (!D->hasBody())
return false;
if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
// We skip function template definitions, as their semantics is
// only determined when they are instantiated.
if (FD->isDependentContext())
return false;
IdentifierInfo *II = FD->getIdentifier();
if (II && II->getName().startswith("__inline"))
return false;
}
return true;
}
void CallGraph::addNodeForDecl(Decl* D, bool IsGlobal) {
assert(D);
// Allocate a new node, mark it as root, and process it's calls.
CallGraphNode *Node = getOrInsertNode(D);
// Process all the calls by this function as well.
CGBuilder builder(this, Node);
if (Stmt *Body = D->getBody())
builder.Visit(Body);
}
CallGraphNode *CallGraph::getNode(const Decl *F) const {
FunctionMapTy::const_iterator I = FunctionMap.find(F);
if (I == FunctionMap.end()) return nullptr;
return I->second.get();
}
CallGraphNode *CallGraph::getOrInsertNode(Decl *F) {
if (F && !isa<ObjCMethodDecl>(F))
F = F->getCanonicalDecl();
std::unique_ptr<CallGraphNode> &Node = FunctionMap[F];
if (Node)
return Node.get();
Node = llvm::make_unique<CallGraphNode>(F);
// Make Root node a parent of all functions to make sure all are reachable.
if (F)
Root->addCallee(Node.get());
return Node.get();
}
void CallGraph::print(raw_ostream &OS) const {
OS << " --- Call graph Dump --- \n";
// We are going to print the graph in reverse post order, partially, to make
// sure the output is deterministic.
llvm::ReversePostOrderTraversal<const CallGraph *> RPOT(this);
for (llvm::ReversePostOrderTraversal<const CallGraph *>::rpo_iterator
I = RPOT.begin(), E = RPOT.end(); I != E; ++I) {
const CallGraphNode *N = *I;
OS << " Function: ";
if (N == Root)
OS << "< root >";
else
N->print(OS);
OS << " calls: ";
for (CallGraphNode::const_iterator CI = N->begin(),
CE = N->end(); CI != CE; ++CI) {
assert(*CI != Root && "No one can call the root node.");
(*CI)->print(OS);
OS << " ";
}
OS << '\n';
}
OS.flush();
}
LLVM_DUMP_METHOD void CallGraph::dump() const {
print(llvm::errs());
}
void CallGraph::viewGraph() const {
llvm::ViewGraph(this, "CallGraph");
}
void CallGraphNode::print(raw_ostream &os) const {
if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(FD))
return ND->printName(os);
os << "< >";
}
LLVM_DUMP_METHOD void CallGraphNode::dump() const {
print(llvm::errs());
}
namespace llvm {
template <>
struct DOTGraphTraits<const CallGraph*> : public DefaultDOTGraphTraits {
DOTGraphTraits (bool isSimple = false) : DefaultDOTGraphTraits(isSimple) {}
static std::string getNodeLabel(const CallGraphNode *Node,
const CallGraph *CG) {
if (CG->getRoot() == Node) {
return "< root >";
}
if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Node->getDecl()))
return ND->getNameAsString();
else
return "< >";
}
};
} // namespace llvm

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,147 @@
//===- CocoaConventions.h - Special handling of Cocoa conventions -*- 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 cocoa naming convention analysis.
//
//===----------------------------------------------------------------------===//
#include "clang/Analysis/DomainSpecific/CocoaConventions.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/Type.h"
#include "clang/Basic/CharInfo.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/ErrorHandling.h"
using namespace clang;
using namespace ento;
bool cocoa::isRefType(QualType RetTy, StringRef Prefix,
StringRef Name) {
// Recursively walk the typedef stack, allowing typedefs of reference types.
while (const TypedefType *TD = RetTy->getAs<TypedefType>()) {
StringRef TDName = TD->getDecl()->getIdentifier()->getName();
if (TDName.startswith(Prefix) && TDName.endswith("Ref"))
return true;
// XPC unfortunately uses CF-style function names, but aren't CF types.
if (TDName.startswith("xpc_"))
return false;
RetTy = TD->getDecl()->getUnderlyingType();
}
if (Name.empty())
return false;
// Is the type void*?
const PointerType* PT = RetTy->getAs<PointerType>();
if (!(PT->getPointeeType().getUnqualifiedType()->isVoidType()))
return false;
// Does the name start with the prefix?
return Name.startswith(Prefix);
}
/// Returns true when the passed-in type is a CF-style reference-counted
/// type from the DiskArbitration framework.
static bool isDiskArbitrationAPIRefType(QualType T) {
return cocoa::isRefType(T, "DADisk") ||
cocoa::isRefType(T, "DADissenter") ||
cocoa::isRefType(T, "DASessionRef");
}
bool coreFoundation::isCFObjectRef(QualType T) {
return cocoa::isRefType(T, "CF") || // Core Foundation.
cocoa::isRefType(T, "CG") || // Core Graphics.
cocoa::isRefType(T, "CM") || // Core Media.
isDiskArbitrationAPIRefType(T);
}
bool cocoa::isCocoaObjectRef(QualType Ty) {
if (!Ty->isObjCObjectPointerType())
return false;
const ObjCObjectPointerType *PT = Ty->getAs<ObjCObjectPointerType>();
// Can be true for objects with the 'NSObject' attribute.
if (!PT)
return true;
// We assume that id<..>, id, Class, and Class<..> all represent tracked
// objects.
if (PT->isObjCIdType() || PT->isObjCQualifiedIdType() ||
PT->isObjCClassType() || PT->isObjCQualifiedClassType())
return true;
// Does the interface subclass NSObject?
// FIXME: We can memoize here if this gets too expensive.
const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
// Assume that anything declared with a forward declaration and no
// @interface subclasses NSObject.
if (!ID->hasDefinition())
return true;
for ( ; ID ; ID = ID->getSuperClass())
if (ID->getIdentifier()->getName() == "NSObject")
return true;
return false;
}
bool coreFoundation::followsCreateRule(const FunctionDecl *fn) {
// For now, *just* base this on the function name, not on anything else.
const IdentifierInfo *ident = fn->getIdentifier();
if (!ident) return false;
StringRef functionName = ident->getName();
StringRef::iterator it = functionName.begin();
StringRef::iterator start = it;
StringRef::iterator endI = functionName.end();
while (true) {
// Scan for the start of 'create' or 'copy'.
for ( ; it != endI ; ++it) {
// Search for the first character. It can either be 'C' or 'c'.
char ch = *it;
if (ch == 'C' || ch == 'c') {
// Make sure this isn't something like 'recreate' or 'Scopy'.
if (ch == 'c' && it != start && isLetter(*(it - 1)))
continue;
++it;
break;
}
}
// Did we hit the end of the string? If so, we didn't find a match.
if (it == endI)
return false;
// Scan for *lowercase* 'reate' or 'opy', followed by no lowercase
// character.
StringRef suffix = functionName.substr(it - start);
if (suffix.startswith("reate")) {
it += 5;
}
else if (suffix.startswith("opy")) {
it += 3;
} else {
// Keep scanning.
continue;
}
if (it == endI || !isLowercase(*it))
return true;
// If we matched a lowercase character, it isn't the end of the
// word. Keep scanning.
}
}

View File

@ -0,0 +1,15 @@
//===-- CodeInjector.cpp ----------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "clang/Analysis/CodeInjector.h"
using namespace clang;
CodeInjector::CodeInjector() {}
CodeInjector::~CodeInjector() {}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,14 @@
//=- Dominators.cpp - Implementation of dominators tree for Clang CFG C++ -*-=//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "clang/Analysis/Analyses/Dominators.h"
using namespace clang;
void DominatorTree::anchor() { }

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,79 @@
#ifndef LLVM_CLANG_LIB_ANALYSIS_FORMATSTRINGPARSING_H
#define LLVM_CLANG_LIB_ANALYSIS_FORMATSTRINGPARSING_H
#include "clang/AST/ASTContext.h"
#include "clang/AST/Type.h"
#include "clang/Analysis/Analyses/FormatString.h"
namespace clang {
class LangOptions;
template <typename T>
class UpdateOnReturn {
T &ValueToUpdate;
const T &ValueToCopy;
public:
UpdateOnReturn(T &valueToUpdate, const T &valueToCopy)
: ValueToUpdate(valueToUpdate), ValueToCopy(valueToCopy) {}
~UpdateOnReturn() {
ValueToUpdate = ValueToCopy;
}
};
namespace analyze_format_string {
OptionalAmount ParseAmount(const char *&Beg, const char *E);
OptionalAmount ParseNonPositionAmount(const char *&Beg, const char *E,
unsigned &argIndex);
OptionalAmount ParsePositionAmount(FormatStringHandler &H,
const char *Start, const char *&Beg,
const char *E, PositionContext p);
bool ParseFieldWidth(FormatStringHandler &H,
FormatSpecifier &CS,
const char *Start, const char *&Beg, const char *E,
unsigned *argIndex);
bool ParseArgPosition(FormatStringHandler &H,
FormatSpecifier &CS, const char *Start,
const char *&Beg, const char *E);
/// Returns true if a LengthModifier was parsed and installed in the
/// FormatSpecifier& argument, and false otherwise.
bool ParseLengthModifier(FormatSpecifier &FS, const char *&Beg, const char *E,
const LangOptions &LO, bool IsScanf = false);
/// Returns true if the invalid specifier in \p SpecifierBegin is a UTF-8
/// string; check that it won't go further than \p FmtStrEnd and write
/// up the total size in \p Len.
bool ParseUTF8InvalidSpecifier(const char *SpecifierBegin,
const char *FmtStrEnd, unsigned &Len);
template <typename T> class SpecifierResult {
T FS;
const char *Start;
bool Stop;
public:
SpecifierResult(bool stop = false)
: Start(nullptr), Stop(stop) {}
SpecifierResult(const char *start,
const T &fs)
: FS(fs), Start(start), Stop(false) {}
const char *getStart() const { return Start; }
bool shouldStop() const { return Stop; }
bool hasValue() const { return Start != nullptr; }
const T &getValue() const {
assert(hasValue());
return FS;
}
const T &getValue() { return FS; }
};
} // end analyze_format_string namespace
} // end clang namespace
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,203 @@
// TODO: header template
#include "clang/Analysis/Analyses/OSLog.h"
#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/ExprObjC.h"
#include "clang/Analysis/Analyses/FormatString.h"
#include "clang/Basic/Builtins.h"
#include "llvm/ADT/SmallBitVector.h"
using namespace clang;
using clang::analyze_os_log::OSLogBufferItem;
using clang::analyze_os_log::OSLogBufferLayout;
namespace {
class OSLogFormatStringHandler
: public analyze_format_string::FormatStringHandler {
private:
struct ArgData {
const Expr *E = nullptr;
Optional<OSLogBufferItem::Kind> Kind;
Optional<unsigned> Size;
Optional<const Expr *> Count;
Optional<const Expr *> Precision;
Optional<const Expr *> FieldWidth;
unsigned char Flags = 0;
};
SmallVector<ArgData, 4> ArgsData;
ArrayRef<const Expr *> Args;
OSLogBufferItem::Kind
getKind(analyze_format_string::ConversionSpecifier::Kind K) {
switch (K) {
case clang::analyze_format_string::ConversionSpecifier::sArg: // "%s"
return OSLogBufferItem::StringKind;
case clang::analyze_format_string::ConversionSpecifier::SArg: // "%S"
return OSLogBufferItem::WideStringKind;
case clang::analyze_format_string::ConversionSpecifier::PArg: { // "%P"
return OSLogBufferItem::PointerKind;
case clang::analyze_format_string::ConversionSpecifier::ObjCObjArg: // "%@"
return OSLogBufferItem::ObjCObjKind;
case clang::analyze_format_string::ConversionSpecifier::PrintErrno: // "%m"
return OSLogBufferItem::ErrnoKind;
default:
return OSLogBufferItem::ScalarKind;
}
}
}
public:
OSLogFormatStringHandler(ArrayRef<const Expr *> Args) : Args(Args) {
ArgsData.reserve(Args.size());
}
virtual bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS,
const char *StartSpecifier,
unsigned SpecifierLen) {
if (!FS.consumesDataArgument() &&
FS.getConversionSpecifier().getKind() !=
clang::analyze_format_string::ConversionSpecifier::PrintErrno)
return true;
ArgsData.emplace_back();
unsigned ArgIndex = FS.getArgIndex();
if (ArgIndex < Args.size())
ArgsData.back().E = Args[ArgIndex];
// First get the Kind
ArgsData.back().Kind = getKind(FS.getConversionSpecifier().getKind());
if (ArgsData.back().Kind != OSLogBufferItem::ErrnoKind &&
!ArgsData.back().E) {
// missing argument
ArgsData.pop_back();
return false;
}
switch (FS.getConversionSpecifier().getKind()) {
case clang::analyze_format_string::ConversionSpecifier::sArg: // "%s"
case clang::analyze_format_string::ConversionSpecifier::SArg: { // "%S"
auto &precision = FS.getPrecision();
switch (precision.getHowSpecified()) {
case clang::analyze_format_string::OptionalAmount::NotSpecified: // "%s"
break;
case clang::analyze_format_string::OptionalAmount::Constant: // "%.16s"
ArgsData.back().Size = precision.getConstantAmount();
break;
case clang::analyze_format_string::OptionalAmount::Arg: // "%.*s"
ArgsData.back().Count = Args[precision.getArgIndex()];
break;
case clang::analyze_format_string::OptionalAmount::Invalid:
return false;
}
break;
}
case clang::analyze_format_string::ConversionSpecifier::PArg: { // "%P"
auto &precision = FS.getPrecision();
switch (precision.getHowSpecified()) {
case clang::analyze_format_string::OptionalAmount::NotSpecified: // "%P"
return false; // length must be supplied with pointer format specifier
case clang::analyze_format_string::OptionalAmount::Constant: // "%.16P"
ArgsData.back().Size = precision.getConstantAmount();
break;
case clang::analyze_format_string::OptionalAmount::Arg: // "%.*P"
ArgsData.back().Count = Args[precision.getArgIndex()];
break;
case clang::analyze_format_string::OptionalAmount::Invalid:
return false;
}
break;
}
default:
if (FS.getPrecision().hasDataArgument()) {
ArgsData.back().Precision = Args[FS.getPrecision().getArgIndex()];
}
break;
}
if (FS.getFieldWidth().hasDataArgument()) {
ArgsData.back().FieldWidth = Args[FS.getFieldWidth().getArgIndex()];
}
if (FS.isPrivate()) {
ArgsData.back().Flags |= OSLogBufferItem::IsPrivate;
}
if (FS.isPublic()) {
ArgsData.back().Flags |= OSLogBufferItem::IsPublic;
}
return true;
}
void computeLayout(ASTContext &Ctx, OSLogBufferLayout &Layout) const {
Layout.Items.clear();
for (auto &Data : ArgsData) {
if (Data.FieldWidth) {
CharUnits Size = Ctx.getTypeSizeInChars((*Data.FieldWidth)->getType());
Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, *Data.FieldWidth,
Size, 0);
}
if (Data.Precision) {
CharUnits Size = Ctx.getTypeSizeInChars((*Data.Precision)->getType());
Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, *Data.Precision,
Size, 0);
}
if (Data.Count) {
// "%.*P" has an extra "count" that we insert before the argument.
CharUnits Size = Ctx.getTypeSizeInChars((*Data.Count)->getType());
Layout.Items.emplace_back(OSLogBufferItem::CountKind, *Data.Count, Size,
0);
}
if (Data.Size)
Layout.Items.emplace_back(Ctx, CharUnits::fromQuantity(*Data.Size),
Data.Flags);
if (Data.Kind) {
CharUnits Size;
if (*Data.Kind == OSLogBufferItem::ErrnoKind)
Size = CharUnits::Zero();
else
Size = Ctx.getTypeSizeInChars(Data.E->getType());
Layout.Items.emplace_back(*Data.Kind, Data.E, Size, Data.Flags);
} else {
auto Size = Ctx.getTypeSizeInChars(Data.E->getType());
Layout.Items.emplace_back(OSLogBufferItem::ScalarKind, Data.E, Size,
Data.Flags);
}
}
}
};
} // end anonymous namespace
bool clang::analyze_os_log::computeOSLogBufferLayout(
ASTContext &Ctx, const CallExpr *E, OSLogBufferLayout &Layout) {
ArrayRef<const Expr *> Args(E->getArgs(), E->getArgs() + E->getNumArgs());
const Expr *StringArg;
ArrayRef<const Expr *> VarArgs;
switch (E->getBuiltinCallee()) {
case Builtin::BI__builtin_os_log_format_buffer_size:
assert(E->getNumArgs() >= 1 &&
"__builtin_os_log_format_buffer_size takes at least 1 argument");
StringArg = E->getArg(0);
VarArgs = Args.slice(1);
break;
case Builtin::BI__builtin_os_log_format:
assert(E->getNumArgs() >= 2 &&
"__builtin_os_log_format takes at least 2 arguments");
StringArg = E->getArg(1);
VarArgs = Args.slice(2);
break;
default:
llvm_unreachable("non-os_log builtin passed to computeOSLogBufferLayout");
}
const StringLiteral *Lit = cast<StringLiteral>(StringArg->IgnoreParenCasts());
assert(Lit && (Lit->isAscii() || Lit->isUTF8()));
StringRef Data = Lit->getString();
OSLogFormatStringHandler H(VarArgs);
ParsePrintfString(H, Data.begin(), Data.end(), Ctx.getLangOpts(),
Ctx.getTargetInfo(), /*isFreeBSDKPrintf*/ false);
H.computeLayout(Ctx, Layout);
return true;
}

View File

@ -0,0 +1,67 @@
//= ObjCNoReturn.cpp - Handling of Cocoa APIs known not to return --*- 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 special handling of recognizing ObjC API hooks that
// do not return but aren't marked as such in API headers.
//
//===----------------------------------------------------------------------===//
#include "clang/AST/ASTContext.h"
#include "clang/AST/ExprObjC.h"
#include "clang/Analysis/DomainSpecific/ObjCNoReturn.h"
using namespace clang;
static bool isSubclass(const ObjCInterfaceDecl *Class, IdentifierInfo *II) {
if (!Class)
return false;
if (Class->getIdentifier() == II)
return true;
return isSubclass(Class->getSuperClass(), II);
}
ObjCNoReturn::ObjCNoReturn(ASTContext &C)
: RaiseSel(GetNullarySelector("raise", C)),
NSExceptionII(&C.Idents.get("NSException"))
{
// Generate selectors.
SmallVector<IdentifierInfo*, 3> II;
// raise:format:
II.push_back(&C.Idents.get("raise"));
II.push_back(&C.Idents.get("format"));
NSExceptionInstanceRaiseSelectors[0] =
C.Selectors.getSelector(II.size(), &II[0]);
// raise:format:arguments:
II.push_back(&C.Idents.get("arguments"));
NSExceptionInstanceRaiseSelectors[1] =
C.Selectors.getSelector(II.size(), &II[0]);
}
bool ObjCNoReturn::isImplicitNoReturn(const ObjCMessageExpr *ME) {
Selector S = ME->getSelector();
if (ME->isInstanceMessage()) {
// Check for the "raise" message.
return S == RaiseSel;
}
if (const ObjCInterfaceDecl *ID = ME->getReceiverInterface()) {
if (isSubclass(ID, NSExceptionII)) {
for (unsigned i = 0; i < NUM_RAISE_SELECTORS; ++i) {
if (S == NSExceptionInstanceRaiseSelectors[i])
return true;
}
}
}
return false;
}

View File

@ -0,0 +1,49 @@
//===- PostOrderCFGView.cpp - Post order view of CFG blocks -------*- 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 post order view of the blocks in a CFG.
//
//===----------------------------------------------------------------------===//
#include "clang/Analysis/Analyses/PostOrderCFGView.h"
using namespace clang;
void PostOrderCFGView::anchor() { }
PostOrderCFGView::PostOrderCFGView(const CFG *cfg) {
Blocks.reserve(cfg->getNumBlockIDs());
CFGBlockSet BSet(cfg);
for (po_iterator I = po_iterator::begin(cfg, BSet),
E = po_iterator::end(cfg, BSet); I != E; ++I) {
BlockOrder[*I] = Blocks.size() + 1;
Blocks.push_back(*I);
}
}
PostOrderCFGView *PostOrderCFGView::create(AnalysisDeclContext &ctx) {
const CFG *cfg = ctx.getCFG();
if (!cfg)
return nullptr;
return new PostOrderCFGView(cfg);
}
const void *PostOrderCFGView::getTag() { static int x; return &x; }
bool PostOrderCFGView::BlockOrderCompare::operator()(const CFGBlock *b1,
const CFGBlock *b2) const {
PostOrderCFGView::BlockOrderTy::const_iterator b1It = POV.BlockOrder.find(b1);
PostOrderCFGView::BlockOrderTy::const_iterator b2It = POV.BlockOrder.find(b2);
unsigned b1V = (b1It == POV.BlockOrder.end()) ? 0 : b1It->second;
unsigned b2V = (b2It == POV.BlockOrder.end()) ? 0 : b2It->second;
return b1V > b2V;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,52 @@
//==- ProgramPoint.cpp - Program Points for Path-Sensitive Analysis -*- 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 the interface ProgramPoint, which identifies a
// distinct location in a function.
//
//===----------------------------------------------------------------------===//
#include "clang/Analysis/ProgramPoint.h"
using namespace clang;
ProgramPointTag::~ProgramPointTag() {}
ProgramPoint ProgramPoint::getProgramPoint(const Stmt *S, ProgramPoint::Kind K,
const LocationContext *LC,
const ProgramPointTag *tag){
switch (K) {
default:
llvm_unreachable("Unhandled ProgramPoint kind");
case ProgramPoint::PreStmtKind:
return PreStmt(S, LC, tag);
case ProgramPoint::PostStmtKind:
return PostStmt(S, LC, tag);
case ProgramPoint::PreLoadKind:
return PreLoad(S, LC, tag);
case ProgramPoint::PostLoadKind:
return PostLoad(S, LC, tag);
case ProgramPoint::PreStoreKind:
return PreStore(S, LC, tag);
case ProgramPoint::PostLValueKind:
return PostLValue(S, LC, tag);
case ProgramPoint::PostStmtPurgeDeadSymbolsKind:
return PostStmtPurgeDeadSymbols(S, LC, tag);
case ProgramPoint::PreStmtPurgeDeadSymbolsKind:
return PreStmtPurgeDeadSymbols(S, LC, tag);
}
}
SimpleProgramPointTag::SimpleProgramPointTag(StringRef MsgProvider,
StringRef Msg)
: Desc((MsgProvider + " : " + Msg).str()) {}
StringRef SimpleProgramPointTag::getTagDescription() const {
return Desc;
}

Some files were not shown because too many files have changed in this diff Show More