[clang] [Clang][CodeGen] Do not set inbounds flag in `EmitMemberDataPointerAddress` when the base pointer is null (PR #130952)
Yingwei Zheng via cfe-commits
cfe-commits at lists.llvm.org
Thu Apr 10 19:00:38 PDT 2025
https://github.com/dtcxzyw updated https://github.com/llvm/llvm-project/pull/130952
>From 9a9c7cf2eff8c740789e9702a190af6dbd3f5014 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Wed, 12 Mar 2025 20:17:28 +0800
Subject: [PATCH 1/3] [Clang][CodeGen] Do not set inbounds in
`EmitMemberDataPointerAddress` when the base pointer is null
---
clang/lib/CodeGen/ItaniumCXXABI.cpp | 11 +++++++---
clang/lib/CodeGen/MicrosoftCXXABI.cpp | 10 ++++++---
.../microsoft-abi-member-pointers.cpp | 21 +++++++++++++++++++
.../CodeGenCXX/pointers-to-data-members.cpp | 21 +++++++++++++++++++
4 files changed, 57 insertions(+), 6 deletions(-)
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index 2822d526a54b0..400510d7056b3 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -872,9 +872,14 @@ llvm::Value *ItaniumCXXABI::EmitMemberDataPointerAddress(
CGBuilderTy &Builder = CGF.Builder;
- // Apply the offset, which we assume is non-null.
- return Builder.CreateInBoundsGEP(CGF.Int8Ty, Base.emitRawPointer(CGF), MemPtr,
- "memptr.offset");
+ // Apply the offset.
+ // Specially, we don't add inbounds flags if the base pointer is a constant
+ // null. This is a workaround for old-style container_of macros.
+ llvm::Value *BaseAddr = Base.emitRawPointer(CGF);
+ return Builder.CreateGEP(CGF.Int8Ty, BaseAddr, MemPtr, "memptr.offset",
+ isa<llvm::ConstantPointerNull>(BaseAddr)
+ ? llvm::GEPNoWrapFlags::none()
+ : llvm::GEPNoWrapFlags::inBounds());
}
// See if it's possible to return a constant signed pointer.
diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
index 7bef436302526..c32ca3be3405e 100644
--- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -3269,9 +3269,13 @@ llvm::Value *MicrosoftCXXABI::EmitMemberDataPointerAddress(
Addr = Base.emitRawPointer(CGF);
}
- // Apply the offset, which we assume is non-null.
- return Builder.CreateInBoundsGEP(CGF.Int8Ty, Addr, FieldOffset,
- "memptr.offset");
+ // Apply the offset.
+ // Specially, we don't add inbounds flags if the base pointer is a constant
+ // null. This is a workaround for old-style container_of macros.
+ return Builder.CreateGEP(CGF.Int8Ty, Addr, FieldOffset, "memptr.offset",
+ isa<llvm::ConstantPointerNull>(Addr)
+ ? llvm::GEPNoWrapFlags::none()
+ : llvm::GEPNoWrapFlags::inBounds());
}
llvm::Value *
diff --git a/clang/test/CodeGenCXX/microsoft-abi-member-pointers.cpp b/clang/test/CodeGenCXX/microsoft-abi-member-pointers.cpp
index fc8a31e0350e5..fe4cab164249f 100644
--- a/clang/test/CodeGenCXX/microsoft-abi-member-pointers.cpp
+++ b/clang/test/CodeGenCXX/microsoft-abi-member-pointers.cpp
@@ -964,3 +964,24 @@ static_assert(sizeof(b::d) == 16, "");
static_assert(sizeof(void (a<int>::*)()) == 16, "");
#endif
}
+
+namespace ContainerOf {
+ using size_t = unsigned long long;
+
+ struct List {
+ int data;
+ };
+
+ struct Node {
+ int data;
+ struct List list1;
+ struct List list2;
+ };
+
+ // CHECK-LABEL: define{{.*}} ptr @"?getOwner at ContainerOf@@
+ // CHECK: %memptr.offset = getelementptr i8, ptr null, {{.*}}
+ Node* getOwner(List *list, List Node::*member) {
+ size_t offset = reinterpret_cast<size_t>(&((Node*)nullptr->*member));
+ return reinterpret_cast<Node*>(reinterpret_cast<char*>(list) - offset);
+ }
+}
diff --git a/clang/test/CodeGenCXX/pointers-to-data-members.cpp b/clang/test/CodeGenCXX/pointers-to-data-members.cpp
index cf1d6c018409d..2ee6c65cf167d 100644
--- a/clang/test/CodeGenCXX/pointers-to-data-members.cpp
+++ b/clang/test/CodeGenCXX/pointers-to-data-members.cpp
@@ -265,3 +265,24 @@ namespace PR47864 {
struct D : B { int m; };
auto x = (int B::*)&D::m;
}
+
+namespace ContainerOf {
+ using size_t = unsigned long long;
+
+ struct List {
+ int data;
+ };
+
+ struct Node {
+ int data;
+ struct List list1;
+ struct List list2;
+ };
+
+ // CHECK-LABEL: define{{.*}} ptr @_ZN11ContainerOf8getOwnerEPNS_4ListEMNS_4NodeES0_
+ // CHECK: %memptr.offset = getelementptr i8, ptr null, i64 {{.*}}
+ Node* getOwner(List *list, List Node::*member) {
+ size_t offset = reinterpret_cast<size_t>(&((Node*)nullptr->*member));
+ return reinterpret_cast<Node*>(reinterpret_cast<char*>(list) - offset);
+ }
+}
>From af9661089cfb2954ced2f73add29f1e2070a1140 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Thu, 10 Apr 2025 12:19:15 +0800
Subject: [PATCH 2/3] [Clang][CodeGen] Address review comments.
---
clang/lib/CodeGen/CGCXXABI.cpp | 7 +++----
clang/lib/CodeGen/CGCXXABI.h | 2 +-
clang/lib/CodeGen/CGClass.cpp | 15 ++++++---------
clang/lib/CodeGen/CGExpr.cpp | 11 ++++++-----
clang/lib/CodeGen/CodeGenFunction.h | 2 +-
clang/lib/CodeGen/ItaniumCXXABI.cpp | 18 +++++++-----------
clang/lib/CodeGen/MicrosoftCXXABI.cpp | 17 +++++++----------
7 files changed, 31 insertions(+), 41 deletions(-)
diff --git a/clang/lib/CodeGen/CGCXXABI.cpp b/clang/lib/CodeGen/CGCXXABI.cpp
index 9f77fbec21380..93dc17bac95e0 100644
--- a/clang/lib/CodeGen/CGCXXABI.cpp
+++ b/clang/lib/CodeGen/CGCXXABI.cpp
@@ -60,10 +60,9 @@ CGCallee CGCXXABI::EmitLoadOfMemberFunctionPointer(
return CGCallee::forDirect(FnPtr, FPT);
}
-llvm::Value *
-CGCXXABI::EmitMemberDataPointerAddress(CodeGenFunction &CGF, const Expr *E,
- Address Base, llvm::Value *MemPtr,
- const MemberPointerType *MPT) {
+llvm::Value *CGCXXABI::EmitMemberDataPointerAddress(
+ CodeGenFunction &CGF, const Expr *E, Address Base, llvm::Value *MemPtr,
+ const MemberPointerType *MPT, bool IsInBounds) {
ErrorUnsupportedABI(CGF, "loads of member pointers");
llvm::Type *Ty =
llvm::PointerType::get(CGF.getLLVMContext(), Base.getAddressSpace());
diff --git a/clang/lib/CodeGen/CGCXXABI.h b/clang/lib/CodeGen/CGCXXABI.h
index 148a7ba6df7e6..da2d367da7096 100644
--- a/clang/lib/CodeGen/CGCXXABI.h
+++ b/clang/lib/CodeGen/CGCXXABI.h
@@ -192,7 +192,7 @@ class CGCXXABI {
virtual llvm::Value *
EmitMemberDataPointerAddress(CodeGenFunction &CGF, const Expr *E,
Address Base, llvm::Value *MemPtr,
- const MemberPointerType *MPT);
+ const MemberPointerType *MPT, bool IsInBounds);
/// Perform a derived-to-base, base-to-derived, or bitcast member
/// pointer conversion.
diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp
index c683dbb0af825..0f2422a6a665a 100644
--- a/clang/lib/CodeGen/CGClass.cpp
+++ b/clang/lib/CodeGen/CGClass.cpp
@@ -147,16 +147,13 @@ Address CodeGenFunction::LoadCXXThisAddress() {
/// Emit the address of a field using a member data pointer.
///
/// \param E Only used for emergency diagnostics
-Address
-CodeGenFunction::EmitCXXMemberDataPointerAddress(const Expr *E, Address base,
- llvm::Value *memberPtr,
- const MemberPointerType *memberPtrType,
- LValueBaseInfo *BaseInfo,
- TBAAAccessInfo *TBAAInfo) {
+Address CodeGenFunction::EmitCXXMemberDataPointerAddress(
+ const Expr *E, Address base, llvm::Value *memberPtr,
+ const MemberPointerType *memberPtrType, bool IsInBounds,
+ LValueBaseInfo *BaseInfo, TBAAAccessInfo *TBAAInfo) {
// Ask the ABI to compute the actual address.
- llvm::Value *ptr =
- CGM.getCXXABI().EmitMemberDataPointerAddress(*this, E, base,
- memberPtr, memberPtrType);
+ llvm::Value *ptr = CGM.getCXXABI().EmitMemberDataPointerAddress(
+ *this, E, base, memberPtr, memberPtrType, IsInBounds);
QualType memberType = memberPtrType->getPointeeType();
CharUnits memberAlign =
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 03aa2e27ee075..4d6e776f42660 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -654,8 +654,8 @@ EmitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *M) {
case SubobjectAdjustment::MemberPointerAdjustment: {
llvm::Value *Ptr = EmitScalarExpr(Adjustment.Ptr.RHS);
- Object = EmitCXXMemberDataPointerAddress(E, Object, Ptr,
- Adjustment.Ptr.MPT);
+ Object = EmitCXXMemberDataPointerAddress(
+ E, Object, Ptr, Adjustment.Ptr.MPT, /*IsInBounds=*/true);
break;
}
}
@@ -6295,9 +6295,10 @@ EmitPointerToDataMemberBinaryExpr(const BinaryOperator *E) {
LValueBaseInfo BaseInfo;
TBAAAccessInfo TBAAInfo;
- Address MemberAddr =
- EmitCXXMemberDataPointerAddress(E, BaseAddr, OffsetV, MPT, &BaseInfo,
- &TBAAInfo);
+ bool IsInBounds = !getLangOpts().PointerOverflowDefined &&
+ !isUnderlyingBasePointerConstantNull(E->getLHS());
+ Address MemberAddr = EmitCXXMemberDataPointerAddress(
+ E, BaseAddr, OffsetV, MPT, IsInBounds, &BaseInfo, &TBAAInfo);
return MakeAddrLValue(MemberAddr, MPT->getPointeeType(), BaseInfo, TBAAInfo);
}
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 9d0a46bc4808b..cdddc69effb86 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -4642,7 +4642,7 @@ class CodeGenFunction : public CodeGenTypeCache {
// Compute the object pointer.
Address EmitCXXMemberDataPointerAddress(
const Expr *E, Address base, llvm::Value *memberPtr,
- const MemberPointerType *memberPtrType,
+ const MemberPointerType *memberPtrType, bool IsInBounds,
LValueBaseInfo *BaseInfo = nullptr, TBAAAccessInfo *TBAAInfo = nullptr);
RValue EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E,
ReturnValueSlot ReturnValue,
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index 400510d7056b3..35485dc6d867f 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -130,11 +130,10 @@ class ItaniumCXXABI : public CodeGen::CGCXXABI {
llvm::Value *MemFnPtr,
const MemberPointerType *MPT) override;
- llvm::Value *
- EmitMemberDataPointerAddress(CodeGenFunction &CGF, const Expr *E,
- Address Base,
- llvm::Value *MemPtr,
- const MemberPointerType *MPT) override;
+ llvm::Value *EmitMemberDataPointerAddress(CodeGenFunction &CGF, const Expr *E,
+ Address Base, llvm::Value *MemPtr,
+ const MemberPointerType *MPT,
+ bool IsInBounds) override;
llvm::Value *EmitMemberPointerConversion(CodeGenFunction &CGF,
const CastExpr *E,
@@ -867,19 +866,16 @@ CGCallee ItaniumCXXABI::EmitLoadOfMemberFunctionPointer(
/// base object.
llvm::Value *ItaniumCXXABI::EmitMemberDataPointerAddress(
CodeGenFunction &CGF, const Expr *E, Address Base, llvm::Value *MemPtr,
- const MemberPointerType *MPT) {
+ const MemberPointerType *MPT, bool IsInBounds) {
assert(MemPtr->getType() == CGM.PtrDiffTy);
CGBuilderTy &Builder = CGF.Builder;
// Apply the offset.
- // Specially, we don't add inbounds flags if the base pointer is a constant
- // null. This is a workaround for old-style container_of macros.
llvm::Value *BaseAddr = Base.emitRawPointer(CGF);
return Builder.CreateGEP(CGF.Int8Ty, BaseAddr, MemPtr, "memptr.offset",
- isa<llvm::ConstantPointerNull>(BaseAddr)
- ? llvm::GEPNoWrapFlags::none()
- : llvm::GEPNoWrapFlags::inBounds());
+ IsInBounds ? llvm::GEPNoWrapFlags::inBounds()
+ : llvm::GEPNoWrapFlags::none());
}
// See if it's possible to return a constant signed pointer.
diff --git a/clang/lib/CodeGen/MicrosoftCXXABI.cpp b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
index c32ca3be3405e..93ca8704de742 100644
--- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp
+++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp
@@ -689,10 +689,10 @@ class MicrosoftCXXABI : public CGCXXABI {
llvm::Value *MemPtr,
const MemberPointerType *MPT) override;
- llvm::Value *
- EmitMemberDataPointerAddress(CodeGenFunction &CGF, const Expr *E,
- Address Base, llvm::Value *MemPtr,
- const MemberPointerType *MPT) override;
+ llvm::Value *EmitMemberDataPointerAddress(CodeGenFunction &CGF, const Expr *E,
+ Address Base, llvm::Value *MemPtr,
+ const MemberPointerType *MPT,
+ bool IsInBounds) override;
llvm::Value *EmitNonNullMemberPointerConversion(
const MemberPointerType *SrcTy, const MemberPointerType *DstTy,
@@ -3240,7 +3240,7 @@ llvm::Value *MicrosoftCXXABI::AdjustVirtualBase(
llvm::Value *MicrosoftCXXABI::EmitMemberDataPointerAddress(
CodeGenFunction &CGF, const Expr *E, Address Base, llvm::Value *MemPtr,
- const MemberPointerType *MPT) {
+ const MemberPointerType *MPT, bool IsInBounds) {
assert(MPT->isMemberDataPointer());
CGBuilderTy &Builder = CGF.Builder;
const CXXRecordDecl *RD = MPT->getMostRecentCXXRecordDecl();
@@ -3270,12 +3270,9 @@ llvm::Value *MicrosoftCXXABI::EmitMemberDataPointerAddress(
}
// Apply the offset.
- // Specially, we don't add inbounds flags if the base pointer is a constant
- // null. This is a workaround for old-style container_of macros.
return Builder.CreateGEP(CGF.Int8Ty, Addr, FieldOffset, "memptr.offset",
- isa<llvm::ConstantPointerNull>(Addr)
- ? llvm::GEPNoWrapFlags::none()
- : llvm::GEPNoWrapFlags::inBounds());
+ IsInBounds ? llvm::GEPNoWrapFlags::inBounds()
+ : llvm::GEPNoWrapFlags::none());
}
llvm::Value *
>From e71ca8b1b011a85e17d4b9764f93af0e132e8f9d Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Fri, 11 Apr 2025 10:00:10 +0800
Subject: [PATCH 3/3] [Clang][Docs] Update ReleaseNotes. NFC.
---
clang/docs/ReleaseNotes.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index fca2c4248155c..5983621a7a875 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -47,7 +47,7 @@ C/C++ Language Potentially Breaking Changes
case for old-style offsetof idioms like ``((int)(&(((struct S *)0)->field)))``, to
ensure they are not caught by these optimizations. It is also possible to use
``-fwrapv-pointer`` or ``-fno-delete-null-pointer-checks`` to make pointer arithmetic
- on null pointers well-defined. (#GH130734, #GH130742)
+ on null pointers well-defined. (#GH130734, #GH130742, #GH130952)
C++ Specific Potentially Breaking Changes
-----------------------------------------
More information about the cfe-commits
mailing list