[clang] [PAC] Re-sign a pointer to a noexcept member function when it is converted to a pointer to a member function without noexcept (PR #109056)
Akira Hatanaka via cfe-commits
cfe-commits at lists.llvm.org
Tue Sep 17 14:27:32 PDT 2024
https://github.com/ahatanak created https://github.com/llvm/llvm-project/pull/109056
Fixes https://github.com/llvm/llvm-project/issues/106487.
>From eede4b2c2916a3016643fb56f87f7601dfaff69b Mon Sep 17 00:00:00 2001
From: Akira Hatanaka <ahatanak at gmail.com>
Date: Mon, 16 Sep 2024 17:12:13 -0700
Subject: [PATCH] [PAC] Re-sign a pointer to a noexcept member function when it
is converted to a pointer to a member function without noexcept
Fixes https://github.com/llvm/llvm-project/issues/106487.
---
clang/lib/CodeGen/CGExprScalar.cpp | 9 +-
clang/lib/CodeGen/ItaniumCXXABI.cpp | 28 ++++-
.../ptrauth-member-function-pointer.cpp | 109 +++++++++++++++++-
3 files changed, 136 insertions(+), 10 deletions(-)
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp
index 82caf65ac68d6b..76e2f047e84ae4 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -2419,8 +2419,13 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
return Visit(const_cast<Expr*>(E));
case CK_NoOp: {
- return CE->changesVolatileQualification() ? EmitLoadOfLValue(CE)
- : Visit(const_cast<Expr *>(E));
+ if (CE->changesVolatileQualification())
+ return EmitLoadOfLValue(CE);
+ auto V = Visit(const_cast<Expr *>(E));
+ if (CGF.CGM.getCodeGenOpts().PointerAuth.CXXMemberFunctionPointers &&
+ CE->getType()->isMemberFunctionPointerType())
+ V = CGF.CGM.getCXXABI().EmitMemberPointerConversion(CGF, CE, V);
+ return V;
}
case CK_BaseToDerived: {
diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index dcc35d5689831e..085ed84b5108b4 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -924,17 +924,20 @@ ItaniumCXXABI::EmitMemberPointerConversion(CodeGenFunction &CGF,
if (isa<llvm::Constant>(src))
return EmitMemberPointerConversion(E, cast<llvm::Constant>(src));
+ QualType DstType = E->getType(), SrcType = E->getSubExpr()->getType();
+
assert(E->getCastKind() == CK_DerivedToBaseMemberPointer ||
E->getCastKind() == CK_BaseToDerivedMemberPointer ||
- E->getCastKind() == CK_ReinterpretMemberPointer);
+ E->getCastKind() == CK_ReinterpretMemberPointer ||
+ (E->getCastKind() == CK_NoOp &&
+ getContext().hasSameFunctionTypeIgnoringExceptionSpec(
+ DstType->getPointeeType(), SrcType->getPointeeType())));
CGBuilderTy &Builder = CGF.Builder;
- QualType DstType = E->getType();
if (DstType->isMemberFunctionPointerType()) {
if (const auto &NewAuthInfo =
CGM.getMemberFunctionPointerAuthInfo(DstType)) {
- QualType SrcType = E->getSubExpr()->getType();
assert(SrcType->isMemberFunctionPointerType());
const auto &CurAuthInfo = CGM.getMemberFunctionPointerAuthInfo(SrcType);
llvm::Value *MemFnPtr = Builder.CreateExtractValue(src, 0, "memptr.ptr");
@@ -971,6 +974,11 @@ ItaniumCXXABI::EmitMemberPointerConversion(CodeGenFunction &CGF,
}
}
+ // Conversion from a pointer to a noexcept member function to a pointer to a
+ // member function without noexcept doesn't require any additional processing.
+ if (E->getCastKind() == CK_NoOp)
+ return src;
+
// Under Itanium, reinterprets don't require any additional processing.
if (E->getCastKind() == CK_ReinterpretMemberPointer) return src;
@@ -1045,16 +1053,24 @@ pointerAuthResignMemberFunctionPointer(llvm::Constant *Src, QualType DestType,
llvm::Constant *
ItaniumCXXABI::EmitMemberPointerConversion(const CastExpr *E,
llvm::Constant *src) {
+ QualType DstType = E->getType(), SrcType = E->getSubExpr()->getType();
+
assert(E->getCastKind() == CK_DerivedToBaseMemberPointer ||
E->getCastKind() == CK_BaseToDerivedMemberPointer ||
- E->getCastKind() == CK_ReinterpretMemberPointer);
-
- QualType DstType = E->getType();
+ E->getCastKind() == CK_ReinterpretMemberPointer ||
+ (E->getCastKind() == CK_NoOp &&
+ getContext().hasSameFunctionTypeIgnoringExceptionSpec(
+ DstType->getPointeeType(), SrcType->getPointeeType())));
if (DstType->isMemberFunctionPointerType())
src = pointerAuthResignMemberFunctionPointer(
src, DstType, E->getSubExpr()->getType(), CGM);
+ // Conversion from a pointer to a noexcept member function to a pointer to a
+ // member function without noexcept doesn't require any additional processing.
+ if (E->getCastKind() == CK_NoOp)
+ return src;
+
// Under Itanium, reinterprets don't require any additional processing.
if (E->getCastKind() == CK_ReinterpretMemberPointer) return src;
diff --git a/clang/test/CodeGenCXX/ptrauth-member-function-pointer.cpp b/clang/test/CodeGenCXX/ptrauth-member-function-pointer.cpp
index 0a9ac3fa510f56..3408e7e18c3adc 100644
--- a/clang/test/CodeGenCXX/ptrauth-member-function-pointer.cpp
+++ b/clang/test/CodeGenCXX/ptrauth-member-function-pointer.cpp
@@ -1,10 +1,12 @@
-// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics -emit-llvm -std=c++11 -O1 -disable-llvm-passes -o - %s | FileCheck -check-prefixes=CHECK,NODEBUG,DARWIN %s
+// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics -emit-llvm -std=c++11 -O1 -disable-llvm-passes -o - %s | FileCheck -check-prefixes=CHECK,NODEBUG,DARWIN,CXX11 %s
+// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics -emit-llvm -std=c++17 -O1 -disable-llvm-passes -o - %s | FileCheck -check-prefixes=CHECK,NODEBUG,DARWIN,CXX17 %s
// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics -emit-llvm -std=c++11 -O1 -disable-llvm-passes -debug-info-kind=limited -o - %s | FileCheck -check-prefixes=CHECK,DARWIN %s
// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics -emit-llvm -std=c++11 -O1 -disable-llvm-passes -stack-protector 1 -o - %s | FileCheck %s -check-prefix=STACK-PROT
// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics -emit-llvm -std=c++11 -O1 -disable-llvm-passes -stack-protector 2 -o - %s | FileCheck %s -check-prefix=STACK-PROT
// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fptrauth-intrinsics -emit-llvm -std=c++11 -O1 -disable-llvm-passes -stack-protector 3 -o - %s | FileCheck %s -check-prefix=STACK-PROT
-// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics -emit-llvm -std=c++11 -O1 -disable-llvm-passes -o - %s | FileCheck -check-prefixes=CHECK,NODEBUG,ELF %s
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics -emit-llvm -std=c++11 -O1 -disable-llvm-passes -o - %s | FileCheck -check-prefixes=CHECK,NODEBUG,ELF,CXX11 %s
+// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics -emit-llvm -std=c++17 -O1 -disable-llvm-passes -o - %s | FileCheck -check-prefixes=CHECK,NODEBUG,ELF,CXX17 %s
// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics -emit-llvm -std=c++11 -O1 -disable-llvm-passes -debug-info-kind=limited -o - %s | FileCheck -check-prefixes=CHECK,ELF %s
// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics -emit-llvm -std=c++11 -O1 -disable-llvm-passes -stack-protector 1 -o - %s | FileCheck %s -check-prefix=STACK-PROT
// RUN: %clang_cc1 -triple aarch64-linux-gnu -fptrauth-calls -fptrauth-intrinsics -emit-llvm -std=c++11 -O1 -disable-llvm-passes -stack-protector 2 -o - %s | FileCheck %s -check-prefix=STACK-PROT
@@ -20,6 +22,11 @@
// CHECK: @__const._Z13testArrayInitv.c0 = private unnamed_addr constant %struct.Class0 { { i64, i64 } { i64 ptrtoint (ptr ptrauth (ptr @_ZN5Base011nonvirtual0Ev, i32 0, i64 35591) to i64), i64 0 } }, align 8
// CHECK: @__const._Z13testArrayInitv.c1 = private unnamed_addr constant %struct.Class0 { { i64, i64 } { i64 ptrtoint (ptr ptrauth (ptr @_ZN5Base08virtual1Ev_vfpthunk_, i32 0, i64 35591) to i64), i64 0 } }, align 8
+// CHECK: @_ZN22testNoexceptConversion6mfptr1E = global { i64, i64 } { i64 ptrtoint (ptr ptrauth (ptr @_ZN22testNoexceptConversion1S19nonvirtual_noexceptEv, i32 0, i64 [[DISC_NO_NOEXCEPT:.*]]) to i64), i64 0 },
+// CHECK: @_ZN22testNoexceptConversion6mfptr2E = global { i64, i64 } { i64 ptrtoint (ptr ptrauth (ptr @_ZN22testNoexceptConversion1S16virtual_noexceptEv_vfpthunk_, i32 0, i64 [[DISC_NO_NOEXCEPT]]) to i64), i64 0 },
+// CXX11: @_ZN22testNoexceptConversion15mfptr3_noexceptE = global { i64, i64 } { i64 ptrtoint (ptr ptrauth (ptr @_ZN22testNoexceptConversion1S19nonvirtual_noexceptEv, i32 0, i64 [[DISC_NO_NOEXCEPT]]) to i64), i64 0 },
+// CXX17: @_ZN22testNoexceptConversion15mfptr3_noexceptE = global { i64, i64 } { i64 ptrtoint (ptr ptrauth (ptr @_ZN22testNoexceptConversion1S19nonvirtual_noexceptEv, i32 0, i64 [[DISC_NOEXCEPT:.*]]) to i64), i64 0 },
+
// CHECK: @_ZTV5Base0 = unnamed_addr constant { [5 x ptr] } { [5 x ptr] [ptr null, ptr @_ZTI5Base0,
// CHECK-SAME: ptr ptrauth (ptr @_ZN5Base08virtual1Ev, i32 0, i64 55600, ptr getelementptr inbounds ({ [5 x ptr] }, ptr @_ZTV5Base0, i32 0, i32 0, i32 2)),
// CHECK-SAME: ptr ptrauth (ptr @_ZN5Base08virtual3Ev, i32 0, i64 53007, ptr getelementptr inbounds ({ [5 x ptr] }, ptr @_ZTV5Base0, i32 0, i32 0, i32 3)),
@@ -438,3 +445,101 @@ void testArrayInit() {
void testConvertNull() {
VariadicMethodTy0 t = (VariadicMethodTy0)(MethodTy0{});
}
+
+namespace testNoexceptConversion {
+
+// CHECK-LABEL: define internal void @__cxx_global_var_init()
+// CXX17: [[ENTRY:.*]]:
+// CHECK: %[[V0:.*]] = load { i64, i64 }, ptr @_ZN22testNoexceptConversion15mfptr0_noexceptE, align 8
+// CXX17: %[[MEMPTR_PTR:.*]] = extractvalue { i64, i64 } %[[V0]], 0
+// CXX17: %[[MEMPTR_ADJ:.*]] = extractvalue { i64, i64 } %[[V0]], 1
+// CXX17: %[[V1:.*]] = and i64 %[[MEMPTR_ADJ]], 1
+// CXX17: %[[IS_VIRTUAL_OFFSET:.*]] = icmp ne i64 %[[V1]], 0
+// CXX17: br i1 %[[IS_VIRTUAL_OFFSET]], label %[[MERGE:.*]], label %[[RESIGN:.*]]
+
+// CXX17: [[RESIGN]]:
+// CXX17: %[[V2:.*]] = inttoptr i64 %[[MEMPTR_PTR]] to ptr
+// CXX17: %[[V3:.*]] = icmp ne ptr %[[V2]], null
+// CXX17: br i1 %[[V3]], label %[[RESIGN_NONNULL:.*]], label %[[RESIGN_CONT:.*]]
+
+// CXX17: [[RESIGN_NONNULL]]:
+// CXX17: %[[V4:.*]] = ptrtoint ptr %[[V2]] to i64
+// CXX17: %[[V5:.*]] = call i64 @llvm.ptrauth.resign(i64 %[[V4]], i32 0, i64 [[DISC_NOEXCEPT]], i32 0, i64 [[DISC_NO_NOEXCEPT]])
+// CXX17: %[[V6:.*]] = inttoptr i64 %[[V5]] to ptr
+// CXX17: br label %[[RESIGN_CONT]]
+
+// CXX17: [[RESIGN_CONT]]:
+// CXX17: %[[V7:.*]] = phi ptr [ null, %[[RESIGN]] ], [ %[[V6]], %[[RESIGN_NONNULL]] ]
+// CXX17: %[[V8:.*]] = ptrtoint ptr %[[V7]] to i64
+// CXX17: %[[V9:.*]] = insertvalue { i64, i64 } %[[V0]], i64 %[[V8]], 0
+// CXX17: br label %[[MERGE]]
+
+// CXX17: [[MERGE]]:
+// CXX17: %[[V10:.*]] = phi { i64, i64 } [ %[[V0]], %[[ENTRY]] ], [ %[[V9]], %[[RESIGN_CONT]] ]
+// CXX17: store { i64, i64 } %[[V10]], ptr @_ZN22testNoexceptConversion6mfptr4E, align 8
+// CXX11: store { i64, i64 } %[[V0]], ptr @_ZN22testNoexceptConversion6mfptr4E, align 8
+
+// CHECK: define {{.*}}void @_ZN22testNoexceptConversion5test0Ev()
+// CHECK: %[[P0:.*]] = alloca { i64, i64 }, align 8
+// CHECK: store { i64, i64 } { i64 ptrtoint (ptr ptrauth (ptr @_ZN22testNoexceptConversion1S19nonvirtual_noexceptEv, i32 0, i64 [[DISC_NO_NOEXCEPT]]) to i64), i64 0 }, ptr %[[P0]], align 8,
+
+// CHECK: define {{.*}}void @_ZN22testNoexceptConversion5test1Ev()
+// CHECK: %[[P0:.*]] = alloca { i64, i64 }, align 8
+// CHECK: store { i64, i64 } { i64 ptrtoint (ptr ptrauth (ptr @_ZN22testNoexceptConversion1S16virtual_noexceptEv_vfpthunk_, i32 0, i64 [[DISC_NO_NOEXCEPT]]) to i64), i64 0 }, ptr %[[P0]], align 8,
+
+// CHECK: define {{.*}}void @_ZN22testNoexceptConversion5test2Ev()
+// CXX17: [[ENTRY:.*]]:
+// CHECK: %[[P0:.*]] = alloca { i64, i64 }, align 8
+// CHECK: %[[V0:.*]] = load { i64, i64 }, ptr @_ZN22testNoexceptConversion15mfptr0_noexceptE, align 8
+// CXX17: %[[MEMPTR_PTR:.*]] = extractvalue { i64, i64 } %[[V0]], 0
+// CXX17: %[[MEMPTR_ADJ:.*]] = extractvalue { i64, i64 } %[[V0]], 1
+// CXX17: %[[V1:.*]] = and i64 %[[MEMPTR_ADJ]], 1
+// CXX17: %[[IS_VIRTUAL_OFFSET:.*]] = icmp ne i64 %[[V1]], 0
+// CXX17: br i1 %[[IS_VIRTUAL_OFFSET]], label %[[MERGE:.*]], label %[[RESIGN:.*]]
+
+// CXX17: [[RESIGN]]:
+// CXX17: %[[V2:.*]] = inttoptr i64 %[[MEMPTR_PTR]] to ptr
+// CXX17: %[[V3:.*]] = icmp ne ptr %[[V2]], null
+// CXX17: br i1 %[[V3]], label %[[RESIGN_NONNULL:.*]], label %[[RESIGN_CONT:.*]]
+
+// CXX17: [[RESIGN_NONNULL]]:
+// CXX17: %[[V4:.*]] = ptrtoint ptr %[[V2]] to i64
+// CXX17: %[[V5:.*]] = call i64 @llvm.ptrauth.resign(i64 %[[V4]], i32 0, i64 [[DISC_NOEXCEPT]], i32 0, i64 [[DISC_NO_NOEXCEPT]])
+// CXX17: %[[V6:.*]] = inttoptr i64 %[[V5]] to ptr
+// CXX17: br label %[[RESIGN_CONT]]
+
+// CXX17: [[RESIGN_CONT]]:
+// CXX17: %[[V7:.*]] = phi ptr [ null, %[[RESIGN]] ], [ %[[V6]], %[[RESIGN_NONNULL]] ]
+// CXX17: %[[V8:.*]] = ptrtoint ptr %[[V7]] to i64
+// CXX17: %[[V9:.*]] = insertvalue { i64, i64 } %[[V0]], i64 %[[V8]], 0
+// CXX17: br label %[[MERGE]]
+
+// CXX17: [[MERGE]]:
+// CXX17: %[[V10:.*]] = phi { i64, i64 } [ %[[V0]], %[[ENTRY]] ], [ %[[V9]], %[[RESIGN_CONT]] ]
+// CXX11: store { i64, i64 } %[[V0]], ptr %[[P0]], align 8
+// CXX17: store { i64, i64 } %[[V10]], ptr %[[P0]], align 8
+
+struct S {
+ void nonvirtual_noexcept() noexcept;
+ virtual void virtual_noexcept() noexcept;
+};
+
+void (S::*mfptr0_noexcept)() noexcept;
+void (S::*mfptr1)() = &S::nonvirtual_noexcept;
+void (S::*mfptr2)() = &S::virtual_noexcept;
+void (S::*mfptr3_noexcept)() noexcept = &S::nonvirtual_noexcept;
+void (S::*mfptr4)() = mfptr0_noexcept;
+
+void test0() {
+ void (S::*p0)() = &S::nonvirtual_noexcept;
+}
+
+void test1() {
+ void (S::*p0)() = &S::virtual_noexcept;
+}
+
+void test2() {
+ void (S::*p0)() = mfptr0_noexcept;
+}
+
+}
More information about the cfe-commits
mailing list