https://github.com/ahatanak created https://github.com/llvm/llvm-project/pull/137429
clang currently issues a warning when memset is used on a struct that contains an address-discriminated pointer field, even though this is entirely valid behavior. For example: ``` struct S { int * __ptrauth(1, 1, 100) p; } s; memset(&s, 0, sizeof(struct S)); ``` Only allow the warning to be emitted in C++ mode to silence the warning. rdar://142495870 >From e9e673f956891f603d63e1184f33ad9e7a0fc11f Mon Sep 17 00:00:00 2001 From: Akira Hatanaka <ahata...@gmail.com> Date: Fri, 25 Apr 2025 18:37:22 -0700 Subject: [PATCH] Silence spurious -Wnontrivial-memcall warnings in C mode clang currently issues a warning when memset is used on a struct that contains an address-discriminated pointer field, even though this is entirely valid behavior. For example: ``` struct S { int * __ptrauth(1, 1, 100) p; } s; memset(&s, 0, sizeof(struct S)); ``` Only allow the warning to be emitted in C++ mode to silence the warning. rdar://142495870 --- clang/lib/Sema/SemaChecking.cpp | 10 ++--- ...warn-nontrivial-struct-memaccess-ptrauth.c | 42 +++++++++++++++++++ 2 files changed, 47 insertions(+), 5 deletions(-) create mode 100644 clang/test/Sema/warn-nontrivial-struct-memaccess-ptrauth.c diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 9c9372d9ee2b0..ee3b55c83699e 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -9724,9 +9724,9 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call, // completed later. GCC does not diagnose such code, but we may want to // consider diagnosing it in the future, perhaps under a different, but // related, diagnostic group. - bool MayBeTriviallyCopyableCXXRecord = - RT->isIncompleteType() || - RT->desugar().isTriviallyCopyableType(Context); + bool NonTriviallyCopyableCXXRecord = + getLangOpts().CPlusPlus && !RT->isIncompleteType() && + !RT->desugar().isTriviallyCopyableType(Context); if ((BId == Builtin::BImemset || BId == Builtin::BIbzero) && RT->getDecl()->isNonTrivialToPrimitiveDefaultInitialize()) { @@ -9735,7 +9735,7 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call, << ArgIdx << FnName << PointeeTy << 0); SearchNonTrivialToInitializeField::diag(PointeeTy, Dest, *this); } else if ((BId == Builtin::BImemset || BId == Builtin::BIbzero) && - !MayBeTriviallyCopyableCXXRecord && ArgIdx == 0) { + NonTriviallyCopyableCXXRecord && ArgIdx == 0) { // FIXME: Limiting this warning to dest argument until we decide // whether it's valid for source argument too. DiagRuntimeBehavior(Dest->getExprLoc(), Dest, @@ -9748,7 +9748,7 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call, << ArgIdx << FnName << PointeeTy << 1); SearchNonTrivialToCopyField::diag(PointeeTy, Dest, *this); } else if ((BId == Builtin::BImemcpy || BId == Builtin::BImemmove) && - !MayBeTriviallyCopyableCXXRecord && ArgIdx == 0) { + NonTriviallyCopyableCXXRecord && ArgIdx == 0) { // FIXME: Limiting this warning to dest argument until we decide // whether it's valid for source argument too. DiagRuntimeBehavior(Dest->getExprLoc(), Dest, diff --git a/clang/test/Sema/warn-nontrivial-struct-memaccess-ptrauth.c b/clang/test/Sema/warn-nontrivial-struct-memaccess-ptrauth.c new file mode 100644 index 0000000000000..d9cd712330c1b --- /dev/null +++ b/clang/test/Sema/warn-nontrivial-struct-memaccess-ptrauth.c @@ -0,0 +1,42 @@ +// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics -fsyntax-only -verify %s +// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics -fsyntax-only -verify %s + +void *memset(void *, int, __SIZE_TYPE__); +void bzero(void *, __SIZE_TYPE__); +void *memcpy(void *, const void *, __SIZE_TYPE__); +void *memmove(void *, const void *, __SIZE_TYPE__); + +#define AQ __ptrauth(1,1,50) +#define IQ __ptrauth(1,0,50) + +struct PtrAuthTrivial { + int f0; + int * IQ f1; +}; + +struct PtrAuthNonTrivial0 { + int f0; + int * AQ f1; // expected-note 2 {{non-trivial to copy}} + int f2; +}; + +struct PtrAuthNonTrivial1 { + int * AQ f0; // expected-note 2 {{non-trivial to copy}} + int f1; + struct PtrAuthNonTrivial0 f2; +}; + +void testPtrAuthTrivial(struct PtrAuthTrivial *d, struct PtrAuthTrivial *s) { + memset(d, 0, sizeof(struct PtrAuthTrivial)); + bzero(d, sizeof(struct PtrAuthTrivial)); + memcpy(d, s, sizeof(struct PtrAuthTrivial)); + memmove(d, s, sizeof(struct PtrAuthTrivial)); +} + +void testPtrAuthNonTrivial1(struct PtrAuthNonTrivial1 *d, + struct PtrAuthNonTrivial1 *s) { + memset(d, 0, sizeof(struct PtrAuthNonTrivial1)); + bzero(d, sizeof(struct PtrAuthNonTrivial1)); + memcpy(d, s, sizeof(struct PtrAuthNonTrivial1)); // expected-warning {{that is not trivial to primitive-copy}} expected-note {{explicitly cast the pointer to silence}} + memmove(d, s, sizeof(struct PtrAuthNonTrivial1)); // expected-warning {{that is not trivial to primitive-copy}} expected-note {{explicitly cast the pointer to silence}} +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits