[clang] [-Wunsafe-buffer-usage] Fix bug in unsafe casts to incomplete types (PR #116433)
Ziqing Luo via cfe-commits
cfe-commits at lists.llvm.org
Fri Nov 15 12:04:56 PST 2024
https://github.com/ziqingluo-90 created https://github.com/llvm/llvm-project/pull/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.
>From 5aacab98129f8c663f737245a04b5a103fcba061 Mon Sep 17 00:00:00 2001
From: Ziqing Luo <ziqing_luo at apple.com>
Date: Thu, 14 Nov 2024 23:08:47 -0800
Subject: [PATCH] [-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.
---
clang/lib/Sema/AnalysisBasedWarnings.cpp | 23 +++++++++++++------
...e-buffer-usage-warning-data-invocation.cpp | 17 ++++++++++++++
2 files changed, 33 insertions(+), 7 deletions(-)
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp
index c76733e9a774b6..129040115acb5c 100644
--- a/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -2270,19 +2270,28 @@ class UnsafeBufferUsageReporter : public UnsafeBufferUsageHandler {
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();
diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-warning-data-invocation.cpp b/clang/test/SemaCXX/warn-unsafe-buffer-usage-warning-data-invocation.cpp
index 0228e42652bd95..a6a334d247023c 100644
--- a/clang/test/SemaCXX/warn-unsafe-buffer-usage-warning-data-invocation.cpp
+++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-warning-data-invocation.cpp
@@ -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
More information about the cfe-commits
mailing list