Skip to content

Commit 0683c4e

Browse files
committed
Revert "[clang] Diagnose dangling issues for the "Container<GSLPointer>" case. (#107213)"
This reverts commit e50131a. It introduces a new false positive, see comment #107213 (comment)
1 parent 703ebca commit 0683c4e

File tree

4 files changed

+9
-126
lines changed

4 files changed

+9
-126
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -301,8 +301,6 @@ Improvements to Clang's diagnostics
301301

302302
- Clang now warns for u8 character literals used in C23 with ``-Wpre-c23-compat`` instead of ``-Wpre-c++17-compat``.
303303

304-
- Clang now diagnoses cases where a dangling ``GSLOwner<GSLPointer>`` object is constructed, e.g. ``std::vector<string_view> v = {std::string()};`` (#GH100526).
305-
306304
Improvements to Clang's time-trace
307305
----------------------------------
308306

clang/include/clang/Basic/AttrDocs.td

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6690,20 +6690,6 @@ When the Owner's lifetime ends, it will consider the Pointer to be dangling.
66906690
P.getInt(); // P is dangling
66916691
}
66926692

6693-
If a template class is annotated with ``[[gsl::Owner]]``, and the first
6694-
instantiated template argument is a pointer type (raw pointer, or ``[[gsl::Pointer]]``),
6695-
the analysis will consider the instantiated class as a container of the pointer.
6696-
When constructing such an object from a GSL owner object, the analysis will
6697-
assume that the container holds a pointer to the owner object. Consequently,
6698-
when the owner object is destroyed, the pointer will be considered dangling.
6699-
6700-
.. code-block:: c++
6701-
6702-
int f() {
6703-
std::vector<std::string_view> v = {std::string()}; // v holds a dangling pointer.
6704-
std::optional<std::string_view> o = std::string(); // o holds a dangling pointer.
6705-
}
6706-
67076693
}];
67086694
}
67096695

clang/lib/Sema/CheckExprLifetime.cpp

Lines changed: 9 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -267,26 +267,6 @@ static bool isInStlNamespace(const Decl *D) {
267267
return DC->isStdNamespace();
268268
}
269269

