https://github.com/dtcxzyw created https://github.com/llvm/llvm-project/pull/130952
See also https://github.com/llvm/llvm-project/pull/130734 for the original motivation. This pattern (`container_of`) is also widely used by real-world programs. Examples: https://github.com/llvm/llvm-project/blob/1d89d7d5d76e391b035f50343e2a4890506c6f2b/llvm/include/llvm/IR/SymbolTableListTraits.h#L77-L87 https://github.com/nodejs/node/blob/a2a53cb728ec5f776ac16879ce0f480a8e838320/src/util-inl.h#L134-L137 https://github.com/search?q=*%29nullptr-%3E*&type=code >From 824a5e7551437233ed6a7990d43572b8c50a5397 Mon Sep 17 00:00:00 2001 From: Yingwei Zheng <dtcxzyw2...@gmail.com> Date: Wed, 12 Mar 2025 20:17:28 +0800 Subject: [PATCH] [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 b145da0f0ec09..b2eaea683ebe7 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 4b55fc3f17bd7..3501b2b2fdca8 100644 --- a/clang/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/clang/lib/CodeGen/MicrosoftCXXABI.cpp @@ -3265,9 +3265,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@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); + } +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits