Skip to content

Commit 429dd67

Browse files
committed
[-Wunsafe-buffer-usage] Fix bug in unsafe cast to incomplete types
Fixed the crash coming from attempting to get size of incomplete types. Casting `span.data()` to pointer-to-incomplete-type should be directly considered unsafe. Solving issue #116286.
1 parent 2f55de4 commit 429dd67

File tree

2 files changed

+33
-7
lines changed

2 files changed

+33
-7
lines changed

clang/lib/Sema/AnalysisBasedWarnings.cpp

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2270,19 +2270,28 @@ class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler {
22702270
MsgParam = 5;
22712271
} else if (const auto *ECE = dyn_cast<ExplicitCastExpr>(Operation)) {
22722272
QualType destType = ECE->getType();
2273+
bool destTypeComplete = true;
2274+
22732275
if (!isa<PointerType>(destType))
22742276
return;
2277+
destType = destType.getTypePtr()->getPointeeType();
2278+
if (const auto *D = destType->getAsTagDecl())
2279+
destTypeComplete = D->isCompleteDefinition();
22752280

2276-
const uint64_t dSize =
2277-
Ctx.getTypeSize(destType.getTypePtr()->getPointeeType());
2281+
// If destination type is incomplete, it is unsafe to cast to anyway, no
2282+
// need to check its type:
2283+
if (destTypeComplete) {
2284+
const uint64_t dSize = Ctx.getTypeSize(destType);
2285+
QualType srcType = ECE->getSubExpr()->getType();
22782286

2279-
QualType srcType = ECE->getSubExpr()->getType();
2280-
const uint64_t sSize =
2281-
Ctx.getTypeSize(srcType.getTypePtr()->getPointeeType());
2287+
assert(srcType->isPointerType());
22822288

2283-
if (sSize >= dSize)
2284-
return;
2289+
const uint64_t sSize =
2290+
Ctx.getTypeSize(srcType.getTypePtr()->getPointeeType());
22852291

2292+
if (sSize >= dSize)
2293+
return;
2294+
}
22862295
if (const auto *CE = dyn_cast<CXXMemberCallExpr>(
22872296
ECE->getSubExpr()->IgnoreParens())) {
22882297
D = CE->getMethodDecl();

clang/test/SemaCXX/warn-unsafe-buffer-usage-warning-data-invocation.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,4 +173,21 @@ A false_negatives(std::span<int> span_pt, span<A> span_A) {
173173
return *a2; // TODO: Can cause OOB if span_pt is empty
174174

175175
}
176+
177+
void test_incomplete_type(std::span<char> S) {
178+
(struct IncompleteStruct *)S.data(); // expected-warning{{unsafe invocation of 'data'}}
179+
(class IncompleteClass *)S.data(); // expected-warning{{unsafe invocation of 'data'}}
180+
(union IncompleteUnion *)S.data(); // expected-warning{{unsafe invocation of 'data'}}
181+
}
182+
183+
void test_complete_type(std::span<long> S) {
184+
(struct CompleteStruct *)S.data(); // no warn as the struct size is smaller than long
185+
(class CompleteClass *)S.data(); // no warn as the class size is smaller than long
186+
(union CompleteUnion *)S.data(); // no warn as the union size is smaller than long
187+
188+
struct CompleteStruct {};
189+
class CompleteClass {};
190+
union CompleteUnion {};
191+
}
192+
176193
#endif

0 commit comments

Comments
 (0)