-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[PAC] Ignore noexcept on function type when computing discriminator of member function pointers #109056
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-clang-codegen @llvm/pr-subscribers-clang Author: Akira Hatanaka (ahatanak) ChangesFixes #106487. Full diff: https://github.com/llvm/llvm-project/pull/109056.diff 3 Files Affected:
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;
+}
+
+}
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good to me, thanks!
LGTM |
clang/lib/CodeGen/CGExprScalar.cpp
Outdated
if (CGF.CGM.getCodeGenOpts().PointerAuth.CXXMemberFunctionPointers && | ||
CE->getType()->isMemberFunctionPointerType()) | ||
V = CGF.CGM.getCXXABI().EmitMemberPointerConversion(CGF, CE, V); | ||
return V; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we not need similar logic here when casting function pointer types when function pointer type diversity is enabled? Does Sema not use CK_NoOp
for those? Maybe we should do the same for member pointer conversions and make sure there's a better cast kind to use.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sema does use CK_NoOp
for those, but we don't need to re-sign function pointers because the presence of noexcept
on a function type doesn't change the discriminator. The function that encodes the function type (encodeTypeForFunctionPointerAuth
) encodes the parameter and return types, but ignores noexcept
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, but that's coincidental, right? The language doesn't semantically guarantee that that conversion is a no-op, it just happens to be under normal conditions, even with function pointer type diversity enabled.
What cast kind do we use if you cast a function pointer to a completely different type?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Depending on the kind of casts in the source code, CStyleCastExpr
or CXXReinterpretCastExpr
(or possibly another cast kind) is used when casting to a completely different function pointer type.
But those are explicit casts. I'm not sure there's another cast operation other than CK_NoOp
in clang/AST/OperationKinds.def
that we can use for that purpose.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I mean the CastKind
, not the expression class. We generally treat the conversion side of CastExpr
s uniformly in CodeGen (although there are some important exceptions).
And we can add new CastKind
s if there isn't a good one that covers the operation. Adding a new CastKind
is generally much more straightforward than adding a new expression class (which we definitely don't need to do here).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think there's a CastKind
we can use in clang/AST/OperationKinds.def
. We'll have to define a new one if we are going to stop using NoOp
.
The new cast kinds are needed to distinguish between no-op conversions and conversions from pointers to noexcept functions to pointers to functions without noexcept as the latter can cause function pointers to be re-signed on arm64e. See llvm#109056 for background.
The new cast kinds are needed to distinguish between no-op conversions and conversions from pointers to noexcept functions to pointers to functions without noexcept as the latter can cause function pointers to be re-signed on arm64e. See llvm#109056 for background.
The new cast kinds are needed to distinguish between no-op conversions and conversions from pointers to noexcept functions to pointers to functions without noexcept as the latter can cause function pointers to be re-signed on arm64e. See llvm#109056 for background.
clang/lib/CodeGen/ItaniumCXXABI.cpp
Outdated
@@ -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(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SrcType
is unused in non-assert builds.
This change isn't needed anymore as it was decided that |
I meant to close #110048. |
Looks like ignoring |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
member function pointers This fixes a bug where a member function pointer signed using a function type with noexcept as the discriminator was being authenticated using a function type without noexcept. Fixes llvm#106487.
52ef0c6
to
ca0c74f
Compare
Fixes #106487.