summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHenry Wong <movietravelcode@outlook.com>2018-08-22 13:30:46 +0000
committerHenry Wong <movietravelcode@outlook.com>2018-08-22 13:30:46 +0000
commit2ca72e03c3e690d618319c9563b5e28d10b9f857 (patch)
treebf98de0cd91c72fc27d335fd68bbe7093ee1d078
parent03533087105994646891a903e4730fa68b8bf173 (diff)
downloadbcm5719-llvm-2ca72e03c3e690d618319c9563b5e28d10b9f857.tar.gz
bcm5719-llvm-2ca72e03c3e690d618319c9563b5e28d10b9f857.zip
[analyzer] Improve `CallDescription` to handle c++ method.
Summary: `CallDecription` can only handle function for the time being. If we want to match c++ method, we can only use method name to match and can't improve the matching accuracy through the qualifiers. This patch add the support for `QualifiedName` matching to improve the matching accuracy. Reviewers: xazax.hun, NoQ, george.karpenkov, rnkovacs Reviewed By: xazax.hun, NoQ, rnkovacs Subscribers: Szelethus, szepet, rnkovacs, a.sidorin, mikhail.ramalho, cfe-commits, MTC Differential Revision: https://reviews.llvm.org/D48027 llvm-svn: 340407
-rw-r--r--clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h23
-rw-r--r--clang/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp85
-rw-r--r--clang/lib/StaticAnalyzer/Core/CallEvent.cpp29
3 files changed, 85 insertions, 52 deletions
diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
index 6557f382135..f8b2cf70646 100644
--- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
+++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
@@ -80,7 +80,9 @@ class CallDescription {
mutable IdentifierInfo *II = nullptr;
mutable bool IsLookupDone = false;
- StringRef FuncName;
+ // The list of the qualified names used to identify the specified CallEvent,
+ // e.g. "{a, b}" represent the qualified names, like "a::b".
+ std::vector<StringRef> QualifiedName;
unsigned RequiredArgs;
public:
@@ -88,16 +90,31 @@ public:
/// Constructs a CallDescription object.
///
+ /// @param QualifiedName The list of the qualified names of the function that
+ /// will be matched. It does not require the user to provide the full list of
+ /// the qualified name. The more details provided, the more accurate the
+ /// matching.
+ ///
+ /// @param RequiredArgs The number of arguments that is expected to match a
+ /// call. Omit this parameter to match every occurrence of call with a given
+ /// name regardless the number of arguments.
+ CallDescription(std::vector<StringRef> QualifiedName,
+ unsigned RequiredArgs = NoArgRequirement)
+ : QualifiedName(QualifiedName), RequiredArgs(RequiredArgs) {}
+
+ /// Constructs a CallDescription object.
+ ///
/// @param FuncName The name of the function that will be matched.
///
/// @param RequiredArgs The number of arguments that is expected to match a
/// call. Omit this parameter to match every occurrence of call with a given
/// name regardless the number of arguments.
CallDescription(StringRef FuncName, unsigned RequiredArgs = NoArgRequirement)
- : FuncName(FuncName), RequiredArgs(RequiredArgs) {}
+ : CallDescription(std::vector<StringRef>({FuncName}), NoArgRequirement) {
+ }
/// Get the name of the function that this object matches.
- StringRef getFunctionName() const { return FuncName; }
+ StringRef getFunctionName() const { return QualifiedName.back(); }
};
template<typename T = CallEvent>
diff --git a/clang/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp
index 926a1d7d842..91805e40a3d 100644
--- a/clang/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp
@@ -86,14 +86,20 @@ public:
};
InnerPointerChecker()
- : AppendFn("append"), AssignFn("assign"), ClearFn("clear"),
- CStrFn("c_str"), DataFn("data"), EraseFn("erase"), InsertFn("insert"),
- PopBackFn("pop_back"), PushBackFn("push_back"), ReplaceFn("replace"),
- ReserveFn("reserve"), ResizeFn("resize"),
- ShrinkToFitFn("shrink_to_fit"), SwapFn("swap") {}
-
- /// Check if the object of this member function call is a `basic_string`.
- bool isCalledOnStringObject(const CXXInstanceCall *ICall) const;
+ : AppendFn({"std", "basic_string", "append"}),
+ AssignFn({"std", "basic_string", "assign"}),
+ ClearFn({"std", "basic_string", "clear"}),
+ CStrFn({"std", "basic_string", "c_str"}),
+ DataFn({"std", "basic_string", "data"}),
+ EraseFn({"std", "basic_string", "erase"}),
+ InsertFn({"std", "basic_string", "insert"}),
+ PopBackFn({"std", "basic_string", "pop_back"}),
+ PushBackFn({"std", "basic_string", "push_back"}),
+ ReplaceFn({"std", "basic_string", "replace"}),
+ ReserveFn({"std", "basic_string", "reserve"}),
+ ResizeFn({"std", "basic_string", "resize"}),
+ ShrinkToFitFn({"std", "basic_string", "shrink_to_fit"}),
+ SwapFn({"std", "basic_string", "swap"}) {}
/// Check whether the called member function potentially invalidates
/// pointers referring to the container object's inner buffer.
@@ -122,21 +128,6 @@ public:
} // end anonymous namespace
-bool InnerPointerChecker::isCalledOnStringObject(
- const CXXInstanceCall *ICall) const {
- const auto *ObjRegion =
- dyn_cast_or_null<TypedValueRegion>(ICall->getCXXThisVal().getAsRegion());
- if (!ObjRegion)
- return false;
-
- QualType ObjTy = ObjRegion->getValueType();
- if (ObjTy.isNull())
- return false;
-
- CXXRecordDecl *Decl = ObjTy->getAsCXXRecordDecl();
- return Decl && Decl->getName() == "basic_string";
-}
-
bool InnerPointerChecker::isInvalidatingMemberFunction(
const CallEvent &Call) const {
if (const auto *MemOpCall = dyn_cast<CXXMemberOperatorCall>(&Call)) {
@@ -220,33 +211,31 @@ void InnerPointerChecker::checkPostCall(const CallEvent &Call,
ProgramStateRef State = C.getState();
if (const auto *ICall = dyn_cast<CXXInstanceCall>(&Call)) {
- if (isCalledOnStringObject(ICall)) {
- const auto *ObjRegion = dyn_cast_or_null<TypedValueRegion>(
- ICall->getCXXThisVal().getAsRegion());
-
- if (Call.isCalled(CStrFn) || Call.isCalled(DataFn)) {
- SVal RawPtr = Call.getReturnValue();
- if (SymbolRef Sym = RawPtr.getAsSymbol(/*IncludeBaseRegions=*/true)) {
- // Start tracking this raw pointer by adding it to the set of symbols
- // associated with this container object in the program state map.
-
- PtrSet::Factory &F = State->getStateManager().get_context<PtrSet>();
- const PtrSet *SetPtr = State->get<RawPtrMap>(ObjRegion);
- PtrSet Set = SetPtr ? *SetPtr : F.getEmptySet();
- assert(C.wasInlined || !Set.contains(Sym));
- Set = F.add(Set, Sym);
-
- State = State->set<RawPtrMap>(ObjRegion, Set);
- C.addTransition(State);
- }
- return;
+ const auto *ObjRegion = dyn_cast_or_null<TypedValueRegion>(
+ ICall->getCXXThisVal().getAsRegion());
+
+ if (Call.isCalled(CStrFn) || Call.isCalled(DataFn)) {
+ SVal RawPtr = Call.getReturnValue();
+ if (SymbolRef Sym = RawPtr.getAsSymbol(/*IncludeBaseRegions=*/true)) {
+ // Start tracking this raw pointer by adding it to the set of symbols
+ // associated with this container object in the program state map.
+
+ PtrSet::Factory &F = State->getStateManager().get_context<PtrSet>();
+ const PtrSet *SetPtr = State->get<RawPtrMap>(ObjRegion);
+ PtrSet Set = SetPtr ? *SetPtr : F.getEmptySet();
+ assert(C.wasInlined || !Set.contains(Sym));
+ Set = F.add(Set, Sym);
+
+ State = State->set<RawPtrMap>(ObjRegion, Set);
+ C.addTransition(State);
}
+ return;
+ }
- // Check [string.require] / second point.
- if (isInvalidatingMemberFunction(Call)) {
- markPtrSymbolsReleased(Call, State, ObjRegion, C);
- return;
- }
+ // Check [string.require] / second point.
+ if (isInvalidatingMemberFunction(Call)) {
+ markPtrSymbolsReleased(Call, State, ObjRegion, C);
+ return;
}
}
diff --git a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
index b1688184d87..3ba68d4cdd2 100644
--- a/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/clang/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -359,11 +359,38 @@ bool CallEvent::isCalled(const CallDescription &CD) const {
return false;
if (!CD.IsLookupDone) {
CD.IsLookupDone = true;
- CD.II = &getState()->getStateManager().getContext().Idents.get(CD.FuncName);
+ CD.II = &getState()->getStateManager().getContext().Idents.get(
+ CD.getFunctionName());
}
const IdentifierInfo *II = getCalleeIdentifier();
if (!II || II != CD.II)
return false;
+
+ const Decl *D = getDecl();
+ // If CallDescription provides prefix names, use them to improve matching
+ // accuracy.
+ if (CD.QualifiedName.size() > 1 && D) {
+ const DeclContext *Ctx = D->getDeclContext();
+ std::vector<StringRef> QualifiedName = CD.QualifiedName;
+ QualifiedName.pop_back();
+ for (; Ctx && isa<NamedDecl>(Ctx); Ctx = Ctx->getParent()) {
+ if (const auto *ND = dyn_cast<NamespaceDecl>(Ctx)) {
+ if (!QualifiedName.empty() && ND->getName() == QualifiedName.back())
+ QualifiedName.pop_back();
+ continue;
+ }
+
+ if (const auto *RD = dyn_cast<RecordDecl>(Ctx)) {
+ if (!QualifiedName.empty() && RD->getName() == QualifiedName.back())
+ QualifiedName.pop_back();
+ continue;
+ }
+ }
+
+ if (!QualifiedName.empty())
+ return false;
+ }
+
return (CD.RequiredArgs == CallDescription::NoArgRequirement ||
CD.RequiredArgs == getNumArgs());
}
OpenPOWER on IntegriCloud