Skip to content

Commit b05d37d

Browse files
committed
Revert "Respect the [[clang::unsafe_buffer_usage]] attribute for field and constructor initializers (#91991)"
This reverts commit a518ed2 because it causes regression. See #91991 (comment) for detail.
1 parent 46d8aa8 commit b05d37d

File tree

3 files changed

+45
-224
lines changed

3 files changed

+45
-224
lines changed

clang/lib/Analysis/UnsafeBufferUsage.cpp

Lines changed: 45 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -171,12 +171,6 @@ class MatchDescendantVisitor
171171
return VisitorBase::TraverseCXXTypeidExpr(Node);
172172
}
173173

174-
bool TraverseCXXDefaultInitExpr(CXXDefaultInitExpr *Node) {
175-
if (!TraverseStmt(Node->getExpr()))
176-
return false;
177-
return VisitorBase::TraverseCXXDefaultInitExpr(Node);
178-
}
179-
180174
bool TraverseStmt(Stmt *Node, DataRecursionQueue *Queue = nullptr) {
181175
if (!Node)
182176
return true;
@@ -1998,18 +1992,14 @@ class DerefSimplePtrArithFixableGadget : public FixableGadget {
19981992
};
19991993

20001994
/// Scan the function and return a list of gadgets found with provided kits.
2001-
static void findGadgets(const Stmt *S, ASTContext &Ctx,
2002-
const UnsafeBufferUsageHandler &Handler,
2003-
bool EmitSuggestions, FixableGadgetList &FixableGadgets,
2004-
WarningGadgetList &WarningGadgets,
2005-
DeclUseTracker &Tracker) {
1995+
static std::tuple<FixableGadgetList, WarningGadgetList, DeclUseTracker>
1996+
findGadgets(const Decl *D, const UnsafeBufferUsageHandler &Handler,
1997+
bool EmitSuggestions) {
20061998

20071999
struct GadgetFinderCallback : MatchFinder::MatchCallback {
2008-
GadgetFinderCallback(FixableGadgetList &FixableGadgets,
2009-
WarningGadgetList &WarningGadgets,
2010-
DeclUseTracker &Tracker)
2011-
: FixableGadgets(FixableGadgets), WarningGadgets(WarningGadgets),
2012-
Tracker(Tracker) {}
2000+
FixableGadgetList FixableGadgets;
2001+
WarningGadgetList WarningGadgets;
2002+
DeclUseTracker Tracker;
20132003

20142004
void run(const MatchFinder::MatchResult &Result) override {
20152005
// In debug mode, assert that we've found exactly one gadget.
@@ -2050,14 +2040,10 @@ static void findGadgets(const Stmt *S, ASTContext &Ctx,
20502040
assert(numFound >= 1 && "Gadgets not found in match result!");
20512041
assert(numFound <= 1 && "Conflicting bind tags in gadgets!");
20522042
}
2053-
2054-
FixableGadgetList &FixableGadgets;
2055-
WarningGadgetList &WarningGadgets;
2056-
DeclUseTracker &Tracker;
20572043
};
20582044

20592045
MatchFinder M;
2060-
GadgetFinderCallback CB{FixableGadgets, WarningGadgets, Tracker};
2046+
GadgetFinderCallback CB;
20612047

20622048
// clang-format off
20632049
M.addMatcher(
@@ -2102,7 +2088,9 @@ static void findGadgets(const Stmt *S, ASTContext &Ctx,
21022088
// clang-format on
21032089
}
21042090

2105-
M.match(*S, Ctx);
2091+
M.match(*D->getBody(), D->getASTContext());
2092+
return {std::move(CB.FixableGadgets), std::move(CB.WarningGadgets),
2093+
std::move(CB.Tracker)};
21062094
}
21072095

21082096
// Compares AST nodes by source locations.
@@ -3646,9 +3634,39 @@ class VariableGroupsManagerImpl : public VariableGroupsManager {
36463634
}
36473635
};
36483636

3649-
void applyGadgets(const Decl *D, FixableGadgetList FixableGadgets,
3650-
WarningGadgetList WarningGadgets, DeclUseTracker Tracker,
3651-
UnsafeBufferUsageHandler &Handler, bool EmitSuggestions) {
3637+
void clang::checkUnsafeBufferUsage(const Decl *D,
3638+
UnsafeBufferUsageHandler &Handler,
3639+
bool EmitSuggestions) {
3640+
#ifndef NDEBUG
3641+
Handler.clearDebugNotes();
3642+
#endif
3643+
3644+
assert(D && D->getBody());
3645+
// We do not want to visit a Lambda expression defined inside a method
3646+
// independently. Instead, it should be visited along with the outer method.
3647+
// FIXME: do we want to do the same thing for `BlockDecl`s?
3648+
if (const auto *fd = dyn_cast<CXXMethodDecl>(D)) {
3649+
if (fd->getParent()->isLambda() && fd->getParent()->isLocalClass())
3650+
return;
3651+
}
3652+
3653+
// Do not emit fixit suggestions for functions declared in an
3654+
// extern "C" block.
3655+
if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
3656+
for (FunctionDecl *FReDecl : FD->redecls()) {
3657+
if (FReDecl->isExternC()) {
3658+
EmitSuggestions = false;
3659+
break;
3660+
}
3661+
}
3662+
}
3663+
3664+
WarningGadgetSets UnsafeOps;
3665+
FixableGadgetSets FixablesForAllVars;
3666+
3667+
auto [FixableGadgets, WarningGadgets, Tracker] =
3668+
findGadgets(D, Handler, EmitSuggestions);
3669+
36523670
if (!EmitSuggestions) {
36533671
// Our job is very easy without suggestions. Just warn about
36543672
// every problematic operation and consider it done. No need to deal
@@ -3692,10 +3710,8 @@ void applyGadgets(const Decl *D, FixableGadgetList FixableGadgets,
36923710
if (WarningGadgets.empty())
36933711
return;
36943712

3695-
WarningGadgetSets UnsafeOps =
3696-
groupWarningGadgetsByVar(std::move(WarningGadgets));
3697-
FixableGadgetSets FixablesForAllVars =
3698-
groupFixablesByVar(std::move(FixableGadgets));
3713+
UnsafeOps = groupWarningGadgetsByVar(std::move(WarningGadgets));
3714+
FixablesForAllVars = groupFixablesByVar(std::move(FixableGadgets));
36993715

37003716
std::map<const VarDecl *, FixItList> FixItsForVariableGroup;
37013717

@@ -3916,56 +3932,3 @@ void applyGadgets(const Decl *D, FixableGadgetList FixableGadgets,
39163932
}
39173933
}
39183934
}
3919-
3920-
void clang::checkUnsafeBufferUsage(const Decl *D,
3921-
UnsafeBufferUsageHandler &Handler,
3922-
bool EmitSuggestions) {
3923-
#ifndef NDEBUG
3924-
Handler.clearDebugNotes();
3925-
#endif
3926-
3927-
assert(D);
3928-
3929-
SmallVector<Stmt *> Stmts;
3930-
3931-
if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
3932-
// We do not want to visit a Lambda expression defined inside a method
3933-
// independently. Instead, it should be visited along with the outer method.
3934-
// FIXME: do we want to do the same thing for `BlockDecl`s?
3935-
if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
3936-
if (MD->getParent()->isLambda() && MD->getParent()->isLocalClass())
3937-
return;
3938-
}
3939-
3940-
for (FunctionDecl *FReDecl : FD->redecls()) {
3941-
if (FReDecl->isExternC()) {
3942-
// Do not emit fixit suggestions for functions declared in an
3943-
// extern "C" block.
3944-
EmitSuggestions = false;
3945-
break;
3946-
}
3947-
}
3948-
3949-
Stmts.push_back(FD->getBody());
3950-
3951-
if (const auto *ID = dyn_cast<CXXConstructorDecl>(D)) {
3952-
for (const CXXCtorInitializer *CI : ID->inits()) {
3953-
Stmts.push_back(CI->getInit());
3954-
}
3955-
}
3956-
} else if (isa<BlockDecl>(D) || isa<ObjCMethodDecl>(D)) {
3957-
Stmts.push_back(D->getBody());
3958-
}
3959-
3960-
assert(!Stmts.empty());
3961-
3962-
FixableGadgetList FixableGadgets;
3963-
WarningGadgetList WarningGadgets;
3964-
DeclUseTracker Tracker;
3965-
for (Stmt *S : Stmts) {
3966-
findGadgets(S, D->getASTContext(), Handler, EmitSuggestions, FixableGadgets,
3967-
WarningGadgets, Tracker);
3968-
}
3969-
applyGadgets(D, std::move(FixableGadgets), std::move(WarningGadgets),
3970-
std::move(Tracker), Handler, EmitSuggestions);
3971-
}

clang/test/SemaCXX/warn-unsafe-buffer-usage-function-attr.cpp

Lines changed: 0 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -111,37 +111,6 @@ int testFoldExpression(Vs&&... v) {
111111
return (... + v); // expected-warning{{function introduces unsafe buffer manipulation}}
112112
}
113113

114-
struct HoldsUnsafeMembers {
115-
HoldsUnsafeMembers()
116-
: FromCtor(3), // expected-warning{{function introduces unsafe buffer manipulation}}
117-
FromCtor2{3} // expected-warning{{function introduces unsafe buffer manipulation}}
118-
{}
119-
120-
[[clang::unsafe_buffer_usage]]
121-
HoldsUnsafeMembers(int i)
122-
: FromCtor(i), // expected-warning{{function introduces unsafe buffer manipulation}}
123-
FromCtor2{i} // expected-warning{{function introduces unsafe buffer manipulation}}
124-
{}
125-
126-
HoldsUnsafeMembers(float f)
127-
: HoldsUnsafeMembers(0) {} // expected-warning{{function introduces unsafe buffer manipulation}}
128-
129-
UnsafeMembers FromCtor;
130-
UnsafeMembers FromCtor2;
131-
UnsafeMembers FromField{3}; // expected-warning 2{{function introduces unsafe buffer manipulation}}
132-
};
133-
134-
struct SubclassUnsafeMembers : public UnsafeMembers {
135-
SubclassUnsafeMembers()
136-
: UnsafeMembers(3) // expected-warning{{function introduces unsafe buffer manipulation}}
137-
{}
138-
139-
[[clang::unsafe_buffer_usage]]
140-
SubclassUnsafeMembers(int i)
141-
: UnsafeMembers(i) // expected-warning{{function introduces unsafe buffer manipulation}}
142-
{}
143-
};
144-
145114
// https://github.com/llvm/llvm-project/issues/80482
146115
void testClassMembers() {
147116
UnsafeMembers(3); // expected-warning{{function introduces unsafe buffer manipulation}}
@@ -153,95 +122,4 @@ void testClassMembers() {
153122
UnsafeMembers()(); // expected-warning{{function introduces unsafe buffer manipulation}}
154123

155124
testFoldExpression(UnsafeMembers(), UnsafeMembers());
156-
157-
HoldsUnsafeMembers();
158-
HoldsUnsafeMembers(3); // expected-warning{{function introduces unsafe buffer manipulation}}
159-
160-
SubclassUnsafeMembers();
161-
SubclassUnsafeMembers(3); // expected-warning{{function introduces unsafe buffer manipulation}}
162-
}
163-
164-
// Not an aggregate, so its constructor is not implicit code and will be
165-
// visited/checked for warnings.
166-
struct NotCalledHoldsUnsafeMembers {
167-
NotCalledHoldsUnsafeMembers()
168-
: FromCtor(3), // expected-warning{{function introduces unsafe buffer manipulation}}
169-
FromCtor2{3} // expected-warning{{function introduces unsafe buffer manipulation}}
170-
{}
171-
172-
UnsafeMembers FromCtor;
173-
UnsafeMembers FromCtor2;
174-
UnsafeMembers FromField{3}; // expected-warning{{function introduces unsafe buffer manipulation}}
175-
};
176-
177-
// An aggregate, so its constructor is implicit code. Since it's not called, it
178-
// is never generated.
179-
struct AggregateUnused {
180-
UnsafeMembers f1;
181-
// While this field would trigger the warning during initialization, since
182-
// it's unused, there's no code generated that does the initialization, so
183-
// no warning.
184-
UnsafeMembers f2{3};
185-
};
186-
187-
struct AggregateExplicitlyInitializedSafe {
188-
UnsafeMembers f1;
189-
// The warning is not fired as the field is always explicltly initialized
190-
// elsewhere. This initializer is never used.
191-
UnsafeMembers f2{3};
192-
};
193-
194-
void testAggregateExplicitlyInitializedSafe() {
195-
AggregateExplicitlyInitializedSafe A{
196-
.f2 = UnsafeMembers(), // A safe constructor.
197-
};
198125
}
199-
200-
struct AggregateExplicitlyInitializedUnsafe {
201-
UnsafeMembers f1;
202-
// The warning is not fired as the field is always explicltly initialized
203-
// elsewhere. This initializer is never used.
204-
UnsafeMembers f2{3};
205-
};
206-
207-
void testAggregateExplicitlyInitializedUnsafe() {
208-
AggregateExplicitlyInitializedUnsafe A{
209-
.f2 = UnsafeMembers(3), // expected-warning{{function introduces unsafe buffer manipulation}}
210-
};
211-
}
212-
213-
struct AggregateViaAggregateInit {
214-
UnsafeMembers f1;
215-
// FIXME: A construction of this class does initialize the field through
216-
// this initializer, so it should warn. Ideally it should also point to
217-
// where the site of the construction is in testAggregateViaAggregateInit().
218-
UnsafeMembers f2{3};
219-
};
220-
221-
void testAggregateViaAggregateInit() {
222-
AggregateViaAggregateInit A{};
223-
};
224-
225-
struct AggregateViaValueInit {
226-
UnsafeMembers f1;
227-
// FIXME: A construction of this class does initialize the field through
228-
// this initializer, so it should warn. Ideally it should also point to
229-
// where the site of the construction is in testAggregateViaValueInit().
230-
UnsafeMembers f2{3};
231-
};
232-
233-
void testAggregateViaValueInit() {
234-
auto A = AggregateViaValueInit();
235-
};
236-
237-
struct AggregateViaDefaultInit {
238-
UnsafeMembers f1;
239-
// FIXME: A construction of this class does initialize the field through
240-
// this initializer, so it should warn. Ideally it should also point to
241-
// where the site of the construction is in testAggregateViaValueInit().
242-
UnsafeMembers f2{3};
243-
};
244-
245-
void testAggregateViaDefaultInit() {
246-
AggregateViaDefaultInit A;
247-
};

clang/test/SemaCXX/warn-unsafe-buffer-usage-in-container-span-construct.cpp

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -174,23 +174,3 @@ namespace test_flag {
174174

175175
}
176176
} //namespace test_flag
177-
178-
struct HoldsStdSpanAndInitializedInCtor {
179-
char* Ptr;
180-
unsigned Size;
181-
std::span<char> Span{Ptr, Size}; // no-warning (this code is unreachable)
182-
183-
HoldsStdSpanAndInitializedInCtor(char* P, unsigned S)
184-
: Span(P, S) // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
185-
{}
186-
};
187-
188-
struct HoldsStdSpanAndNotInitializedInCtor {
189-
char* Ptr;
190-
unsigned Size;
191-
std::span<char> Span{Ptr, Size}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
192-
193-
HoldsStdSpanAndNotInitializedInCtor(char* P, unsigned S)
194-
: Ptr(P), Size(S)
195-
{}
196-
};

0 commit comments

Comments
 (0)