[-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 <ziqing_luo@apple.com>
This commit is contained in:
Ziqing Luo 2024-11-18 15:59:48 -08:00 committed by GitHub
parent 6e2b77d469
commit 78606af606
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 33 additions and 7 deletions

View File

@ -2262,19 +2262,28 @@ public:
MsgParam = 5;
} else if (const auto *ECE = dyn_cast<ExplicitCastExpr>(Operation)) {
QualType destType = ECE->getType();
bool destTypeComplete = true;
if (!isa<PointerType>(destType))
return;
destType = destType.getTypePtr()->getPointeeType();
if (const auto *D = destType->getAsTagDecl())
destTypeComplete = D->isCompleteDefinition();
const uint64_t dSize =
Ctx.getTypeSize(destType.getTypePtr()->getPointeeType());
// If destination type is incomplete, it is unsafe to cast to anyway, no
// need to check its type:
if (destTypeComplete) {
const uint64_t dSize = Ctx.getTypeSize(destType);
QualType srcType = ECE->getSubExpr()->getType();
QualType srcType = ECE->getSubExpr()->getType();
const uint64_t sSize =
Ctx.getTypeSize(srcType.getTypePtr()->getPointeeType());
assert(srcType->isPointerType());
if (sSize >= dSize)
return;
const uint64_t sSize =
Ctx.getTypeSize(srcType.getTypePtr()->getPointeeType());
if (sSize >= dSize)
return;
}
if (const auto *CE = dyn_cast<CXXMemberCallExpr>(
ECE->getSubExpr()->IgnoreParens())) {
D = CE->getMethodDecl();

View File

@ -173,4 +173,21 @@ A false_negatives(std::span<int> span_pt, span<A> span_A) {
return *a2; // TODO: Can cause OOB if span_pt is empty
}
void test_incomplete_type(std::span<char> S) {
(struct IncompleteStruct *)S.data(); // expected-warning{{unsafe invocation of 'data'}}
(class IncompleteClass *)S.data(); // expected-warning{{unsafe invocation of 'data'}}
(union IncompleteUnion *)S.data(); // expected-warning{{unsafe invocation of 'data'}}
}
void test_complete_type(std::span<long> S) {
(struct CompleteStruct *)S.data(); // no warn as the struct size is smaller than long
(class CompleteClass *)S.data(); // no warn as the class size is smaller than long
(union CompleteUnion *)S.data(); // no warn as the union size is smaller than long
struct CompleteStruct {};
class CompleteClass {};
union CompleteUnion {};
}
#endif