Skip to content

Commit 78606af

Browse files
authored
[-Wunsafe-buffer-usage] Fix bug in unsafe casts to incomplete types (#116433)
Fixed the crash coming from attempting to get size of incomplete types. Casting `span.data()` to a pointer-to-incomplete-type should be immediately considered unsafe. Solving issue #116286. Co-authored-by: Ziqing Luo <[email protected]>
1 parent 6e2b77d commit 78606af

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
@@ -2262,19 +2262,28 @@ class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler {
22622262
MsgParam = 5;
22632263
} else if (const auto *ECE = dyn_cast<ExplicitCastExpr>(Operation)) {
22642264
QualType destType = ECE->getType();
2265+
bool destTypeComplete = true;
2266+
22652267
if (!isa<PointerType>(destType))
22662268
return;
2269+
destType = destType.getTypePtr()->getPointeeType();
2270+
if (const auto *D = destType->getAsTagDecl())
2271+
destTypeComplete = D->isCompleteDefinition();
22672272

2268-
const uint64_t dSize =
2269-
Ctx.getTypeSize(destType.getTypePtr()->getPointeeType());
2273+
// If destination type is incomplete, it is unsafe to cast to anyway, no
2274+
// need to check its type:
2275+
if (destTypeComplete) {
2276+
const uint64_t dSize = Ctx.getTypeSize(destType);
2277+
QualType srcType = ECE->getSubExpr()->getType();
22702278

2271-
QualType srcType = ECE->getSubExpr()->getType();
2272-
const uint64_t sSize =
2273-
Ctx.getTypeSize(srcType.getTypePtr()->getPointeeType());
2279+
assert(srcType->isPointerType());
22742280

2275-
if (sSize >= dSize)
2276-
return;
2281+
const uint64_t sSize =
2282+
Ctx.getTypeSize(srcType.getTypePtr()->getPointeeType());
22772283

2284+
if (sSize >= dSize)
2285+
return;
2286+
}
22782287
if (const auto *CE = dyn_cast<CXXMemberCallExpr>(
22792288
ECE->getSubExpr()->IgnoreParens())) {
22802289
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)