r340407 - [analyzer] Improve `CallDescription` to handle c++ method.
Henry Wong via cfe-commits
cfe-commits at lists.llvm.org
Wed Aug 22 06:30:46 PDT 2018
Author: henrywong
Date: Wed Aug 22 06:30:46 2018
New Revision: 340407
URL: http://llvm.org/viewvc/llvm-project?rev=340407&view=rev
Log:
[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
Modified:
cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
cfe/trunk/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp
cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp
Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h?rev=340407&r1=340406&r2=340407&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h Wed Aug 22 06:30:46 2018
@@ -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>
Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp?rev=340407&r1=340406&r2=340407&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/InnerPointerChecker.cpp Wed Aug 22 06:30:46 2018
@@ -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(
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);
- // Check [string.require] / second point.
- if (isInvalidatingMemberFunction(Call)) {
- markPtrSymbolsReleased(Call, State, ObjRegion, C);
- return;
+ State = State->set<RawPtrMap>(ObjRegion, Set);
+ C.addTransition(State);
}
+ return;
+ }
+
+ // Check [string.require] / second point.
+ if (isInvalidatingMemberFunction(Call)) {
+ markPtrSymbolsReleased(Call, State, ObjRegion, C);
+ return;
}
}
Modified: cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp?rev=340407&r1=340406&r2=340407&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/CallEvent.cpp Wed Aug 22 06:30:46 2018
@@ -359,11 +359,38 @@ bool CallEvent::isCalled(const CallDescr
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());
}
More information about the cfe-commits
mailing list