Skip to content

Commit c1dafd7

Browse files
committedAug 9, 2019
More warnings regarding gsl::Pointer and gsl::Owner attributes
Differential Revision: https://reviews.llvm.org/D65120 llvm-svn: 368446
1 parent 69ab7a0 commit c1dafd7

File tree

3 files changed

+74
-20
lines changed

3 files changed

+74
-20
lines changed
 

‎clang/lib/Sema/SemaInit.cpp

+22-4
Original file line numberDiff line numberDiff line change
@@ -6564,6 +6564,25 @@ template <typename T> static bool isRecordWithAttr(QualType Type) {
65646564
return false;
65656565
}
65666566

6567+
static bool shouldTrackImplicitObjectArg(const CXXMethodDecl *Callee) {
6568+
if (auto *Conv = dyn_cast_or_null<CXXConversionDecl>(Callee))
6569+
if (isRecordWithAttr<PointerAttr>(Conv->getConversionType()))
6570+
return true;
6571+
if (!Callee->getParent()->isInStdNamespace() || !Callee->getIdentifier())
6572+
return false;
6573+
if (!isRecordWithAttr<PointerAttr>(Callee->getThisObjectType()) &&
6574+
!isRecordWithAttr<OwnerAttr>(Callee->getThisObjectType()))
6575+
return false;
6576+
if (!isRecordWithAttr<PointerAttr>(Callee->getReturnType()) &&
6577+
!Callee->getReturnType()->isPointerType())
6578+
return false;
6579+
return llvm::StringSwitch<bool>(Callee->getName())
6580+
.Cases("begin", "rbegin", "cbegin", "crbegin", true)
6581+
.Cases("end", "rend", "cend", "crend", true)
6582+
.Cases("c_str", "data", "get", true)
6583+
.Default(false);
6584+
}
6585+
65676586
static void handleGslAnnotatedTypes(IndirectLocalPath &Path, Expr *Call,
65686587
LocalVisitor Visit) {
65696588
auto VisitPointerArg = [&](const Decl *D, Expr *Arg) {
@@ -6577,10 +6596,9 @@ static void handleGslAnnotatedTypes(IndirectLocalPath &Path, Expr *Call,
65776596
};
65786597

65796598
if (auto *MCE = dyn_cast<CXXMemberCallExpr>(Call)) {
6580-
const FunctionDecl *Callee = MCE->getDirectCallee();
6581-
if (auto *Conv = dyn_cast_or_null<CXXConversionDecl>(Callee))
6582-
if (isRecordWithAttr<PointerAttr>(Conv->getConversionType()))
6583-
VisitPointerArg(Callee, MCE->getImplicitObjectArgument());
6599+
const auto *MD = cast_or_null<CXXMethodDecl>(MCE->getDirectCallee());
6600+
if (MD && shouldTrackImplicitObjectArg(MD))
6601+
VisitPointerArg(MD, MCE->getImplicitObjectArgument());
65846602
return;
65856603
}
65866604

‎clang/test/Analysis/inner-pointer.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
// RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.InnerPointer \
1+
// RUN: %clang_analyze_cc1 -analyzer-checker=cplusplus.InnerPointer \
2+
// RUN: -Wno-dangling -Wno-dangling-field -Wno-return-stack-address \
23
// RUN: %s -analyzer-output=text -verify
34

45
#include "Inputs/system-header-simulator-cxx.h"

‎clang/test/Sema/warn-lifetime-analysis-nocfg.cpp

+50-15
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
struct [[gsl::Owner(int)]] MyIntOwner {
33
MyIntOwner();
44
int &operator*();
5-
int *c_str() const;
65
};
76

87
struct [[gsl::Pointer(int)]] MyIntPointer {
@@ -52,16 +51,6 @@ long *ownershipTransferToRawPointer() {
5251
return t.releaseAsRawPointer(); // ok
5352
}
5453

55-
int *danglingRawPtrFromLocal() {
56-
MyIntOwner t;
57-
return t.c_str(); // TODO
58-
}
59-
60-
int *danglingRawPtrFromTemp() {
61-
MyIntPointer p;
62-
return p.toOwner().c_str(); // TODO
63-
}
64-
6554
struct Y {
6655
int a[4];
6756
};
@@ -103,6 +92,12 @@ MyIntPointer danglingGslPtrFromTemporary() {
10392
return MyIntOwner{}; // expected-warning {{returning address of local temporary object}}
10493
}
10594

95+
MyIntOwner makeTempOwner();
96+
97+
MyIntPointer danglingGslPtrFromTemporary2() {
98+
return makeTempOwner(); // expected-warning {{returning address of local temporary object}}
99+
}
100+
106101
MyLongPointerFromConversion danglingGslPtrFromTemporaryConv() {
107102
return MyLongOwnerWithConversion{}; // expected-warning {{returning address of local temporary object}}
108103
}
@@ -124,12 +119,52 @@ void initLocalGslPtrWithTempOwner() {
124119
global2 = MyLongOwnerWithConversion{}; // TODO ?
125120
}
126121

127-
struct IntVector {
128-
int *begin();
129-
int *end();
122+
namespace std {
123+
template <typename T>
124+
struct basic_iterator {};
125+
126+
template <typename T>
127+
struct vector {
128+
typedef basic_iterator<T> iterator;
129+
iterator begin();
130+
T *data();
131+
};
132+
133+
template<typename T>
134+
struct basic_string {
135+
const T *c_str() const;
136+
};
137+
138+
template<typename T>
139+
struct unique_ptr {
140+
T *get() const;
130141
};
142+
}
131143

132144
void modelIterators() {
133-
int *it = IntVector{}.begin(); // TODO ?
145+
std::vector<int>::iterator it = std::vector<int>().begin(); // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}}
134146
(void)it;
135147
}
148+
149+
std::vector<int>::iterator modelIteratorReturn() {
150+
return std::vector<int>().begin(); // expected-warning {{returning address of local temporary object}}
151+
}
152+
153+
const char *danglingRawPtrFromLocal() {
154+
std::basic_string<char> s;
155+
return s.c_str(); // expected-warning {{address of stack memory associated with local variable 's' returned}}
156+
}
157+
158+
const char *danglingRawPtrFromTemp() {
159+
return std::basic_string<char>().c_str(); // expected-warning {{returning address of local temporary object}}
160+
}
161+
162+
std::unique_ptr<int> getUniquePtr();
163+
164+
int *danglingUniquePtrFromTemp() {
165+
return getUniquePtr().get(); // expected-warning {{returning address of local temporary object}}
166+
}
167+
168+
int *danglingUniquePtrFromTemp2() {
169+
return std::unique_ptr<int>().get(); // expected-warning {{returning address of local temporary object}}
170+
}

0 commit comments

Comments
 (0)