270-
// Returns true if the given Record decl is a form of `GSLOwner<Pointer>`
271-
// type, e.g. std::vector<string_view>, std::optional<string_view>.
272-
static bool isContainerOfPointer(const RecordDecl *Container) {
273-
if (const auto *CTSD =
274-
dyn_cast_if_present<ClassTemplateSpecializationDecl>(Container)) {
275-
if (!CTSD->hasAttr<OwnerAttr>()) // Container must be a GSL owner type.
276-
return false;
277-
const auto &TAs = CTSD->getTemplateArgs();
278-
return TAs.size() > 0 && TAs[0].getKind() == TemplateArgument::Type &&
279-
(isRecordWithAttr<PointerAttr>(TAs[0].getAsType()) ||
280-
TAs[0].getAsType()->isPointerType());
281-
}
282-
return false;
283-
}
284-
285-
static bool isGSLOwner(QualType T) {
286-
return isRecordWithAttr<OwnerAttr>(T) &&
287-
!isContainerOfPointer(T->getAsRecordDecl());
288-
}
289-
290270
static bool shouldTrackImplicitObjectArg(const CXXMethodDecl *Callee) {
291271
if (auto *Conv = dyn_cast_or_null<CXXConversionDecl>(Callee))
292272
if (isRecordWithAttr<PointerAttr>(Conv->getConversionType()))
@@ -295,7 +275,7 @@ static bool shouldTrackImplicitObjectArg(const CXXMethodDecl *Callee) {
295275
return false;
296276
if (!isRecordWithAttr<PointerAttr>(
297277
Callee->getFunctionObjectParameterType()) &&
298-
!isGSLOwner(Callee->getFunctionObjectParameterType()))
278+
!isRecordWithAttr<OwnerAttr>(Callee->getFunctionObjectParameterType()))
299279
return false;
300280
if (Callee->getReturnType()->isPointerType() ||
301281
isRecordWithAttr<PointerAttr>(Callee->getReturnType())) {
@@ -433,7 +413,7 @@ static void visitFunctionCallArguments(IndirectLocalPath &Path, Expr *Call,
433413
// Once we initialized a value with a non gsl-owner reference, it can no
434414
// longer dangle.
435415
if (ReturnType->isReferenceType() &&
436-
!isGSLOwner(ReturnType->getPointeeType())) {
416+
!isRecordWithAttr<OwnerAttr>(ReturnType->getPointeeType())) {
437417
for (const IndirectLocalPathEntry &PE : llvm::reverse(Path)) {
438418
if (PE.Kind == IndirectLocalPathEntry::GslReferenceInit ||
439419
PE.Kind == IndirectLocalPathEntry::LifetimeBoundCall)
@@ -488,17 +468,12 @@ static void visitFunctionCallArguments(IndirectLocalPath &Path, Expr *Call,
488468
if (CheckCoroCall || Callee->getParamDecl(I)->hasAttr<LifetimeBoundAttr>())
489469
VisitLifetimeBoundArg(Callee->getParamDecl(I), Args[I]);
490470
else if (EnableGSLAnalysis && I == 0) {
491-
// Perform GSL analysis for the first argument
492471
if (shouldTrackFirstArgument(Callee)) {
493472
VisitGSLPointerArg(Callee, Args[0]);
494-
} else if (auto *Ctor = dyn_cast<CXXConstructExpr>(Call)) {
495-
const auto *ClassD = Ctor->getConstructor()->getParent();
496-
// Two cases:
497-
// a GSL pointer, e.g. std::string_view
498-
// a container of GSL pointer, e.g. std::vector<string_view>
499-
if (ClassD->hasAttr<PointerAttr>() ||
500-
(isContainerOfPointer(ClassD) && Callee->getNumParams() == 1))
501-
VisitGSLPointerArg(Ctor->getConstructor(), Args[0]);
473+
} else if (auto *CCE = dyn_cast<CXXConstructExpr>(Call);
474+
CCE &&
475+
CCE->getConstructor()->getParent()->hasAttr<PointerAttr>()) {
476+
VisitGSLPointerArg(CCE->getConstructor(), Args[0]);
502477
}
503478
}
504479
}
@@ -1010,12 +985,13 @@ static void checkExprLifetimeImpl(Sema &SemaRef,
1010985
// int &p = *localUniquePtr;
1011986
// someContainer.add(std::move(localUniquePtr));
1012987
// return p;
1013-
IsLocalGslOwner = isGSLOwner(L->getType());
988+
IsLocalGslOwner = isRecordWithAttr<OwnerAttr>(L->getType());
1014989
if (pathContainsInit(Path) || !IsLocalGslOwner)
1015990
return false;
1016991
} else {
1017992
IsGslPtrValueFromGslTempOwner =
1018-
MTE && !MTE->getExtendingDecl() && isGSLOwner(MTE->getType());
993+
MTE && !MTE->getExtendingDecl() &&
994+
isRecordWithAttr<OwnerAttr>(MTE->getType());
1019995
// Skipping a chain of initializing gsl::Pointer annotated objects.
1020996
// We are looking only for the final source to find out if it was
1021997
// a local or temporary owner or the address of a local variable/param.

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

Lines changed: 0 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -158,30 +158,17 @@ auto begin(C &c) -> decltype(c.begin());
158158
template<typename T, int N>
159159
T *begin(T (&array)[N]);
160160

161-
using size_t = decltype(sizeof(0));
162-
163-
template<typename T>
164-
struct initializer_list {
165-
const T* ptr; size_t sz;
166-
};
167161
template <typename T>
168162
struct vector {
169163
typedef __gnu_cxx::basic_iterator<T> iterator;
170164
iterator begin();
171165
iterator end();
172166
const T *data() const;
173-
vector();
174-
vector(initializer_list<T> __l);
175-
176-
template<typename InputIterator>
177-
vector(InputIterator first, InputIterator __last);
178-
179167
T &at(int n);
180168
};
181169

182170
template<typename T>
183171
struct basic_string_view {
184-
basic_string_view();
185172
basic_string_view(const T *);
186173
const T *begin() const;
187174
};
@@ -216,21 +203,11 @@ template<typename T>
216203
struct optional {
217204
optional();
218205
optional(const T&);
219-
220-
template<typename U = T>
221-
optional(U&& t);
222-
223-
template<typename U>
224-
optional(optional<U>&& __t);
225-
226206
T &operator*() &;
227207
T &&operator*() &&;
228208
T &value() &;
229209
T &&value() &&;
230210
};
231-
template<typename T>
232-
optional<__decay(T)> make_optional(T&&);
233-
234211

235212
template<typename T>
236213
struct stack {
@@ -576,57 +553,3 @@ void test() {
576553
std::string_view svjkk1 = ReturnStringView(StrCat("bar", "x")); // expected-warning {{object backing the pointer will be destroyed at the end of the full-expression}}
577554
}
578555
} // namespace GH100549
579-
580-
namespace GH100526 {
581-
void test() {
582-
std::vector<std::string_view> v1({std::string()}); // expected-warning {{object backing the pointer will be destroyed at the end}}
583-
std::vector<std::string_view> v2({
584-
std::string(), // expected-warning {{object backing the pointer will be destroyed at the end}}
585-
std::string_view()
586-
});
587-
std::vector<std::string_view> v3({
588-
std::string_view(),
589-
std::string() // expected-warning {{object backing the pointer will be destroyed at the end}}
590-
});
591-
592-
std::optional<std::string_view> o1 = std::string(); // expected-warning {{object backing the pointer}}
593-
594-
std::string s;
595-
// This is a tricky use-after-free case, what it does:
596-
// 1. make_optional creates a temporary "optional<string>"" object
597-
// 2. the temporary object owns the underlying string which is copied from s.
598-
// 3. the t3 object holds the view to the underlying string of the temporary object.
599-
std::optional<std::string_view> o2 = std::make_optional(s); // expected-warning {{object backing the pointer}}
600-
std::optional<std::string_view> o3 = std::optional<std::string>(s); // expected-warning {{object backing the pointer}}
601-
std::optional<std::string_view> o4 = std::optional<std::string_view>(s);
602-
603-
// FIXME: should work for assignment cases
604-
v1 = {std::string()};
605-
o1 = std::string();
606-
607-
// no warning on copying pointers.
608-
std::vector<std::string_view> n1 = {std::string_view()};
609-
std::optional<std::string_view> n2 = {std::string_view()};
610-
std::optional<std::string_view> n3 = std::string_view();
611-
std::optional<std::string_view> n4 = std::make_optional(std::string_view());
612-
const char* b = "";
613-
std::optional<std::string_view> n5 = std::make_optional(b);
614-
std::optional<std::string_view> n6 = std::make_optional("test");
615-
}
616-
617-
std::vector<std::string_view> test2(int i) {
618-
std::vector<std::string_view> t;
619-
if (i)
620-
return t; // this is fine, no dangling
621-
return std::vector<std::string_view>(t.begin(), t.end());
622-
}
623-
624-
std::optional<std::string_view> test3(int i) {
625-
std::string s;
626-
std::string_view sv;
627-
if (i)
628-
return s; // expected-warning {{address of stack memory associated}}
629-
return sv; // fine
630-
}
631-
632-
} // namespace GH100526

0 commit comments

Comments
 (0)