Skip to content

Commit 6f98400

Browse files
committedSep 3, 2019
[LifetimeAnalysis] Fix some false positives
Differential Revision: https://reviews.llvm.org/D66806 llvm-svn: 370773
1 parent af7f1a1 commit 6f98400

File tree

2 files changed

+163
-5
lines changed

2 files changed

+163
-5
lines changed
 

‎clang/lib/Sema/SemaInit.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -6775,6 +6775,10 @@ static bool shouldTrackFirstArgument(const FunctionDecl *FD) {
67756775
static void handleGslAnnotatedTypes(IndirectLocalPath &Path, Expr *Call,
67766776
LocalVisitor Visit) {
67776777
auto VisitPointerArg = [&](const Decl *D, Expr *Arg) {
6778+
// We are not interested in the temporary base objects of gsl Pointers:
6779+
// Temp().ptr; // Here ptr might not dangle.
6780+
if (isa<MemberExpr>(Arg->IgnoreImpCasts()))
6781+
return;
67786782
Path.push_back({IndirectLocalPathEntry::GslPointerInit, Arg, D});
67796783
if (Arg->isGLValue())
67806784
visitLocalsRetainedByReferenceBinding(Path, Arg, RK_ReferenceBinding,
@@ -7295,6 +7299,8 @@ static bool pathOnlyInitializesGslPointer(IndirectLocalPath &Path) {
72957299
for (auto It = Path.rbegin(), End = Path.rend(); It != End; ++It) {
72967300
if (It->Kind == IndirectLocalPathEntry::VarInit)
72977301
continue;
7302+
if (It->Kind == IndirectLocalPathEntry::AddressOf)
7303+
continue;
72987304
return It->Kind == IndirectLocalPathEntry::GslPointerInit;
72997305
}
73007306
return false;

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

+157-5
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,21 @@ struct [[gsl::Owner(int)]] MyIntOwner {
77
struct [[gsl::Pointer(int)]] MyIntPointer {
88
MyIntPointer(int *p = nullptr);
99
// Conversion operator and constructor conversion will result in two
10-
// different ASTs. The former is tested with another owner and
10+
// different ASTs. The former is tested with another owner and
1111
// pointer type.
1212
MyIntPointer(const MyIntOwner &);
1313
int &operator*();
1414
MyIntOwner toOwner();
1515
};
1616

17+
struct MySpecialIntPointer : MyIntPointer {
18+
};
19+
20+
// We did see examples in the wild when a derived class changes
21+
// the ownership model. So we have a test for it.
22+
struct [[gsl::Owner(int)]] MyOwnerIntPointer : MyIntPointer {
23+
};
24+
1725
struct [[gsl::Pointer(long)]] MyLongPointerFromConversion {
1826
MyLongPointerFromConversion(long *p = nullptr);
1927
long &operator*();
@@ -56,21 +64,21 @@ struct Y {
5664
};
5765

5866
void dangligGslPtrFromTemporary() {
59-
MyIntPointer p = Y{}.a; // expected-warning {{temporary whose address is used as value of local variable 'p' will be destroyed at the end of the full-expression}}
67+
MyIntPointer p = Y{}.a; // TODO
6068
(void)p;
6169
}
6270

6371
struct DanglingGslPtrField {
64-
MyIntPointer p; // expected-note 2{{pointer member declared here}}
72+
MyIntPointer p; // expected-note {{pointer member declared here}}
6573
MyLongPointerFromConversion p2; // expected-note {{pointer member declared here}}
66-
DanglingGslPtrField(int i) : p(&i) {} // expected-warning {{initializing pointer member 'p' with the stack address of parameter 'i'}}
74+
DanglingGslPtrField(int i) : p(&i) {} // TODO
6775
DanglingGslPtrField() : p2(MyLongOwnerWithConversion{}) {} // expected-warning {{initializing pointer member 'p2' to point to a temporary object whose lifetime is shorter than the lifetime of the constructed object}}
6876
DanglingGslPtrField(double) : p(MyIntOwner{}) {} // expected-warning {{initializing pointer member 'p' to point to a temporary object whose lifetime is shorter than the lifetime of the constructed object}}
6977
};
7078

7179
MyIntPointer danglingGslPtrFromLocal() {
7280
int j;
73-
return &j; // expected-warning {{address of stack memory associated with local variable 'j' returned}}
81+
return &j; // TODO
7482
}
7583

7684
MyIntPointer returningLocalPointer() {
@@ -124,6 +132,7 @@ template <typename T>
124132
struct basic_iterator {
125133
basic_iterator operator++();
126134
T& operator*() const;
135+
T* operator->() const;
127136
};
128137

129138
template<typename T>
@@ -141,6 +150,12 @@ typename remove_reference<T>::type &&move(T &&t) noexcept;
141150
template <typename C>
142151
auto data(const C &c) -> decltype(c.data());
143152

153+
template <typename C>
154+
auto begin(C &c) -> decltype(c.begin());
155+
156+
template<typename T, int N>
157+
T *begin(T (&array)[N]);
158+
144159
template <typename T>
145160
struct vector {
146161
typedef __gnu_cxx::basic_iterator<T> iterator;
@@ -158,6 +173,8 @@ struct basic_string_view {
158173

159174
template<typename T>
160175
struct basic_string {
176+
basic_string();
177+
basic_string(const T *);
161178
const T *c_str() const;
162179
operator basic_string_view<T> () const;
163180
};
@@ -188,8 +205,23 @@ struct any {};
188205

189206
template<typename T>
190207
T any_cast(const any& operand);
208+
209+
template<typename T>
210+
struct reference_wrapper {
211+
template<typename U>
212+
reference_wrapper(U &&);
213+
};
214+
215+
template<typename T>
216+
reference_wrapper<T> ref(T& t) noexcept;
191217
}
192218

219+
struct Unannotated {
220+
typedef std::vector<int>::iterator iterator;
221+
iterator begin();
222+
operator iterator() const;
223+
};
224+
193225
void modelIterators() {
194226
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}}
195227
(void)it;
@@ -298,3 +330,123 @@ void handleGslPtrInitsThroughReference2() {
298330
const std::vector<int> &v = getVec();
299331
const int *val = v.data(); // Ok, it is lifetime extended.
300332
}
333+
334+
void handleTernaryOperator(bool cond) {
335+
std::basic_string<char> def;
336+
std::basic_string_view<char> v = cond ? def : ""; // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}}
337+
}
338+
339+
std::reference_wrapper<int> danglingPtrFromNonOwnerLocal() {
340+
int i = 5;
341+
return i; // TODO
342+
}
343+
344+
std::reference_wrapper<int> danglingPtrFromNonOwnerLocal2() {
345+
int i = 5;
346+
return std::ref(i); // TODO
347+
}
348+
349+
std::reference_wrapper<int> danglingPtrFromNonOwnerLocal3() {
350+
int i = 5;
351+
return std::reference_wrapper<int>(i); // TODO
352+
}
353+
354+
std::reference_wrapper<Unannotated> danglingPtrFromNonOwnerLocal4() {
355+
Unannotated i;
356+
return std::reference_wrapper<Unannotated>(i); // TODO
357+
}
358+
359+
std::reference_wrapper<Unannotated> danglingPtrFromNonOwnerLocal5() {
360+
Unannotated i;
361+
return std::ref(i); // TODO
362+
}
363+
364+
int *returnPtrToLocalArray() {
365+
int a[5];
366+
return std::begin(a); // TODO
367+
}
368+
369+
struct ptr_wrapper {
370+
std::vector<int>::iterator member;
371+
};
372+
373+
ptr_wrapper getPtrWrapper();
374+
375+
std::vector<int>::iterator returnPtrFromWrapper() {
376+
ptr_wrapper local = getPtrWrapper();
377+
return local.member;
378+
}
379+
380+
std::vector<int>::iterator returnPtrFromWrapperThroughRef() {
381+
ptr_wrapper local = getPtrWrapper();
382+
ptr_wrapper &local2 = local;
383+
return local2.member;
384+
}
385+
386+
std::vector<int>::iterator returnPtrFromWrapperThroughRef2() {
387+
ptr_wrapper local = getPtrWrapper();
388+
std::vector<int>::iterator &local2 = local.member;
389+
return local2;
390+
}
391+
392+
void checkPtrMemberFromAggregate() {
393+
std::vector<int>::iterator local = getPtrWrapper().member; // OK.
394+
}
395+
396+
std::vector<int>::iterator doNotInterferWithUnannotated() {
397+
Unannotated value;
398+
// Conservative choice for now. Probably not ok, but we do not warn.
399+
return std::begin(value);
400+
}
401+
402+
std::vector<int>::iterator doNotInterferWithUnannotated2() {
403+
Unannotated value;
404+
return value;
405+
}
406+
407+
std::vector<int>::iterator supportDerefAddrofChain(int a, std::vector<int>::iterator value) {
408+
switch (a) {
409+
default:
410+
return value;
411+
case 1:
412+
return *&value;
413+
case 2:
414+
return *&*&value;
415+
case 3:
416+
return *&*&*&value;
417+
}
418+
}
419+
420+
int &supportDerefAddrofChain2(int a, std::vector<int>::iterator value) {
421+
switch (a) {
422+
default:
423+
return *value;
424+
case 1:
425+
return **&value;
426+
case 2:
427+
return **&*&value;
428+
case 3:
429+
return **&*&*&value;
430+
}
431+
}
432+
433+
int *supportDerefAddrofChain3(int a, std::vector<int>::iterator value) {
434+
switch (a) {
435+
default:
436+
return &*value;
437+
case 1:
438+
return &*&*value;
439+
case 2:
440+
return &*&**&value;
441+
case 3:
442+
return &*&**&*&value;
443+
}
444+
}
445+
446+
MyIntPointer handleDerivedToBaseCast1(MySpecialIntPointer ptr) {
447+
return ptr;
448+
}
449+
450+
MyIntPointer handleDerivedToBaseCast2(MyOwnerIntPointer ptr) {
451+
return ptr; // expected-warning {{address of stack memory associated with parameter 'ptr' returned}}
452+
}

0 commit comments

Comments
 (0)
Please sign in to comment.