https://github.com/pl98 updated https://github.com/llvm/llvm-project/pull/205426
>From 2e5a6b69599f26841454880379295104ceb5027f Mon Sep 17 00:00:00 2001 From: Phoebe Liang <[email protected]> Date: Tue, 23 Jun 2026 16:33:23 -0400 Subject: [PATCH 1/2] [Clang][Sema] Guard type size queries on incomplete types in -Wunsafe-buffer-usage When evaluating explicit pointer casts of container `.data()` invocations, skip querying pointee size if the source or destination pointee type is incomplete or dependent. Previously, destination pointee types were checked using `getAsTagDecl()->isCompleteDefinition()`, which missed incomplete array types (`T[]`) and non-C++ tag declarations. Source pointee types were passed directly to `Ctx.getTypeSize()` without any completeness guard. Querying `getTypeSize()` on incomplete types resulted in assertion failures in debug builds and segmentation faults in release builds. This change guards both source and destination types. --- clang/lib/Sema/AnalysisBasedWarnings.cpp | 22 ++++++++++--------- ...e-buffer-usage-warning-data-invocation.cpp | 20 +++++++++++++---- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index 52fe7765c6c6a..70135d22e724d 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -2508,27 +2508,29 @@ 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(); - // If destination type is incomplete, it is unsafe to cast to anyway, no - // need to check its type: - if (destTypeComplete) { + // If destination type is incomplete or dependent, it is unsafe to cast + // to anyway, no need to check its type: + if (!destType->isIncompleteType() && !destType->isDependentType()) { const uint64_t dSize = Ctx.getTypeSize(destType); QualType srcType = ECE->getSubExpr()->getType(); assert(srcType->isPointerType()); - const uint64_t sSize = - Ctx.getTypeSize(srcType.getTypePtr()->getPointeeType()); + QualType srcPointeeType = srcType.getTypePtr()->getPointeeType(); - if (sSize >= dSize) - return; + // Check if source type is incomplete or dependent as well: + if (!srcPointeeType->isIncompleteType() && + !srcPointeeType->isDependentType()) { + const uint64_t sSize = Ctx.getTypeSize(srcPointeeType); + + if (sSize >= dSize) + return; + } } if (const auto *CE = dyn_cast<CXXMemberCallExpr>( ECE->getSubExpr()->IgnoreParens())) { 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 a6a334d247023..41ac0f12743bd 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 @@ -174,10 +174,22 @@ A false_negatives(std::span<int> span_pt, span<A> span_A) { } -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'}} +struct IncompleteStruct; +class IncompleteClass; +union IncompleteUnion; + +void test_incomplete_dest_type(std::span<char> S) { + (IncompleteStruct *)S.data(); // expected-warning{{unsafe invocation of 'data'}} + (IncompleteClass *)S.data(); // expected-warning{{unsafe invocation of 'data'}} + (IncompleteUnion *)S.data(); // expected-warning{{unsafe invocation of 'data'}} +} + +void test_incomplete_source_type(std::span<IncompleteStruct> S) { + (float *)S.data(); // expected-warning{{unsafe invocation of 'data'}} +} + +void test_incomplete_array_dest_type(std::span<char> S) { + (IncompleteStruct(*)[])S.data(); // expected-warning{{unsafe invocation of 'data'}} } void test_complete_type(std::span<long> S) { >From ecb2156fc02fb3c4ae672358df7995c1cce58a0d Mon Sep 17 00:00:00 2001 From: Phoebe Liang <[email protected]> Date: Wed, 24 Jun 2026 14:34:33 -0400 Subject: [PATCH 2/2] Add dependent test cases. --- ...safe-buffer-usage-warning-data-invocation.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) 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 41ac0f12743bd..107611d461d9d 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 @@ -192,6 +192,22 @@ void test_incomplete_array_dest_type(std::span<char> S) { (IncompleteStruct(*)[])S.data(); // expected-warning{{unsafe invocation of 'data'}} } +template <typename DestType> +void test_dependent_dest_type(std::span<char> S) { + (DestType *)S.data(); // expected-warning{{unsafe invocation of 'data'}} +} + +template <typename SourceType> +void test_dependent_source_type(std::span<SourceType> S) { + (float *)S.data(); // expected-warning{{unsafe invocation of 'data'}} +} + +void instantiate_dependent_tests(std::span<char> char_span, + std::span<IncompleteStruct> incomplete_span) { + test_dependent_dest_type<IncompleteStruct>(char_span); + test_dependent_source_type<IncompleteStruct>(incomplete_span); +} + 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 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
