From e1095c32fc06ebdf25c20de2a0544f936a8cf77b Mon Sep 17 00:00:00 2001 From: Jakub Chlanda Date: Fri, 10 Jul 2026 12:01:47 +0000 Subject: [PATCH 1/8] [PAC] Include discriminator in `FnAbi`, add `llvm.ptrauth.resign` This patch introduces the following: * Extends `FnAbi` (`callconv`) with a `ptrauth_type_discriminator` field. This field is only used when emitting pointer authentication call bundles. It is stored in `FnAbi` because the call site is not guaranteed to have access to an `Instance`, so the discriminator cannot always be computed on demand. * Adds support for `llvm.ptrauth.resign`. This intrinsic will be used when support for semantic transmute is added. * Performs a minor API redesign as groundwork for allowing call sites to modify schemas in place. --- compiler/rustc_codegen_gcc/src/builder.rs | 11 +++++++ compiler/rustc_codegen_gcc/src/common.rs | 2 +- compiler/rustc_codegen_gcc/src/context.rs | 2 +- compiler/rustc_codegen_gcc/src/int.rs | 1 + compiler/rustc_codegen_llvm/src/builder.rs | 32 +++++++++++++++++-- compiler/rustc_codegen_llvm/src/common.rs | 23 +++++++------ compiler/rustc_codegen_llvm/src/context.rs | 4 +-- .../rustc_codegen_ssa/src/traits/builder.rs | 9 ++++++ .../rustc_codegen_ssa/src/traits/consts.rs | 2 +- compiler/rustc_codegen_ssa/src/traits/misc.rs | 2 +- compiler/rustc_session/src/session.rs | 25 ++++++++++++--- compiler/rustc_target/src/callconv/mod.rs | 8 +++-- compiler/rustc_ty_utils/src/abi.rs | 6 ++++ tests/ui/abi/c-zst.aarch64-darwin.stderr | 1 + tests/ui/abi/c-zst.powerpc-linux.stderr | 1 + tests/ui/abi/c-zst.s390x-linux.stderr | 1 + tests/ui/abi/c-zst.sparc-linux.stderr | 1 + tests/ui/abi/c-zst.sparc-none.stderr | 1 + tests/ui/abi/c-zst.sparc64-linux.stderr | 1 + tests/ui/abi/c-zst.x86_64-linux.stderr | 1 + .../ui/abi/c-zst.x86_64-pc-windows-gnu.stderr | 1 + tests/ui/abi/debug.generic.stderr | 12 +++++++ tests/ui/abi/debug.loongarch64.stderr | 12 +++++++ tests/ui/abi/debug.riscv64.stderr | 12 +++++++ .../x86-64-sysv64-arg-ext.apple.stderr | 6 ++++ .../x86-64-sysv64-arg-ext.other.stderr | 6 ++++ tests/ui/abi/pass-indirectly-attr.stderr | 2 ++ tests/ui/abi/sysv64-zst.stderr | 1 + .../pass-by-value-abi.aarch64.stderr | 1 + .../c-variadic/pass-by-value-abi.win.stderr | 1 + .../pass-by-value-abi.x86_64.stderr | 3 ++ 31 files changed, 167 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs index a1eab8f448990..de221ee22f2a0 100644 --- a/compiler/rustc_codegen_gcc/src/builder.rs +++ b/compiler/rustc_codegen_gcc/src/builder.rs @@ -1943,6 +1943,17 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> { fn fptosi_sat(&mut self, val: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> { self.fptoint_sat(true, val, dest_ty) } + + fn ptrauth_resign( + &mut self, + _value: Self::Value, + _old_key: u32, + _old_discriminator: u64, + _new_key: u32, + _new_discriminator: u64, + ) -> Self::Value { + bug!("Resigning of pointers not implemented"); + } } impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index 21d92c6cc2936..42b92f55e0e80 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -332,7 +332,7 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> { cv: Scalar, layout: abi::Scalar, ty: Type<'gcc>, - _schema: Option<&PointerAuthSchema>, + _ptrauth_schema: Option, ) -> RValue<'gcc> { let bitsize = if layout.is_bool() { 1 } else { layout.size(self).bits() }; match cv { diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs index 5f342e8b2dc33..16b3e84bfef66 100644 --- a/compiler/rustc_codegen_gcc/src/context.rs +++ b/compiler/rustc_codegen_gcc/src/context.rs @@ -455,7 +455,7 @@ impl<'gcc, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'gcc, 'tcx> { fn get_fn_addr( &self, instance: Instance<'tcx>, - _pointer_auth_schema: Option<&PointerAuthSchema>, + _ptrauth_schema: Option, ) -> RValue<'gcc> { let func_name = self.tcx.symbol_name(instance).name; diff --git a/compiler/rustc_codegen_gcc/src/int.rs b/compiler/rustc_codegen_gcc/src/int.rs index 4e4b911666143..69049ada616b0 100644 --- a/compiler/rustc_codegen_gcc/src/int.rs +++ b/compiler/rustc_codegen_gcc/src/int.rs @@ -400,6 +400,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { fixed_count: 3, conv: CanonAbi::C, can_unwind: false, + ptrauth_discriminator: 0, }; fn_abi.adjust_for_foreign_abi(self.cx, ExternAbi::C { unwind: false }); diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index dc89414940620..670e94ba24128 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -1567,6 +1567,30 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { let cold_inline = llvm::AttributeKind::Cold.create_attr(self.llcx); attributes::apply_to_callsite(llret, llvm::AttributePlace::Function, &[cold_inline]); } + + fn ptrauth_resign( + &mut self, + value: &'ll Value, + old_key: u32, + old_discriminator: u64, + new_key: u32, + new_discriminator: u64, + ) -> &'ll Value { + let ptr_as_int = self.ptrtoint(value, self.type_i64()); + let resigned_int = self.call_intrinsic( + "llvm.ptrauth.resign", + &[], + &[ + ptr_as_int, + self.const_i32(old_key as i32), + self.const_i64(old_discriminator as i64), + self.const_i32(new_key as i32), + self.const_i64(new_discriminator as i64), + ], + ); + + self.inttoptr(resigned_int, self.val_ty(value)) + } } impl<'ll> StaticBuilderMethods for Builder<'_, 'll, '_> { @@ -2213,8 +2237,12 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { // bundles. // Once this is resolved, we should analyze each call and skip direct calls. See the // discussion in the rust-lang issue: - let key: u32 = 0; - let discriminator: u64 = 0; + + let key: u32 = self.sess().pointer_authentication_fn_ptr_key().unwrap() as u32; + // If sess().pointer_authentication_fn_ptr_type_discrimination() is true, this contains + // the function pointer type discriminator; otherwise, it is 0. + let discriminator = fn_abi?.ptrauth_discriminator; + Some(llvm::OperandBundleBox::new( "ptrauth", &[self.const_u32(key), self.const_u64(discriminator)], diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index 7a05bf718663c..c5c943002dfdc 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -30,11 +30,9 @@ pub(crate) fn maybe_sign_fn_ptr<'ll, 'tcx>( cx: &CodegenCx<'ll, '_>, instance: Instance<'tcx>, llfn: &'ll llvm::Value, - schema: &PointerAuthSchema, + ptrauth_schema: PointerAuthSchema, ) -> &'ll llvm::Value { - if cx.tcx.sess.pointer_authentication_functions().is_none() { - return llfn; - } + assert!(cx.tcx.sess.pointer_authentication_functions().is_some()); // Only free functions or methods let def_id = instance.def_id(); @@ -54,7 +52,7 @@ pub(crate) fn maybe_sign_fn_ptr<'ll, 'tcx>( return llfn; } - let addr_diversity = match schema.is_address_discriminated { + let addr_diversity = match ptrauth_schema.is_address_discriminated { PointerAuthAddressDiscriminator::HardwareAddress(true) => Some(llfn), PointerAuthAddressDiscriminator::HardwareAddress(false) => None, PointerAuthAddressDiscriminator::Synthetic(val) => { @@ -63,7 +61,12 @@ pub(crate) fn maybe_sign_fn_ptr<'ll, 'tcx>( Some(unsafe { llvm::LLVMConstIntToPtr(llval, llty) }) } }; - const_ptr_auth(llfn, schema.key as u32, schema.constant_discriminator as u64, addr_diversity) + const_ptr_auth( + llfn, + ptrauth_schema.key as u32, + ptrauth_schema.constant_discriminator as u64, + addr_diversity, + ) } /* @@ -179,11 +182,11 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { &self, global_alloc: GlobalAlloc<'tcx>, need_symbol_name: bool, - schema: Option<&PointerAuthSchema>, + ptrauth_schema: Option, ) -> Result<&'ll Value, u64> { let alloc = match global_alloc { GlobalAlloc::Function { instance, .. } => { - return Ok(self.get_fn_addr(instance, schema)); + return Ok(self.get_fn_addr(instance, ptrauth_schema)); } GlobalAlloc::Static(def_id) => { assert!(self.tcx.is_static(def_id)); @@ -405,7 +408,7 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { cv: Scalar, layout: abi::Scalar, llty: &'ll Type, - schema: Option<&PointerAuthSchema>, + ptrauth_schema: Option, ) -> &'ll Value { let bitsize = if layout.is_bool() { 1 } else { layout.size(self).bits() }; match cv { @@ -422,7 +425,7 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { let (prov, offset) = ptr.prov_and_relative_offset(); let global_alloc = self.tcx.global_alloc(prov.alloc_id()); let base_addr_space = global_alloc.address_space(self); - let base_addr = match self.alloc_to_backend(global_alloc, false, schema) { + let base_addr = match self.alloc_to_backend(global_alloc, false, ptrauth_schema) { Ok(base_addr) => base_addr, Err(base_addr) => { let val = base_addr.wrapping_add(offset.bytes()); diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 0ce3bfe07c413..2e0db574e8d62 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -987,7 +987,7 @@ impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { fn get_fn_addr( &self, instance: Instance<'tcx>, - pointer_auth_schema: Option<&PointerAuthSchema>, + ptrauth_schema: Option, ) -> &'ll Value { // When pointer authentication metadata is provided, `get_fn_addr` will // attempt to sign the pointer using LLVM's `ConstPtrAuth` constant @@ -1002,7 +1002,7 @@ impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { // , and comment in // builder's `ptrauth_operand_bundle`. let llfn = get_fn(self, instance); - match pointer_auth_schema { + match ptrauth_schema { Some(schema) => common::maybe_sign_fn_ptr(self, instance, llfn, schema), None => llfn, } diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 59e1f6e9d0098..c185094b19c3c 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -687,4 +687,13 @@ pub trait BuilderMethods<'a, 'tcx>: fn zext(&mut self, val: Self::Value, dest_ty: Self::Type) -> Self::Value; fn apply_attrs_to_cleanup_callsite(&mut self, llret: Self::Value); + + fn ptrauth_resign( + &mut self, + value: Self::Value, + old_key: u32, + old_discriminator: u64, + new_key: u32, + new_discriminator: u64, + ) -> Self::Value; } diff --git a/compiler/rustc_codegen_ssa/src/traits/consts.rs b/compiler/rustc_codegen_ssa/src/traits/consts.rs index b4eba38d39c19..b45b5667be6c9 100644 --- a/compiler/rustc_codegen_ssa/src/traits/consts.rs +++ b/compiler/rustc_codegen_ssa/src/traits/consts.rs @@ -47,7 +47,7 @@ pub trait ConstCodegenMethods: BackendTypes { cv: Scalar, layout: abi::Scalar, llty: Self::Type, - schema: Option<&PointerAuthSchema>, + ptrauth_schema: Option, ) -> Self::Value; fn const_ptr_byte_offset(&self, val: Self::Value, offset: abi::Size) -> Self::Value; diff --git a/compiler/rustc_codegen_ssa/src/traits/misc.rs b/compiler/rustc_codegen_ssa/src/traits/misc.rs index add7128a2974b..3d1a931a12e83 100644 --- a/compiler/rustc_codegen_ssa/src/traits/misc.rs +++ b/compiler/rustc_codegen_ssa/src/traits/misc.rs @@ -22,7 +22,7 @@ pub trait MiscCodegenMethods<'tcx>: BackendTypes { fn get_fn_addr( &self, instance: Instance<'tcx>, - pointer_auth_schema: Option<&PointerAuthSchema>, + ptrauth_schema: Option, ) -> Self::Value; fn eh_personality(&self) -> Self::Function; fn sess(&self) -> &Session; diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index f068aaa584dce..1c39124b995e7 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -95,6 +95,7 @@ pub enum PointerAuthARM8_3Key { } /// Forms of extra discrimination. +#[derive(Clone, Debug, PartialEq)] pub enum PointerAuthDiscrimination { /// No additional discrimination. None, @@ -107,6 +108,7 @@ pub enum PointerAuthDiscrimination { } /// Types of address discrimination. +#[derive(Clone, Debug)] pub enum PointerAuthAddressDiscriminator { /// Enable/disable hardware address discrimination. HardwareAddress(bool), @@ -115,6 +117,7 @@ pub enum PointerAuthAddressDiscriminator { Synthetic(u64), } +#[derive(Clone, Debug)] pub struct PointerAuthSchema { pub is_address_discriminated: PointerAuthAddressDiscriminator, pub discrimination_kind: PointerAuthDiscrimination, @@ -1268,12 +1271,26 @@ impl Session { self.pointer_auth_config.is_some() } - pub fn pointer_authentication_functions(&self) -> Option<&PointerAuthSchema> { - self.pointer_auth_config.as_ref().and_then(|cfg| cfg.function_pointers.as_ref()) + pub fn pointer_authentication_functions(&self) -> Option { + self.pointer_auth_config.as_ref().and_then(|cfg| cfg.function_pointers.clone()) } - pub fn pointer_authentication_init_fini(&self) -> Option<&PointerAuthSchema> { - self.pointer_auth_config.as_ref().and_then(|cfg| cfg.init_fini.as_ref()) + pub fn pointer_authentication_init_fini(&self) -> Option { + self.pointer_auth_config.as_ref().and_then(|cfg| cfg.init_fini.clone()) + } + + pub fn pointer_authentication_fn_ptr_type_discrimination(&self) -> bool { + self.pointer_auth_config + .as_ref() + .and_then(|cfg| cfg.function_pointers.as_ref()) + .is_some_and(|schema| schema.discrimination_kind == PointerAuthDiscrimination::Type) + } + + pub fn pointer_authentication_fn_ptr_key(&self) -> Option { + self.pointer_auth_config + .as_ref() + .and_then(|cfg| cfg.function_pointers.as_ref()) + .map(|schema| schema.key) } } diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index edc23b6c50b45..893ac55c8f50e 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -700,12 +700,15 @@ pub struct FnAbi<'a, Ty> { pub conv: CanonAbi, /// Indicates if an unwind may happen across a call to this function. pub can_unwind: bool, + /// Computed type discriminator for pointer authentication purpose. + pub ptrauth_discriminator: u64, } // Needs to be a custom impl because of the bounds on the `TyAndLayout` debug impl. impl<'a, Ty: fmt::Display> fmt::Debug for FnAbi<'a, Ty> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let FnAbi { args, ret, c_variadic, fixed_count, conv, can_unwind } = self; + let FnAbi { args, ret, c_variadic, fixed_count, conv, can_unwind, ptrauth_discriminator } = + self; f.debug_struct("FnAbi") .field("args", args) .field("ret", ret) @@ -713,6 +716,7 @@ impl<'a, Ty: fmt::Display> fmt::Debug for FnAbi<'a, Ty> { .field("fixed_count", fixed_count) .field("conv", conv) .field("can_unwind", can_unwind) + .field("ptrauth_discriminator", ptrauth_discriminator) .finish() } } @@ -1038,6 +1042,6 @@ mod size_asserts { use super::*; // tidy-alphabetical-start static_assert_size!(ArgAbi<'_, usize>, 64); - static_assert_size!(FnAbi<'_, usize>, 88); + static_assert_size!(FnAbi<'_, usize>, 96); // tidy-alphabetical-end } diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 448167ff90874..8c8453e48a273 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -6,6 +6,7 @@ use rustc_attr_ir::find_attr; use rustc_attr_ir::lang_items::LangItem; use rustc_hir as hir; use rustc_middle::middle::deduced_param_attrs::DeducedParamAttrs; +use rustc_middle::ptrauth::ptrauth_compute_fn_ptr_type_discriminator_for; use rustc_middle::query::Providers; use rustc_middle::ty::layout::{ FnAbiError, HasTyCtxt, HasTypingEnv, LayoutCx, LayoutOf, TyAndLayout, fn_can_unwind, @@ -613,6 +614,11 @@ fn fn_abi_new_uncached<'tcx>( determined_fn_def_id, sig.abi(), ), + ptrauth_discriminator: if tcx.sess.pointer_authentication_fn_ptr_type_discrimination() { + ptrauth_compute_fn_ptr_type_discriminator_for(tcx, sig).unwrap_or(0).into() + } else { + 0 + }, }; fn_abi_adjust_for_abi(cx, &mut fn_abi, sig.abi()); debug!("fn_abi_new_uncached = {:?}", fn_abi); diff --git a/tests/ui/abi/c-zst.aarch64-darwin.stderr b/tests/ui/abi/c-zst.aarch64-darwin.stderr index 2ed9ffdf791f6..3c4c88ba2b19f 100644 --- a/tests/ui/abi/c-zst.aarch64-darwin.stderr +++ b/tests/ui/abi/c-zst.aarch64-darwin.stderr @@ -59,6 +59,7 @@ error: fn_abi_of(pass_zst) = FnAbi { fixed_count: 1, conv: C, can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/c-zst.rs:67:1 | diff --git a/tests/ui/abi/c-zst.powerpc-linux.stderr b/tests/ui/abi/c-zst.powerpc-linux.stderr index e5cad2199491b..d0a5bab9e8073 100644 --- a/tests/ui/abi/c-zst.powerpc-linux.stderr +++ b/tests/ui/abi/c-zst.powerpc-linux.stderr @@ -71,6 +71,7 @@ error: fn_abi_of(pass_zst) = FnAbi { fixed_count: 1, conv: C, can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/c-zst.rs:67:1 | diff --git a/tests/ui/abi/c-zst.s390x-linux.stderr b/tests/ui/abi/c-zst.s390x-linux.stderr index e5cad2199491b..d0a5bab9e8073 100644 --- a/tests/ui/abi/c-zst.s390x-linux.stderr +++ b/tests/ui/abi/c-zst.s390x-linux.stderr @@ -71,6 +71,7 @@ error: fn_abi_of(pass_zst) = FnAbi { fixed_count: 1, conv: C, can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/c-zst.rs:67:1 | diff --git a/tests/ui/abi/c-zst.sparc-linux.stderr b/tests/ui/abi/c-zst.sparc-linux.stderr index e5cad2199491b..715fae66f3c93 100644 --- a/tests/ui/abi/c-zst.sparc-linux.stderr +++ b/tests/ui/abi/c-zst.sparc-linux.stderr @@ -71,6 +71,7 @@ error: fn_abi_of(pass_zst) = FnAbi { fixed_count: 1, conv: C, can_unwind: false, + ptrauth_discriminator: None, } --> $DIR/c-zst.rs:67:1 | diff --git a/tests/ui/abi/c-zst.sparc-none.stderr b/tests/ui/abi/c-zst.sparc-none.stderr index e5cad2199491b..715fae66f3c93 100644 --- a/tests/ui/abi/c-zst.sparc-none.stderr +++ b/tests/ui/abi/c-zst.sparc-none.stderr @@ -71,6 +71,7 @@ error: fn_abi_of(pass_zst) = FnAbi { fixed_count: 1, conv: C, can_unwind: false, + ptrauth_discriminator: None, } --> $DIR/c-zst.rs:67:1 | diff --git a/tests/ui/abi/c-zst.sparc64-linux.stderr b/tests/ui/abi/c-zst.sparc64-linux.stderr index e5cad2199491b..d0a5bab9e8073 100644 --- a/tests/ui/abi/c-zst.sparc64-linux.stderr +++ b/tests/ui/abi/c-zst.sparc64-linux.stderr @@ -71,6 +71,7 @@ error: fn_abi_of(pass_zst) = FnAbi { fixed_count: 1, conv: C, can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/c-zst.rs:67:1 | diff --git a/tests/ui/abi/c-zst.x86_64-linux.stderr b/tests/ui/abi/c-zst.x86_64-linux.stderr index 2ed9ffdf791f6..3c4c88ba2b19f 100644 --- a/tests/ui/abi/c-zst.x86_64-linux.stderr +++ b/tests/ui/abi/c-zst.x86_64-linux.stderr @@ -59,6 +59,7 @@ error: fn_abi_of(pass_zst) = FnAbi { fixed_count: 1, conv: C, can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/c-zst.rs:67:1 | diff --git a/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr b/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr index e5cad2199491b..d0a5bab9e8073 100644 --- a/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr +++ b/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr @@ -71,6 +71,7 @@ error: fn_abi_of(pass_zst) = FnAbi { fixed_count: 1, conv: C, can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/c-zst.rs:67:1 | diff --git a/tests/ui/abi/debug.generic.stderr b/tests/ui/abi/debug.generic.stderr index 1793674fa462a..f71e639b16f4f 100644 --- a/tests/ui/abi/debug.generic.stderr +++ b/tests/ui/abi/debug.generic.stderr @@ -106,6 +106,7 @@ error: fn_abi_of(test) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } --> $DIR/debug.rs:31:1 | @@ -187,6 +188,7 @@ error: fn_abi_of(TestFnPtr) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } --> $DIR/debug.rs:37:1 | @@ -258,6 +260,7 @@ error: fn_abi_of(test_generic) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } --> $DIR/debug.rs:40:1 | @@ -336,6 +339,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } right ABI = FnAbi { args: [ @@ -402,6 +406,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } --> $DIR/debug.rs:59:1 | @@ -482,6 +487,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } right ABI = FnAbi { args: [ @@ -556,6 +562,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } --> $DIR/debug.rs:62:1 | @@ -628,6 +635,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } right ABI = FnAbi { args: [ @@ -694,6 +702,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } --> $DIR/debug.rs:65:1 | @@ -766,6 +775,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } right ABI = FnAbi { args: [ @@ -832,6 +842,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } --> $DIR/debug.rs:69:1 | @@ -926,6 +937,7 @@ error: fn_abi_of(assoc_test) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } --> $DIR/debug.rs:52:5 | diff --git a/tests/ui/abi/debug.loongarch64.stderr b/tests/ui/abi/debug.loongarch64.stderr index 29ec7846101f1..f3bd161b301b5 100644 --- a/tests/ui/abi/debug.loongarch64.stderr +++ b/tests/ui/abi/debug.loongarch64.stderr @@ -106,6 +106,7 @@ error: fn_abi_of(test) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } --> $DIR/debug.rs:31:1 | @@ -187,6 +188,7 @@ error: fn_abi_of(TestFnPtr) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } --> $DIR/debug.rs:37:1 | @@ -258,6 +260,7 @@ error: fn_abi_of(test_generic) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } --> $DIR/debug.rs:40:1 | @@ -336,6 +339,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } right ABI = FnAbi { args: [ @@ -402,6 +406,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } --> $DIR/debug.rs:59:1 | @@ -482,6 +487,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } right ABI = FnAbi { args: [ @@ -556,6 +562,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } --> $DIR/debug.rs:62:1 | @@ -628,6 +635,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } right ABI = FnAbi { args: [ @@ -694,6 +702,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } --> $DIR/debug.rs:65:1 | @@ -766,6 +775,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } right ABI = FnAbi { args: [ @@ -832,6 +842,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } --> $DIR/debug.rs:69:1 | @@ -926,6 +937,7 @@ error: fn_abi_of(assoc_test) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } --> $DIR/debug.rs:52:5 | diff --git a/tests/ui/abi/debug.riscv64.stderr b/tests/ui/abi/debug.riscv64.stderr index 29ec7846101f1..f3bd161b301b5 100644 --- a/tests/ui/abi/debug.riscv64.stderr +++ b/tests/ui/abi/debug.riscv64.stderr @@ -106,6 +106,7 @@ error: fn_abi_of(test) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } --> $DIR/debug.rs:31:1 | @@ -187,6 +188,7 @@ error: fn_abi_of(TestFnPtr) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } --> $DIR/debug.rs:37:1 | @@ -258,6 +260,7 @@ error: fn_abi_of(test_generic) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } --> $DIR/debug.rs:40:1 | @@ -336,6 +339,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } right ABI = FnAbi { args: [ @@ -402,6 +406,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } --> $DIR/debug.rs:59:1 | @@ -482,6 +487,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } right ABI = FnAbi { args: [ @@ -556,6 +562,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } --> $DIR/debug.rs:62:1 | @@ -628,6 +635,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } right ABI = FnAbi { args: [ @@ -694,6 +702,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } --> $DIR/debug.rs:65:1 | @@ -766,6 +775,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } right ABI = FnAbi { args: [ @@ -832,6 +842,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } --> $DIR/debug.rs:69:1 | @@ -926,6 +937,7 @@ error: fn_abi_of(assoc_test) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, + ptrauth_discriminator: 0, } --> $DIR/debug.rs:52:5 | diff --git a/tests/ui/abi/numbers-arithmetic/x86-64-sysv64-arg-ext.apple.stderr b/tests/ui/abi/numbers-arithmetic/x86-64-sysv64-arg-ext.apple.stderr index 65818feab4297..927594534d9b8 100644 --- a/tests/ui/abi/numbers-arithmetic/x86-64-sysv64-arg-ext.apple.stderr +++ b/tests/ui/abi/numbers-arithmetic/x86-64-sysv64-arg-ext.apple.stderr @@ -69,6 +69,7 @@ error: fn_abi_of(i8) = FnAbi { SysV64, ), can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/x86-64-sysv64-arg-ext.rs:13:1 | @@ -146,6 +147,7 @@ error: fn_abi_of(u8) = FnAbi { SysV64, ), can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/x86-64-sysv64-arg-ext.rs:19:1 | @@ -223,6 +225,7 @@ error: fn_abi_of(i16) = FnAbi { SysV64, ), can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/x86-64-sysv64-arg-ext.rs:25:1 | @@ -300,6 +303,7 @@ error: fn_abi_of(u16) = FnAbi { SysV64, ), can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/x86-64-sysv64-arg-ext.rs:31:1 | @@ -377,6 +381,7 @@ error: fn_abi_of(i32) = FnAbi { SysV64, ), can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/x86-64-sysv64-arg-ext.rs:37:1 | @@ -454,6 +459,7 @@ error: fn_abi_of(u32) = FnAbi { SysV64, ), can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/x86-64-sysv64-arg-ext.rs:43:1 | diff --git a/tests/ui/abi/numbers-arithmetic/x86-64-sysv64-arg-ext.other.stderr b/tests/ui/abi/numbers-arithmetic/x86-64-sysv64-arg-ext.other.stderr index cbe389c42d40a..113ad20e16bc4 100644 --- a/tests/ui/abi/numbers-arithmetic/x86-64-sysv64-arg-ext.other.stderr +++ b/tests/ui/abi/numbers-arithmetic/x86-64-sysv64-arg-ext.other.stderr @@ -69,6 +69,7 @@ error: fn_abi_of(i8) = FnAbi { SysV64, ), can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/x86-64-sysv64-arg-ext.rs:13:1 | @@ -146,6 +147,7 @@ error: fn_abi_of(u8) = FnAbi { SysV64, ), can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/x86-64-sysv64-arg-ext.rs:19:1 | @@ -223,6 +225,7 @@ error: fn_abi_of(i16) = FnAbi { SysV64, ), can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/x86-64-sysv64-arg-ext.rs:25:1 | @@ -300,6 +303,7 @@ error: fn_abi_of(u16) = FnAbi { SysV64, ), can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/x86-64-sysv64-arg-ext.rs:31:1 | @@ -377,6 +381,7 @@ error: fn_abi_of(i32) = FnAbi { SysV64, ), can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/x86-64-sysv64-arg-ext.rs:37:1 | @@ -454,6 +459,7 @@ error: fn_abi_of(u32) = FnAbi { SysV64, ), can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/x86-64-sysv64-arg-ext.rs:43:1 | diff --git a/tests/ui/abi/pass-indirectly-attr.stderr b/tests/ui/abi/pass-indirectly-attr.stderr index 5821e6279bb85..75504c8546498 100644 --- a/tests/ui/abi/pass-indirectly-attr.stderr +++ b/tests/ui/abi/pass-indirectly-attr.stderr @@ -84,6 +84,7 @@ error: fn_abi_of(extern_c) = FnAbi { fixed_count: 1, conv: C, can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/pass-indirectly-attr.rs:20:1 | @@ -175,6 +176,7 @@ error: fn_abi_of(extern_rust) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/pass-indirectly-attr.rs:27:1 | diff --git a/tests/ui/abi/sysv64-zst.stderr b/tests/ui/abi/sysv64-zst.stderr index 82d3793c35328..ed8fe5b83fe7c 100644 --- a/tests/ui/abi/sysv64-zst.stderr +++ b/tests/ui/abi/sysv64-zst.stderr @@ -61,6 +61,7 @@ error: fn_abi_of(pass_zst) = FnAbi { SysV64, ), can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/sysv64-zst.rs:8:1 | diff --git a/tests/ui/c-variadic/pass-by-value-abi.aarch64.stderr b/tests/ui/c-variadic/pass-by-value-abi.aarch64.stderr index c9e77ac941901..f9dc652b53440 100644 --- a/tests/ui/c-variadic/pass-by-value-abi.aarch64.stderr +++ b/tests/ui/c-variadic/pass-by-value-abi.aarch64.stderr @@ -71,6 +71,7 @@ error: fn_abi_of(take_va_list) = FnAbi { fixed_count: 1, conv: C, can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/pass-by-value-abi.rs:27:1 | diff --git a/tests/ui/c-variadic/pass-by-value-abi.win.stderr b/tests/ui/c-variadic/pass-by-value-abi.win.stderr index d5da912a9b89a..150a9262b0f88 100644 --- a/tests/ui/c-variadic/pass-by-value-abi.win.stderr +++ b/tests/ui/c-variadic/pass-by-value-abi.win.stderr @@ -66,6 +66,7 @@ error: fn_abi_of(take_va_list) = FnAbi { fixed_count: 1, conv: C, can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/pass-by-value-abi.rs:27:1 | diff --git a/tests/ui/c-variadic/pass-by-value-abi.x86_64.stderr b/tests/ui/c-variadic/pass-by-value-abi.x86_64.stderr index 04320a5312361..7471991866eef 100644 --- a/tests/ui/c-variadic/pass-by-value-abi.x86_64.stderr +++ b/tests/ui/c-variadic/pass-by-value-abi.x86_64.stderr @@ -71,6 +71,7 @@ error: fn_abi_of(take_va_list) = FnAbi { fixed_count: 1, conv: C, can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/pass-by-value-abi.rs:27:1 | @@ -152,6 +153,7 @@ error: fn_abi_of(take_va_list_sysv64) = FnAbi { SysV64, ), can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/pass-by-value-abi.rs:37:1 | @@ -233,6 +235,7 @@ error: fn_abi_of(take_va_list_win64) = FnAbi { Win64, ), can_unwind: false, + ptrauth_discriminator: 0, } --> $DIR/pass-by-value-abi.rs:44:1 | From 652847ac7093f38ae9d5d9447b44405c557e1f39 Mon Sep 17 00:00:00 2001 From: Jakub Chlanda Date: Thu, 20 Aug 2026 06:47:34 +0000 Subject: [PATCH 2/8] [PAC] Use Option in FnAbi's discriminator field --- compiler/rustc_codegen_gcc/src/int.rs | 2 +- compiler/rustc_codegen_llvm/src/builder.rs | 7 +++--- compiler/rustc_target/src/callconv/mod.rs | 4 ++-- compiler/rustc_ty_utils/src/abi.rs | 4 ++-- tests/ui/abi/c-zst.aarch64-darwin.stderr | 2 +- tests/ui/abi/c-zst.powerpc-linux.stderr | 2 +- tests/ui/abi/c-zst.s390x-linux.stderr | 2 +- tests/ui/abi/c-zst.sparc64-linux.stderr | 2 +- tests/ui/abi/c-zst.x86_64-linux.stderr | 2 +- .../ui/abi/c-zst.x86_64-pc-windows-gnu.stderr | 2 +- tests/ui/abi/debug.generic.stderr | 24 +++++++++---------- tests/ui/abi/debug.loongarch64.stderr | 24 +++++++++---------- tests/ui/abi/debug.riscv64.stderr | 24 +++++++++---------- .../x86-64-sysv64-arg-ext.apple.stderr | 12 +++++----- .../x86-64-sysv64-arg-ext.other.stderr | 12 +++++----- tests/ui/abi/pass-indirectly-attr.stderr | 4 ++-- tests/ui/abi/sysv64-zst.stderr | 2 +- .../pass-by-value-abi.aarch64.stderr | 2 +- .../c-variadic/pass-by-value-abi.win.stderr | 2 +- .../pass-by-value-abi.x86_64.stderr | 6 ++--- 20 files changed, 71 insertions(+), 70 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/int.rs b/compiler/rustc_codegen_gcc/src/int.rs index 69049ada616b0..abfc2a9999727 100644 --- a/compiler/rustc_codegen_gcc/src/int.rs +++ b/compiler/rustc_codegen_gcc/src/int.rs @@ -400,7 +400,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { fixed_count: 3, conv: CanonAbi::C, can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, }; fn_abi.adjust_for_foreign_abi(self.cx, ExternAbi::C { unwind: false }); diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 670e94ba24128..53338f85ec11e 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -2239,9 +2239,10 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { // discussion in the rust-lang issue: let key: u32 = self.sess().pointer_authentication_fn_ptr_key().unwrap() as u32; - // If sess().pointer_authentication_fn_ptr_type_discrimination() is true, this contains - // the function pointer type discriminator; otherwise, it is 0. - let discriminator = fn_abi?.ptrauth_discriminator; + // If sess().pointer_authentication_fn_ptr_type_discrimination() is enabled, this contains + // the function pointer type discriminator; otherwise, it is None. LLVM expects a u64 here, + // so use 0 when no discriminator is present. + let discriminator = fn_abi?.ptrauth_discriminator.unwrap_or(0); Some(llvm::OperandBundleBox::new( "ptrauth", diff --git a/compiler/rustc_target/src/callconv/mod.rs b/compiler/rustc_target/src/callconv/mod.rs index 893ac55c8f50e..8ea207a4bba56 100644 --- a/compiler/rustc_target/src/callconv/mod.rs +++ b/compiler/rustc_target/src/callconv/mod.rs @@ -701,7 +701,7 @@ pub struct FnAbi<'a, Ty> { /// Indicates if an unwind may happen across a call to this function. pub can_unwind: bool, /// Computed type discriminator for pointer authentication purpose. - pub ptrauth_discriminator: u64, + pub ptrauth_discriminator: Option, } // Needs to be a custom impl because of the bounds on the `TyAndLayout` debug impl. @@ -1042,6 +1042,6 @@ mod size_asserts { use super::*; // tidy-alphabetical-start static_assert_size!(ArgAbi<'_, usize>, 64); - static_assert_size!(FnAbi<'_, usize>, 96); + static_assert_size!(FnAbi<'_, usize>, 104); // tidy-alphabetical-end } diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 8c8453e48a273..867cec3d8fee7 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -615,9 +615,9 @@ fn fn_abi_new_uncached<'tcx>( sig.abi(), ), ptrauth_discriminator: if tcx.sess.pointer_authentication_fn_ptr_type_discrimination() { - ptrauth_compute_fn_ptr_type_discriminator_for(tcx, sig).unwrap_or(0).into() + Some(ptrauth_compute_fn_ptr_type_discriminator_for(tcx, sig).unwrap_or(0).into()) } else { - 0 + None }, }; fn_abi_adjust_for_abi(cx, &mut fn_abi, sig.abi()); diff --git a/tests/ui/abi/c-zst.aarch64-darwin.stderr b/tests/ui/abi/c-zst.aarch64-darwin.stderr index 3c4c88ba2b19f..c9ad40983c331 100644 --- a/tests/ui/abi/c-zst.aarch64-darwin.stderr +++ b/tests/ui/abi/c-zst.aarch64-darwin.stderr @@ -59,7 +59,7 @@ error: fn_abi_of(pass_zst) = FnAbi { fixed_count: 1, conv: C, can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/c-zst.rs:67:1 | diff --git a/tests/ui/abi/c-zst.powerpc-linux.stderr b/tests/ui/abi/c-zst.powerpc-linux.stderr index d0a5bab9e8073..715fae66f3c93 100644 --- a/tests/ui/abi/c-zst.powerpc-linux.stderr +++ b/tests/ui/abi/c-zst.powerpc-linux.stderr @@ -71,7 +71,7 @@ error: fn_abi_of(pass_zst) = FnAbi { fixed_count: 1, conv: C, can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/c-zst.rs:67:1 | diff --git a/tests/ui/abi/c-zst.s390x-linux.stderr b/tests/ui/abi/c-zst.s390x-linux.stderr index d0a5bab9e8073..715fae66f3c93 100644 --- a/tests/ui/abi/c-zst.s390x-linux.stderr +++ b/tests/ui/abi/c-zst.s390x-linux.stderr @@ -71,7 +71,7 @@ error: fn_abi_of(pass_zst) = FnAbi { fixed_count: 1, conv: C, can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/c-zst.rs:67:1 | diff --git a/tests/ui/abi/c-zst.sparc64-linux.stderr b/tests/ui/abi/c-zst.sparc64-linux.stderr index d0a5bab9e8073..715fae66f3c93 100644 --- a/tests/ui/abi/c-zst.sparc64-linux.stderr +++ b/tests/ui/abi/c-zst.sparc64-linux.stderr @@ -71,7 +71,7 @@ error: fn_abi_of(pass_zst) = FnAbi { fixed_count: 1, conv: C, can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/c-zst.rs:67:1 | diff --git a/tests/ui/abi/c-zst.x86_64-linux.stderr b/tests/ui/abi/c-zst.x86_64-linux.stderr index 3c4c88ba2b19f..c9ad40983c331 100644 --- a/tests/ui/abi/c-zst.x86_64-linux.stderr +++ b/tests/ui/abi/c-zst.x86_64-linux.stderr @@ -59,7 +59,7 @@ error: fn_abi_of(pass_zst) = FnAbi { fixed_count: 1, conv: C, can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/c-zst.rs:67:1 | diff --git a/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr b/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr index d0a5bab9e8073..715fae66f3c93 100644 --- a/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr +++ b/tests/ui/abi/c-zst.x86_64-pc-windows-gnu.stderr @@ -71,7 +71,7 @@ error: fn_abi_of(pass_zst) = FnAbi { fixed_count: 1, conv: C, can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/c-zst.rs:67:1 | diff --git a/tests/ui/abi/debug.generic.stderr b/tests/ui/abi/debug.generic.stderr index f71e639b16f4f..6149a9aa01b7b 100644 --- a/tests/ui/abi/debug.generic.stderr +++ b/tests/ui/abi/debug.generic.stderr @@ -106,7 +106,7 @@ error: fn_abi_of(test) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/debug.rs:31:1 | @@ -188,7 +188,7 @@ error: fn_abi_of(TestFnPtr) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/debug.rs:37:1 | @@ -260,7 +260,7 @@ error: fn_abi_of(test_generic) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/debug.rs:40:1 | @@ -339,7 +339,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } right ABI = FnAbi { args: [ @@ -406,7 +406,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/debug.rs:59:1 | @@ -487,7 +487,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } right ABI = FnAbi { args: [ @@ -562,7 +562,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/debug.rs:62:1 | @@ -635,7 +635,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } right ABI = FnAbi { args: [ @@ -702,7 +702,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/debug.rs:65:1 | @@ -775,7 +775,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } right ABI = FnAbi { args: [ @@ -842,7 +842,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/debug.rs:69:1 | @@ -937,7 +937,7 @@ error: fn_abi_of(assoc_test) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/debug.rs:52:5 | diff --git a/tests/ui/abi/debug.loongarch64.stderr b/tests/ui/abi/debug.loongarch64.stderr index f3bd161b301b5..8fd106815487d 100644 --- a/tests/ui/abi/debug.loongarch64.stderr +++ b/tests/ui/abi/debug.loongarch64.stderr @@ -106,7 +106,7 @@ error: fn_abi_of(test) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/debug.rs:31:1 | @@ -188,7 +188,7 @@ error: fn_abi_of(TestFnPtr) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/debug.rs:37:1 | @@ -260,7 +260,7 @@ error: fn_abi_of(test_generic) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/debug.rs:40:1 | @@ -339,7 +339,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } right ABI = FnAbi { args: [ @@ -406,7 +406,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/debug.rs:59:1 | @@ -487,7 +487,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } right ABI = FnAbi { args: [ @@ -562,7 +562,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/debug.rs:62:1 | @@ -635,7 +635,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } right ABI = FnAbi { args: [ @@ -702,7 +702,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/debug.rs:65:1 | @@ -775,7 +775,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } right ABI = FnAbi { args: [ @@ -842,7 +842,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/debug.rs:69:1 | @@ -937,7 +937,7 @@ error: fn_abi_of(assoc_test) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/debug.rs:52:5 | diff --git a/tests/ui/abi/debug.riscv64.stderr b/tests/ui/abi/debug.riscv64.stderr index f3bd161b301b5..8fd106815487d 100644 --- a/tests/ui/abi/debug.riscv64.stderr +++ b/tests/ui/abi/debug.riscv64.stderr @@ -106,7 +106,7 @@ error: fn_abi_of(test) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/debug.rs:31:1 | @@ -188,7 +188,7 @@ error: fn_abi_of(TestFnPtr) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/debug.rs:37:1 | @@ -260,7 +260,7 @@ error: fn_abi_of(test_generic) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/debug.rs:40:1 | @@ -339,7 +339,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } right ABI = FnAbi { args: [ @@ -406,7 +406,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/debug.rs:59:1 | @@ -487,7 +487,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } right ABI = FnAbi { args: [ @@ -562,7 +562,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/debug.rs:62:1 | @@ -635,7 +635,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } right ABI = FnAbi { args: [ @@ -702,7 +702,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/debug.rs:65:1 | @@ -775,7 +775,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } right ABI = FnAbi { args: [ @@ -842,7 +842,7 @@ error: ABIs are not compatible fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/debug.rs:69:1 | @@ -937,7 +937,7 @@ error: fn_abi_of(assoc_test) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: $SOME_BOOL, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/debug.rs:52:5 | diff --git a/tests/ui/abi/numbers-arithmetic/x86-64-sysv64-arg-ext.apple.stderr b/tests/ui/abi/numbers-arithmetic/x86-64-sysv64-arg-ext.apple.stderr index 927594534d9b8..df49fbfe3d272 100644 --- a/tests/ui/abi/numbers-arithmetic/x86-64-sysv64-arg-ext.apple.stderr +++ b/tests/ui/abi/numbers-arithmetic/x86-64-sysv64-arg-ext.apple.stderr @@ -69,7 +69,7 @@ error: fn_abi_of(i8) = FnAbi { SysV64, ), can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/x86-64-sysv64-arg-ext.rs:13:1 | @@ -147,7 +147,7 @@ error: fn_abi_of(u8) = FnAbi { SysV64, ), can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/x86-64-sysv64-arg-ext.rs:19:1 | @@ -225,7 +225,7 @@ error: fn_abi_of(i16) = FnAbi { SysV64, ), can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/x86-64-sysv64-arg-ext.rs:25:1 | @@ -303,7 +303,7 @@ error: fn_abi_of(u16) = FnAbi { SysV64, ), can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/x86-64-sysv64-arg-ext.rs:31:1 | @@ -381,7 +381,7 @@ error: fn_abi_of(i32) = FnAbi { SysV64, ), can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/x86-64-sysv64-arg-ext.rs:37:1 | @@ -459,7 +459,7 @@ error: fn_abi_of(u32) = FnAbi { SysV64, ), can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/x86-64-sysv64-arg-ext.rs:43:1 | diff --git a/tests/ui/abi/numbers-arithmetic/x86-64-sysv64-arg-ext.other.stderr b/tests/ui/abi/numbers-arithmetic/x86-64-sysv64-arg-ext.other.stderr index 113ad20e16bc4..7ceb6a2092af2 100644 --- a/tests/ui/abi/numbers-arithmetic/x86-64-sysv64-arg-ext.other.stderr +++ b/tests/ui/abi/numbers-arithmetic/x86-64-sysv64-arg-ext.other.stderr @@ -69,7 +69,7 @@ error: fn_abi_of(i8) = FnAbi { SysV64, ), can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/x86-64-sysv64-arg-ext.rs:13:1 | @@ -147,7 +147,7 @@ error: fn_abi_of(u8) = FnAbi { SysV64, ), can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/x86-64-sysv64-arg-ext.rs:19:1 | @@ -225,7 +225,7 @@ error: fn_abi_of(i16) = FnAbi { SysV64, ), can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/x86-64-sysv64-arg-ext.rs:25:1 | @@ -303,7 +303,7 @@ error: fn_abi_of(u16) = FnAbi { SysV64, ), can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/x86-64-sysv64-arg-ext.rs:31:1 | @@ -381,7 +381,7 @@ error: fn_abi_of(i32) = FnAbi { SysV64, ), can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/x86-64-sysv64-arg-ext.rs:37:1 | @@ -459,7 +459,7 @@ error: fn_abi_of(u32) = FnAbi { SysV64, ), can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/x86-64-sysv64-arg-ext.rs:43:1 | diff --git a/tests/ui/abi/pass-indirectly-attr.stderr b/tests/ui/abi/pass-indirectly-attr.stderr index 75504c8546498..8431b6ed6dea0 100644 --- a/tests/ui/abi/pass-indirectly-attr.stderr +++ b/tests/ui/abi/pass-indirectly-attr.stderr @@ -84,7 +84,7 @@ error: fn_abi_of(extern_c) = FnAbi { fixed_count: 1, conv: C, can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/pass-indirectly-attr.rs:20:1 | @@ -176,7 +176,7 @@ error: fn_abi_of(extern_rust) = FnAbi { fixed_count: 1, conv: Rust, can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/pass-indirectly-attr.rs:27:1 | diff --git a/tests/ui/abi/sysv64-zst.stderr b/tests/ui/abi/sysv64-zst.stderr index ed8fe5b83fe7c..f19480faec4fa 100644 --- a/tests/ui/abi/sysv64-zst.stderr +++ b/tests/ui/abi/sysv64-zst.stderr @@ -61,7 +61,7 @@ error: fn_abi_of(pass_zst) = FnAbi { SysV64, ), can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/sysv64-zst.rs:8:1 | diff --git a/tests/ui/c-variadic/pass-by-value-abi.aarch64.stderr b/tests/ui/c-variadic/pass-by-value-abi.aarch64.stderr index f9dc652b53440..f827817dccc55 100644 --- a/tests/ui/c-variadic/pass-by-value-abi.aarch64.stderr +++ b/tests/ui/c-variadic/pass-by-value-abi.aarch64.stderr @@ -71,7 +71,7 @@ error: fn_abi_of(take_va_list) = FnAbi { fixed_count: 1, conv: C, can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/pass-by-value-abi.rs:27:1 | diff --git a/tests/ui/c-variadic/pass-by-value-abi.win.stderr b/tests/ui/c-variadic/pass-by-value-abi.win.stderr index 150a9262b0f88..638a0856b7b7f 100644 --- a/tests/ui/c-variadic/pass-by-value-abi.win.stderr +++ b/tests/ui/c-variadic/pass-by-value-abi.win.stderr @@ -66,7 +66,7 @@ error: fn_abi_of(take_va_list) = FnAbi { fixed_count: 1, conv: C, can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/pass-by-value-abi.rs:27:1 | diff --git a/tests/ui/c-variadic/pass-by-value-abi.x86_64.stderr b/tests/ui/c-variadic/pass-by-value-abi.x86_64.stderr index 7471991866eef..afa436de5b83b 100644 --- a/tests/ui/c-variadic/pass-by-value-abi.x86_64.stderr +++ b/tests/ui/c-variadic/pass-by-value-abi.x86_64.stderr @@ -71,7 +71,7 @@ error: fn_abi_of(take_va_list) = FnAbi { fixed_count: 1, conv: C, can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/pass-by-value-abi.rs:27:1 | @@ -153,7 +153,7 @@ error: fn_abi_of(take_va_list_sysv64) = FnAbi { SysV64, ), can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/pass-by-value-abi.rs:37:1 | @@ -235,7 +235,7 @@ error: fn_abi_of(take_va_list_win64) = FnAbi { Win64, ), can_unwind: false, - ptrauth_discriminator: 0, + ptrauth_discriminator: None, } --> $DIR/pass-by-value-abi.rs:44:1 | From 224c1a708ca98163d18c27cb76d265ff02e93c03 Mon Sep 17 00:00:00 2001 From: Jakub Chlanda Date: Thu, 10 Sep 2026 13:33:36 +0000 Subject: [PATCH 3/8] [PAC] repr(transparent) and correct handling of Option in encoder Also tighten the handling of enums. --- .../rustc_middle/src/ptrauth/discriminator.rs | 72 ++++++++++++------- 1 file changed, 45 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_middle/src/ptrauth/discriminator.rs b/compiler/rustc_middle/src/ptrauth/discriminator.rs index 7501f1b072188..30226b8eebe07 100644 --- a/compiler/rustc_middle/src/ptrauth/discriminator.rs +++ b/compiler/rustc_middle/src/ptrauth/discriminator.rs @@ -81,6 +81,7 @@ use rustc_session::PointerAuthSchema; use rustc_span::sym; use crate::ptrauth::llvm_siphash::llvm_pointer_auth_stable_siphash; +use crate::ty::layout::LayoutCx; /// Types that can serve as a source for function pointer type discrimination. /// @@ -317,35 +318,46 @@ enum ClangDiscTy<'tcx> { Void, } -// Canonicalize Option-wrapped pointer types used to model C nullable pointers. +// Canonicalize types that are ABI-compatible with C's nullable pointer +// convention, so the rest of this encoder can treat them like the corresponding +// plain pointer type. // -// Rust and Clang should compute identical discriminators for equivalent C APIs. -// Clang does not distinguish nullable from non-nullable pointer types when -// computing function pointer authentication discriminators, so -// `Option` and `Option<*mut T>` are encoded identically to their -// underlying pointer types. +// Rust guarantees the null-pointer optimization for references, function +// pointers, Box, NonNull, and NonZero*. `Option` and `Option<&T>` are +// therefore unwrapped here. `Option<*mut T>` and `Option<*const T>` are +// deliberately left unchanged: raw pointers are not covered by the NPO +// guarantee and are handled by the general `Adt` arm in `to_clang_disc_ty`. // -// Although `Option<*mut T>` is not considered FFI-safe by Rust and triggers the -// `improper_ctypes`/`improper_ctypes_definitions` lints, this is a warning -// rather than a hard error. Canonicalizing it here preserves Clang-compatible -// discriminator computation. -// -// Please see the following tests for sample use cases: -// pauth-fn-ptr-type-discrimination-option-callback.rs, -// pauth-fn-ptr-type-discrimination-option-return.rs and pauth-fn-ptr-type-discrimination-option.rs -fn canonicalize_c_type<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { - if let ty::Adt(def, args) = ty.kind() - && tcx.is_diagnostic_item(sym::Option, def.did()) - { - let inner = args.type_at(0); - - match inner.kind() { - ty::FnPtr(..) | ty::RawPtr(..) => return inner, - _ => {} +// Also peels `repr(transparent)` wrappers to canonicalize them to their +// underlying type. +fn canonicalize_c_type<'tcx>(tcx: TyCtxt<'tcx>, mut ty: Ty<'tcx>) -> Ty<'tcx> { + loop { + let before = ty; + + if let ty::Adt(def, args) = ty.kind() + && tcx.is_diagnostic_item(sym::Option, def.did()) + { + let inner = args.type_at(0); + if let ty::FnPtr(..) | ty::Ref(..) = inner.kind() { + ty = inner; + } } - } - ty + // Only ADTs can be repr(transparent); skip the layout query entirely + // for everything else. + if matches!(ty.kind(), ty::Adt(..)) { + let typing_env = ty::TypingEnv::fully_monomorphized(); + + if let Ok(layout) = tcx.layout_of(typing_env.as_query_input(ty)) { + let cx = LayoutCx::new(tcx, typing_env); + ty = layout.peel_transparent_wrappers(&cx).ty; + } + } + + if ty == before { + return ty; + } + } } /// Lowers a Rust type into a Clang-compatible discriminator type. @@ -388,8 +400,14 @@ fn to_clang_disc_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ClangDiscTy<'tcx> // arrays ignore size ty::Array(elem, _) => ClangDiscTy::Array { elem: *elem }, - // enums to integer collapse - ty::Adt(def, _) if def.is_enum() => ClangDiscTy::EnumLikeInt, + // enums to integer collapse - mirrors Clang's Type::Enum handling, + // which recurses into the enum's underlying integer type per C11 + // 6.7.2.2p4. + // A non-niche, data-carrying enum (e.g. Option<*mut T>) is not an + // "enumerated type" in the C11 sense, such enums fall through to the + // general Adt(_) => AdtName(..) arm below instead. + ty::Adt(def, _) if def.is_enum() && def.is_payloadfree() => ClangDiscTy::EnumLikeInt, + // simd vectors ty::Adt(def, args) if def.repr().simd() => { // Clang encodes SIMD vectors by their total size From 72089e70fe14b786d6cea0fa8940c223ed08b63d Mon Sep 17 00:00:00 2001 From: Jakub Chlanda Date: Fri, 10 Jul 2026 12:16:40 +0000 Subject: [PATCH 4/8] [PAC] Enable support for FPTR_TYPE_DISCR in ABI Version Also remove error messages/tests that used to guarded it. --- compiler/rustc_session/src/diagnostics.rs | 6 ------ compiler/rustc_session/src/session.rs | 21 +++++-------------- ...on_not_supported_pointer_authentication.rs | 12 ----------- ...ot_supported_pointer_authentication.stderr | 4 ---- 4 files changed, 5 insertions(+), 38 deletions(-) delete mode 100644 tests/ui/pointer_authentication/type_discrimination_not_supported_pointer_authentication.rs delete mode 100644 tests/ui/pointer_authentication/type_discrimination_not_supported_pointer_authentication.stderr diff --git a/compiler/rustc_session/src/diagnostics.rs b/compiler/rustc_session/src/diagnostics.rs index e673435dae396..46cece7075924 100644 --- a/compiler/rustc_session/src/diagnostics.rs +++ b/compiler/rustc_session/src/diagnostics.rs @@ -394,12 +394,6 @@ pub(crate) struct StackProtectorNotSupportedForTarget<'a> { pub(crate) target_triple: &'a TargetTuple, } -#[derive(Diagnostic)] -#[diag("function pointer type discrimination is not supported")] -pub(crate) struct PointerAuthenticationTypeDiscriminationNotSupportedForTarget<'a> { - pub(crate) target_triple: &'a TargetTuple, -} - #[derive(Diagnostic)] #[diag( "`-Z pointer-authentication` is not supported for target {$target_triple} and will be ignored" diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 1c39124b995e7..dc27c76046d16 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -208,8 +208,7 @@ impl PointerAuthConfig { const GOT: u32 = 8; const GOTOS: u32 = 9; const TYPEINFO_VT_PTR_DISCR: u32 = 10; - // FIXME(jchlanda) We don't yet support function pointer type discrimination. - // const FPTR_TYPE_DISCR: u32 = 11; + const FPTR_TYPE_DISCR: u32 = 11; let pauth_abi_version: u32 = (u32::from(self.intrinsics) << INTRINSICS) | (u32::from(self.function_pointers.is_some()) << CALLS) @@ -227,7 +226,10 @@ impl PointerAuthConfig { })) << INIT_FINI_ADDR_DISC) | (u32::from(self.elf_got) << GOT) | (u32::from(self.indirect_gotos) << GOTOS) - | (u32::from(self.typeinfo_vt_ptr_discrimination) << TYPEINFO_VT_PTR_DISCR); + | (u32::from(self.typeinfo_vt_ptr_discrimination) << TYPEINFO_VT_PTR_DISCR) + | (u32::from(self.function_pointers.as_ref().is_some_and(|schema| { + matches!(schema.discrimination_kind, PointerAuthDiscrimination::Type) + })) << FPTR_TYPE_DISCR); pauth_abi_version } @@ -1574,19 +1576,6 @@ fn validate_commandline_args_with_session_available(sess: &Session) { sess.dcx().emit_err(diagnostics::LinkerPluginToWindowsNotSupported); } - if sess - .pointer_auth_config - .as_ref() - .and_then(|cfg| cfg.function_pointers.as_ref()) - .is_some_and(|schema| matches!(schema.discrimination_kind, PointerAuthDiscrimination::Type)) - { - sess.dcx().emit_err( - diagnostics::PointerAuthenticationTypeDiscriminationNotSupportedForTarget { - target_triple: &sess.opts.target_triple, - }, - ); - } - if sess.target.cfg_abi != CfgAbi::Pauthtest && !sess.opts.unstable_opts.pointer_authentication.is_empty() { diff --git a/tests/ui/pointer_authentication/type_discrimination_not_supported_pointer_authentication.rs b/tests/ui/pointer_authentication/type_discrimination_not_supported_pointer_authentication.rs deleted file mode 100644 index 6838e749fd333..0000000000000 --- a/tests/ui/pointer_authentication/type_discrimination_not_supported_pointer_authentication.rs +++ /dev/null @@ -1,12 +0,0 @@ -//@ ignore-backends: gcc -//@ check-fail -//@ needs-llvm-components: aarch64 - -//@ compile-flags: -Zpointer-authentication=+function-pointer-type-discrimination --crate-type=lib --target aarch64-unknown-linux-pauthtest - -#![feature(no_core)] -#![no_std] -#![no_main] -#![no_core] - -//~? ERROR function pointer type discrimination is not supported diff --git a/tests/ui/pointer_authentication/type_discrimination_not_supported_pointer_authentication.stderr b/tests/ui/pointer_authentication/type_discrimination_not_supported_pointer_authentication.stderr deleted file mode 100644 index c040b0cb61f66..0000000000000 --- a/tests/ui/pointer_authentication/type_discrimination_not_supported_pointer_authentication.stderr +++ /dev/null @@ -1,4 +0,0 @@ -error: function pointer type discrimination is not supported - -error: aborting due to 1 previous error - From a22bf9a9a0330cec37cfb7b31907f212be6c1176 Mon Sep 17 00:00:00 2001 From: Jakub Chlanda Date: Fri, 10 Jul 2026 12:59:12 +0000 Subject: [PATCH 5/8] [PAC] Support type discriminators in static allocations The codegen now walks the layout of static initializer types to find extern "C" function pointer fields, computes their type discriminators, and applies those discriminators when emitting authenticated function pointer relocations. Also make sure that type discrimination is never applied to init/fini entries. --- compiler/rustc_codegen_gcc/src/common.rs | 4 +- compiler/rustc_codegen_llvm/src/asm.rs | 8 +- compiler/rustc_codegen_llvm/src/common.rs | 20 ++- compiler/rustc_codegen_llvm/src/consts.rs | 170 +++++++++++++++++- .../rustc_codegen_ssa/src/traits/consts.rs | 5 +- 5 files changed, 195 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index 42b92f55e0e80..8c00f0f378850 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -1,9 +1,10 @@ use gccjit::{GlobalKind, LValue, RValue, ToRValue, Type}; use rustc_abi::Primitive::Pointer; -use rustc_abi::{self as abi, HasDataLayout}; +use rustc_abi::{self as abi, HasDataLayout, Size}; use rustc_codegen_ssa::traits::{ BaseTypeCodegenMethods, ConstCodegenMethods, MiscCodegenMethods, StaticCodegenMethods, }; +use rustc_data_structures::fx::FxHashMap; use rustc_middle::mir::Mutability; use rustc_middle::mir::interpret::{GlobalAlloc, PointerArithmetic, Scalar}; use rustc_middle::ty::layout::LayoutOf; @@ -333,6 +334,7 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> { layout: abi::Scalar, ty: Type<'gcc>, _ptrauth_schema: Option, + _ptrauth_discriminators: Option<&FxHashMap>, ) -> RValue<'gcc> { let bitsize = if layout.is_bool() { 1 } else { layout.size(self).bits() }; match cv { diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 21888720524a5..21ca616c615ca 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -166,7 +166,8 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { ConstScalar::Ptr(ptr, _) => { let (prov, _) = ptr.prov_and_relative_offset(); let global_alloc = self.tcx.global_alloc(prov.alloc_id()); - let value = self.cx.alloc_to_backend(global_alloc, false, None).unwrap(); + let value = + self.cx.alloc_to_backend(global_alloc, false, None, None).unwrap(); inputs.push(value); op_idx.insert(idx, constraints.len()); constraints.push("s".to_string()); @@ -456,8 +457,9 @@ impl<'tcx> AsmCodegenMethods<'tcx> for CodegenCx<'_, 'tcx> { ConstScalar::Ptr(ptr, _) => { let (prov, offset) = ptr.prov_and_relative_offset(); let global_alloc = self.tcx.global_alloc(prov.alloc_id()); - let llval = - self.alloc_to_backend(global_alloc, true, None).unwrap(); + let llval = self + .alloc_to_backend(global_alloc, true, None, None) + .unwrap(); self.add_compiler_used_global(llval); let symbol = llvm::build_string(|s| unsafe { diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index c5c943002dfdc..7f4a49dcef818 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -4,11 +4,12 @@ use std::borrow::Borrow; use libc::{c_char, c_uint}; use rustc_abi::Primitive::Pointer; -use rustc_abi::{self as abi, ExternAbi, HasDataLayout as _}; +use rustc_abi::{self as abi, ExternAbi, HasDataLayout as _, Size}; use rustc_ast::Mutability; use rustc_codegen_ssa::common::TypeKind; use rustc_codegen_ssa::traits::*; use rustc_crate_store::DllImport; +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hash::{StableHash, StableHasher}; use rustc_hashes::Hash128; use rustc_hir::def::DefKind; @@ -183,6 +184,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { global_alloc: GlobalAlloc<'tcx>, need_symbol_name: bool, ptrauth_schema: Option, + ptrauth_discriminators: Option<&FxHashMap>, ) -> Result<&'ll Value, u64> { let alloc = match global_alloc { GlobalAlloc::Function { instance, .. } => { @@ -229,7 +231,13 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { } }; - let init = const_alloc_to_llvm(self, alloc.inner(), IsStatic::No, IsInitOrFini::No); + let init = const_alloc_to_llvm( + self, + alloc.inner(), + IsStatic::No, + IsInitOrFini::No, + ptrauth_discriminators, + ); let alloc = alloc.inner(); if need_symbol_name { @@ -409,6 +417,7 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { layout: abi::Scalar, llty: &'ll Type, ptrauth_schema: Option, + ptrauth_discriminators: Option<&FxHashMap>, ) -> &'ll Value { let bitsize = if layout.is_bool() { 1 } else { layout.size(self).bits() }; match cv { @@ -425,7 +434,12 @@ impl<'ll, 'tcx> ConstCodegenMethods for CodegenCx<'ll, 'tcx> { let (prov, offset) = ptr.prov_and_relative_offset(); let global_alloc = self.tcx.global_alloc(prov.alloc_id()); let base_addr_space = global_alloc.address_space(self); - let base_addr = match self.alloc_to_backend(global_alloc, false, ptrauth_schema) { + let base_addr = match self.alloc_to_backend( + global_alloc, + false, + ptrauth_schema, + ptrauth_discriminators, + ) { Ok(base_addr) => base_addr, Err(base_addr) => { let val = base_addr.wrapping_add(offset.bytes()); diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index ec58c3cb6ad7a..5eebc962d551c 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -5,6 +5,7 @@ use rustc_attr_ir::Linkage; use rustc_attr_ir::lang_items::LangItem; use rustc_codegen_ssa::common; use rustc_codegen_ssa::traits::*; +use rustc_data_structures::fx::FxHashMap; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; @@ -13,8 +14,10 @@ use rustc_middle::mir::interpret::{ read_target_uint, }; use rustc_middle::mono::MonoItem; +use rustc_middle::ptrauth::ptrauth_compute_fn_ptr_type_discriminator_for; +use rustc_middle::ty::consts::ConstExt; use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf}; -use rustc_middle::ty::{self, Instance}; +use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_span::{Symbol, bug, span_bug}; use rustc_target::spec::Arch; use tracing::{debug, instrument, trace}; @@ -36,11 +39,135 @@ pub(crate) enum IsInitOrFini { Yes, No, } + +/// Recursively walks a type layout and records the offsets of all extern "C" +/// function pointer fields together with their computed type discriminators. +/// +/// Traversal currently supports: +/// - references +/// - direct function pointers +/// - structs +/// - tuples +/// - arrays +/// +/// Offsets are accumulated relative to the containing object. +fn collect_fn_ptr_discriminators<'tcx>( + tcx: TyCtxt<'tcx>, + typing_env: ty::TypingEnv<'tcx>, + ty: Ty<'tcx>, +) -> FxHashMap { + let mut map = FxHashMap::default(); + + collect_fn_ptr_discriminators_inner(tcx, typing_env, ty, Size::ZERO, &mut map); + + map +} + +fn collect_fn_ptr_discriminators_inner<'tcx>( + tcx: TyCtxt<'tcx>, + typing_env: ty::TypingEnv<'tcx>, + ty: Ty<'tcx>, + base_offset: Size, + map: &mut FxHashMap, +) { + // Direct function pointer. + if let Some(disc) = ptrauth_compute_fn_ptr_type_discriminator_for(tcx, ty) { + map.insert(base_offset, disc.into()); + + return; + } + + match ty.kind() { + ty::Ref(_, pointee, _) => { + collect_fn_ptr_discriminators_inner(tcx, typing_env, *pointee, base_offset, map); + } + ty::Adt(def, args) if def.is_struct() => { + let Ok(layout) = tcx.layout_of(typing_env.as_query_input(ty)) else { + return; + }; + + let variant = def.non_enum_variant(); + + for (idx, field_def) in variant.fields.iter_enumerated() { + let field_ty = tcx.normalize_erasing_regions(typing_env, field_def.ty(tcx, args)); + + let field_offset = layout.fields.offset(idx.into()); + + collect_fn_ptr_discriminators_inner( + tcx, + typing_env, + field_ty, + base_offset + field_offset, + map, + ); + } + } + ty::Tuple(fields) => { + let Ok(layout) = tcx.layout_of(typing_env.as_query_input(ty)) else { + return; + }; + + for (idx, field_ty) in fields.iter().enumerate() { + let field_offset = layout.fields.offset(idx); + + collect_fn_ptr_discriminators_inner( + tcx, + typing_env, + field_ty, + base_offset + field_offset, + map, + ); + } + } + ty::Array(elem_ty, len) => { + let count = match len.try_to_target_usize(tcx) { + Some(v) => v, + None => return, + }; + + let Ok(elem_layout) = tcx.layout_of(typing_env.as_query_input(*elem_ty)) else { + return; + }; + + let stride = elem_layout.size; + + // Collect discriminator of one element, so we don't have to recompute it for all the + // elements in the array. + let mut elem_map = FxHashMap::default(); + + collect_fn_ptr_discriminators_inner( + tcx, + typing_env, + *elem_ty, + Size::ZERO, + &mut elem_map, + ); + + // SAFETY: We immediately collect into a Vec and sort by offset. + // The HashMap iteration order is irrelevant and must not affect determinism. + #[allow(rustc::potential_query_instability)] + let mut entries: Vec<(Size, u64)> = elem_map.into_iter().collect(); + entries.sort_unstable_by_key(|(offset, _)| *offset); + + // Replicate for every array slot. + for i in 0..count { + let elem_base = base_offset + stride * i; + + for (inner_offset, discr) in entries.iter().copied() { + map.insert(elem_base + inner_offset, discr); + } + } + } + _ => {} + } +} + pub(crate) fn const_alloc_to_llvm<'ll>( cx: &CodegenCx<'ll, '_>, alloc: &Allocation, is_static: IsStatic, is_init_fini: IsInitOrFini, + ptrauth_discriminators: Option<&FxHashMap>, ) -> &'ll Value { // We expect that callers of const_alloc_to_llvm will instead directly codegen a pointer or // integer for any &ZST where the ZST is a constant (i.e. not a static). We should never be @@ -120,7 +247,7 @@ pub(crate) fn const_alloc_to_llvm<'ll>( as u64; let address_space = cx.tcx.global_alloc(prov.alloc_id()).address_space(cx); - let schema = if cx.sess().pointer_authentication() { + let mut schema = if cx.sess().pointer_authentication() { match is_init_fini { IsInitOrFini::Yes => cx.sess().pointer_authentication_init_fini(), IsInitOrFini::No => cx.sess().pointer_authentication_functions(), @@ -128,6 +255,16 @@ pub(crate) fn const_alloc_to_llvm<'ll>( } else { None }; + let discr = + ptrauth_discriminators.as_ref().and_then(|m| m.get(&Size::from_bytes(offset as u64))); + + // Init/fini entries must not participate in function pointer type discrimination, they use + // a dedicated constant value (ptrauth_string_discriminator("init_fini") which is: 0xd9d4). + if let (Some(schema), Some(discr)) = (schema.as_mut(), discr) + && is_init_fini == IsInitOrFini::No + { + schema.constant_discriminator = *discr as u16; + } llvals.push(cx.scalar_to_backend_with_pac( InterpScalar::from_pointer(Pointer::new(prov, Size::from_bytes(ptr_offset)), &cx.tcx), Scalar::Initialized { @@ -136,6 +273,7 @@ pub(crate) fn const_alloc_to_llvm<'ll>( }, cx.type_ptr_ext(address_space), schema, + ptrauth_discriminators, )); next_offset = offset + pointer_size_bytes; } @@ -159,6 +297,15 @@ fn codegen_static_initializer<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, def_id: DefId, ) -> Result<(&'ll Value, ConstAllocation<'tcx>), ErrorHandled> { + let ptrauth_discriminators = if cx.sess().pointer_authentication_fn_ptr_type_discrimination() { + let instance = Instance::mono(cx.tcx, def_id); + let ty = instance.ty(cx.tcx, cx.typing_env()); + + Some(collect_fn_ptr_discriminators(cx.tcx, cx.typing_env(), ty)) + } else { + None + }; + let alloc = cx.tcx.eval_static_initializer(def_id)?; let attrs = cx.tcx.codegen_fn_attrs(def_id); // FIXME(jchlanda) Decide if this could be better served by `ctor` crate. See the discussion @@ -174,7 +321,16 @@ fn codegen_static_initializer<'ll, 'tcx>( } }) .unwrap_or(IsInitOrFini::No); - Ok((const_alloc_to_llvm(cx, alloc.inner(), IsStatic::Yes, is_in_init_fini), alloc)) + Ok(( + const_alloc_to_llvm( + cx, + alloc.inner(), + IsStatic::Yes, + is_in_init_fini, + ptrauth_discriminators.as_ref(), + ), + alloc, + )) } fn set_global_alignment<'ll>(cx: &CodegenCx<'ll, '_>, gv: &'ll Value, mut align: Align) { @@ -911,7 +1067,13 @@ impl<'ll> StaticCodegenMethods for CodegenCx<'ll, '_> { fn static_addr_of(&self, alloc: ConstAllocation<'_>, kind: Option<&str>) -> &'ll Value { // FIXME: should we cache `const_alloc_to_llvm` to avoid repeating this for the // same `ConstAllocation`? - let cv = const_alloc_to_llvm(self, alloc.inner(), IsStatic::No, IsInitOrFini::No); + // FIXME(jchlanda): Add support for pointer authentication type discrimination. + // `static_addr_of` only receives a `ConstAllocation`, so it does not have the type + // information needed to compute function pointer type discriminators. We'll likely need + // to either compute the discriminator map at callers that still know the Rust type, or + // extend this API to accept the required type information. See + // `codegen_static_initializer` for an example of how the discriminator map is computed. + let cv = const_alloc_to_llvm(self, alloc.inner(), IsStatic::No, IsInitOrFini::No, None); let gv = self.static_addr_of_impl(cv, alloc.inner().align, kind); // static_addr_of_impl returns the bare global variable, which might not be in the default diff --git a/compiler/rustc_codegen_ssa/src/traits/consts.rs b/compiler/rustc_codegen_ssa/src/traits/consts.rs index b45b5667be6c9..7f82ebda2e5fb 100644 --- a/compiler/rustc_codegen_ssa/src/traits/consts.rs +++ b/compiler/rustc_codegen_ssa/src/traits/consts.rs @@ -1,4 +1,6 @@ use rustc_abi as abi; +use rustc_abi::Size; +use rustc_data_structures::fx::FxHashMap; use rustc_middle::mir::interpret::Scalar; use rustc_session::PointerAuthSchema; @@ -40,7 +42,7 @@ pub trait ConstCodegenMethods: BackendTypes { fn const_to_opt_u128(&self, v: Self::Value, sign_ext: bool) -> Option; fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: Self::Type) -> Self::Value { - self.scalar_to_backend_with_pac(cv, layout, llty, None) + self.scalar_to_backend_with_pac(cv, layout, llty, None, None) } fn scalar_to_backend_with_pac( &self, @@ -48,6 +50,7 @@ pub trait ConstCodegenMethods: BackendTypes { layout: abi::Scalar, llty: Self::Type, ptrauth_schema: Option, + ptrauth_discriminators: Option<&FxHashMap>, ) -> Self::Value; fn const_ptr_byte_offset(&self, val: Self::Value, offset: abi::Size) -> Self::Value; From 1d4a06cdbc0845371005a4cf051f37df3d95e9cb Mon Sep 17 00:00:00 2001 From: Jakub Chlanda Date: Wed, 29 Jul 2026 14:18:57 +0000 Subject: [PATCH 6/8] [PAC] Extend support to compile-time constants This covers standalone function pointer constants, promoted temporaries, immutable and mutable statics, arrays of function pointers, and mixed structs containing function pointers. Consult pauth-fn-ptr-type-discrimination-static-allocs.rs test for example uses. Revolves around threading PAC information through: * static_addr_of (StaticCodegenMethods) * from_const and from_const_alloc (both on rustc_codegen_ssa::mir::operand / OperandRef) --- compiler/rustc_codegen_gcc/src/common.rs | 2 +- compiler/rustc_codegen_gcc/src/consts.rs | 8 +- compiler/rustc_codegen_llvm/src/consts.rs | 150 ++-------------- compiler/rustc_codegen_ssa/src/meth.rs | 5 +- compiler/rustc_codegen_ssa/src/mir/operand.rs | 43 ++++- compiler/rustc_codegen_ssa/src/mir/retag.rs | 4 +- .../rustc_codegen_ssa/src/traits/statics.rs | 10 +- .../rustc_middle/src/ptrauth/discriminator.rs | 161 ++++++++++++++++-- compiler/rustc_middle/src/ptrauth/mod.rs | 2 +- compiler/rustc_middle/src/ty/vtable.rs | 23 +++ 10 files changed, 256 insertions(+), 152 deletions(-) diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index 8c00f0f378850..2a89ee4d0d3a5 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -117,7 +117,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { Mutability::Mut => { self.static_addr_of_mut(const_alloc_to_gcc(self, alloc), alloc.inner().align, None) } - _ => self.static_addr_of(alloc, None), + _ => self.static_addr_of(alloc, None, None), }; if !self.sess().fewer_names() { // FIXME(antoyo): set value name. diff --git a/compiler/rustc_codegen_gcc/src/consts.rs b/compiler/rustc_codegen_gcc/src/consts.rs index c58ab6d2a9bef..4cf98723490f3 100644 --- a/compiler/rustc_codegen_gcc/src/consts.rs +++ b/compiler/rustc_codegen_gcc/src/consts.rs @@ -8,6 +8,7 @@ use rustc_attr_ir::Linkage; use rustc_codegen_ssa::traits::{ BaseTypeCodegenMethods, ConstCodegenMethods, StaticCodegenMethods, }; +use rustc_data_structures::fx::FxHashMap; use rustc_hir::def::DefKind; use rustc_hir::def_id::LOCAL_CRATE; use rustc_log::tracing::trace; @@ -61,7 +62,12 @@ fn set_global_alignment<'gcc, 'tcx>( } impl<'gcc, 'tcx> StaticCodegenMethods for CodegenCx<'gcc, 'tcx> { - fn static_addr_of(&self, alloc: ConstAllocation<'_>, kind: Option<&str>) -> RValue<'gcc> { + fn static_addr_of( + &self, + alloc: ConstAllocation<'_>, + kind: Option<&str>, + _ptrauth_discriminators: Option<&FxHashMap>, + ) -> RValue<'gcc> { let cv = const_alloc_to_gcc(self, alloc); let align = alloc.inner().align; diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 5eebc962d551c..bb9068f9593dd 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -14,10 +14,9 @@ use rustc_middle::mir::interpret::{ read_target_uint, }; use rustc_middle::mono::MonoItem; -use rustc_middle::ptrauth::ptrauth_compute_fn_ptr_type_discriminator_for; -use rustc_middle::ty::consts::ConstExt; +use rustc_middle::ptrauth::ptrauth_collect_fn_ptr_discriminators; use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf}; -use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; +use rustc_middle::ty::{self, Instance}; use rustc_span::{Symbol, bug, span_bug}; use rustc_target::spec::Arch; use tracing::{debug, instrument, trace}; @@ -40,128 +39,6 @@ pub(crate) enum IsInitOrFini { No, } -/// Recursively walks a type layout and records the offsets of all extern "C" -/// function pointer fields together with their computed type discriminators. -/// -/// Traversal currently supports: -/// - references -/// - direct function pointers -/// - structs -/// - tuples -/// - arrays -/// -/// Offsets are accumulated relative to the containing object. -fn collect_fn_ptr_discriminators<'tcx>( - tcx: TyCtxt<'tcx>, - typing_env: ty::TypingEnv<'tcx>, - ty: Ty<'tcx>, -) -> FxHashMap { - let mut map = FxHashMap::default(); - - collect_fn_ptr_discriminators_inner(tcx, typing_env, ty, Size::ZERO, &mut map); - - map -} - -fn collect_fn_ptr_discriminators_inner<'tcx>( - tcx: TyCtxt<'tcx>, - typing_env: ty::TypingEnv<'tcx>, - ty: Ty<'tcx>, - base_offset: Size, - map: &mut FxHashMap, -) { - // Direct function pointer. - if let Some(disc) = ptrauth_compute_fn_ptr_type_discriminator_for(tcx, ty) { - map.insert(base_offset, disc.into()); - - return; - } - - match ty.kind() { - ty::Ref(_, pointee, _) => { - collect_fn_ptr_discriminators_inner(tcx, typing_env, *pointee, base_offset, map); - } - ty::Adt(def, args) if def.is_struct() => { - let Ok(layout) = tcx.layout_of(typing_env.as_query_input(ty)) else { - return; - }; - - let variant = def.non_enum_variant(); - - for (idx, field_def) in variant.fields.iter_enumerated() { - let field_ty = tcx.normalize_erasing_regions(typing_env, field_def.ty(tcx, args)); - - let field_offset = layout.fields.offset(idx.into()); - - collect_fn_ptr_discriminators_inner( - tcx, - typing_env, - field_ty, - base_offset + field_offset, - map, - ); - } - } - ty::Tuple(fields) => { - let Ok(layout) = tcx.layout_of(typing_env.as_query_input(ty)) else { - return; - }; - - for (idx, field_ty) in fields.iter().enumerate() { - let field_offset = layout.fields.offset(idx); - - collect_fn_ptr_discriminators_inner( - tcx, - typing_env, - field_ty, - base_offset + field_offset, - map, - ); - } - } - ty::Array(elem_ty, len) => { - let count = match len.try_to_target_usize(tcx) { - Some(v) => v, - None => return, - }; - - let Ok(elem_layout) = tcx.layout_of(typing_env.as_query_input(*elem_ty)) else { - return; - }; - - let stride = elem_layout.size; - - // Collect discriminator of one element, so we don't have to recompute it for all the - // elements in the array. - let mut elem_map = FxHashMap::default(); - - collect_fn_ptr_discriminators_inner( - tcx, - typing_env, - *elem_ty, - Size::ZERO, - &mut elem_map, - ); - - // SAFETY: We immediately collect into a Vec and sort by offset. - // The HashMap iteration order is irrelevant and must not affect determinism. - #[allow(rustc::potential_query_instability)] - let mut entries: Vec<(Size, u64)> = elem_map.into_iter().collect(); - entries.sort_unstable_by_key(|(offset, _)| *offset); - - // Replicate for every array slot. - for i in 0..count { - let elem_base = base_offset + stride * i; - - for (inner_offset, discr) in entries.iter().copied() { - map.insert(elem_base + inner_offset, discr); - } - } - } - _ => {} - } -} - pub(crate) fn const_alloc_to_llvm<'ll>( cx: &CodegenCx<'ll, '_>, alloc: &Allocation, @@ -301,7 +178,7 @@ fn codegen_static_initializer<'ll, 'tcx>( let instance = Instance::mono(cx.tcx, def_id); let ty = instance.ty(cx.tcx, cx.typing_env()); - Some(collect_fn_ptr_discriminators(cx.tcx, cx.typing_env(), ty)) + Some(ptrauth_collect_fn_ptr_discriminators(cx.tcx, cx.typing_env(), ty)) } else { None }; @@ -1064,16 +941,21 @@ impl<'ll> StaticCodegenMethods for CodegenCx<'ll, '_> { /// /// The pointer will always be in the default address space. If global variables default to a /// different address space, an addrspacecast is inserted. - fn static_addr_of(&self, alloc: ConstAllocation<'_>, kind: Option<&str>) -> &'ll Value { + fn static_addr_of( + &self, + alloc: ConstAllocation<'_>, + kind: Option<&str>, + ptrauth_discriminators: Option<&FxHashMap>, + ) -> &'ll Value { // FIXME: should we cache `const_alloc_to_llvm` to avoid repeating this for the // same `ConstAllocation`? - // FIXME(jchlanda): Add support for pointer authentication type discrimination. - // `static_addr_of` only receives a `ConstAllocation`, so it does not have the type - // information needed to compute function pointer type discriminators. We'll likely need - // to either compute the discriminator map at callers that still know the Rust type, or - // extend this API to accept the required type information. See - // `codegen_static_initializer` for an example of how the discriminator map is computed. - let cv = const_alloc_to_llvm(self, alloc.inner(), IsStatic::No, IsInitOrFini::No, None); + let cv = const_alloc_to_llvm( + self, + alloc.inner(), + IsStatic::No, + IsInitOrFini::No, + ptrauth_discriminators, + ); let gv = self.static_addr_of_impl(cv, alloc.inner().align, kind); // static_addr_of_impl returns the bare global variable, which might not be in the default diff --git a/compiler/rustc_codegen_ssa/src/meth.rs b/compiler/rustc_codegen_ssa/src/meth.rs index 9c024cacc35c9..b88a1b1c147f1 100644 --- a/compiler/rustc_codegen_ssa/src/meth.rs +++ b/compiler/rustc_codegen_ssa/src/meth.rs @@ -114,7 +114,10 @@ pub(crate) fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>( let vtable_alloc_id = tcx.vtable_allocation((ty, trait_ref)); let vtable_allocation = tcx.global_alloc(vtable_alloc_id).unwrap_memory(); - let vtable = cx.static_addr_of(vtable_allocation, Some("vtable")); + // Vtables cannot contain extern "C"/"System" function pointers (asserted in + // vtable_allocation_provider), so they do not require function pointer type + // discriminators. + let vtable = cx.static_addr_of(vtable_allocation, Some("vtable"), None); cx.apply_vcall_visibility_metadata(ty, trait_ref, vtable); cx.create_vtable_debuginfo(ty, trait_ref, vtable); diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index e017220c549b0..0ebaa24af4cbc 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -8,6 +8,7 @@ use rustc_abi::{ use rustc_attr_ir::lang_items::LangItem; use rustc_middle::mir::interpret::{Pointer, Scalar, alloc_range}; use rustc_middle::mir::{self, ConstValue}; +use rustc_middle::ptrauth::ptrauth_collect_fn_ptr_discriminators; use rustc_middle::ty::consts::ConstExt; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, Ty}; @@ -183,7 +184,34 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { let BackendRepr::Scalar(scalar) = layout.backend_repr else { bug!("from_const: invalid ByVal layout: {:#?}", layout); }; - let llval = bx.scalar_to_backend(x, scalar, bx.immediate_backend_type(layout)); + let llval = match x { + Scalar::Ptr(..) => { + let pointee_ty = match ty.kind() { + ty::Ref(_, pointee, _) => *pointee, + _ => ty, + }; + let ptrauth_discriminators = + if bx.tcx().sess.pointer_authentication_fn_ptr_type_discrimination() { + Some(ptrauth_collect_fn_ptr_discriminators( + bx.tcx(), + bx.typing_env(), + pointee_ty, + )) + } else { + None + }; + let ptrauth_schema = bx.sess().pointer_authentication_functions(); + bx.scalar_to_backend_with_pac( + x, + scalar, + bx.immediate_backend_type(layout), + ptrauth_schema, + ptrauth_discriminators.as_ref(), + ) + } + _ => bx.scalar_to_backend(x, scalar, bx.immediate_backend_type(layout)), + }; + OperandValue::Immediate(llval) } ConstValue::ZeroSized => return OperandRef::zero_sized(layout), @@ -268,8 +296,19 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { } _ if layout.is_zst() => OperandRef::zero_sized(layout), _ => { + let ptrauth_discriminators = + if bx.tcx().sess.pointer_authentication_fn_ptr_type_discrimination() { + Some(ptrauth_collect_fn_ptr_discriminators( + bx.tcx(), + bx.typing_env(), + layout.ty, + )) + } else { + None + }; + // Neither a scalar nor scalar pair. Load from a place - let base_addr = bx.static_addr_of(alloc, None); + let base_addr = bx.static_addr_of(alloc, None, ptrauth_discriminators.as_ref()); let llval = bx.const_ptr_byte_offset(base_addr, offset); bx.load_operand(PlaceRef::new_sized(llval, layout)) diff --git a/compiler/rustc_codegen_ssa/src/mir/retag.rs b/compiler/rustc_codegen_ssa/src/mir/retag.rs index a71a57f02c82a..7652a656db8a3 100644 --- a/compiler/rustc_codegen_ssa/src/mir/retag.rs +++ b/compiler/rustc_codegen_ssa/src/mir/retag.rs @@ -271,7 +271,9 @@ impl<'a, 'tcx, V> RetagPlan { let global_alloc = tcx.global_alloc(alloc_id); let global_mem = global_alloc.unwrap_memory(); - bx.cx().static_addr_of(global_mem, None) + // The range table contains only integer data, not pointer relocations, so no ptrauth + // discriminators are needed. + bx.cx().static_addr_of(global_mem, None, None) } } diff --git a/compiler/rustc_codegen_ssa/src/traits/statics.rs b/compiler/rustc_codegen_ssa/src/traits/statics.rs index c726213025350..20394c98812c1 100644 --- a/compiler/rustc_codegen_ssa/src/traits/statics.rs +++ b/compiler/rustc_codegen_ssa/src/traits/statics.rs @@ -1,10 +1,18 @@ +use rustc_abi::Size; +use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::DefId; use rustc_middle::mir::interpret::ConstAllocation; use super::BackendTypes; pub trait StaticCodegenMethods: BackendTypes { - fn static_addr_of(&self, alloc: ConstAllocation<'_>, kind: Option<&str>) -> Self::Value; + fn static_addr_of( + &self, + alloc: ConstAllocation<'_>, + kind: Option<&str>, + ptrauth_discriminators: Option<&FxHashMap>, + ) -> Self::Value; + fn codegen_static(&mut self, def_id: DefId); } diff --git a/compiler/rustc_middle/src/ptrauth/discriminator.rs b/compiler/rustc_middle/src/ptrauth/discriminator.rs index 30226b8eebe07..b15c66f806172 100644 --- a/compiler/rustc_middle/src/ptrauth/discriminator.rs +++ b/compiler/rustc_middle/src/ptrauth/discriminator.rs @@ -1,11 +1,13 @@ //! Function pointer type discrimination for pointer authentication. //! This module implements Rust's equivalent of Clang's function pointer type -//! discriminator computation used in pointer authentication. +//! discriminator computation used in pointer authentication, as well as the +//! machinery required to locate function pointer fields in Rust layouts that +//! require such discriminators. //! //! Compatibility with Clang is a primary goal. The discriminator produced for a -//! given external "C" function type must match the value computed by Clang so that -//! function pointers can be exchanged safely between Rust and C code while +//! given external "C" function type must match the value computed by Clang so +//! that function pointers can be exchanged safely between Rust and C code while //! preserving pointer authentication semantics. //! //! The implementation mirrors Clang's behavior in @@ -15,14 +17,16 @@ //! //! ## Overview //! -//! The computation is structured into three conceptual stages: +//! The implementation is structured into three conceptual stages: //! //! ### 1. Type normalization and lowering +//! //! Rust types are converted into a language-independent representation //! (`ClangDiscTy`) that mirrors the type categories used by Clang when computing //! function pointer discriminators. This includes canonicalization such as //! treating all pointer-like types uniformly and mapping Rust constructs onto //! their closest C equivalents. +//! //! One notable exception is C `_Complex`. Rust has no corresponding native type, //! so there is no canonical Rust representation to map onto Clang's `_Complex` //! type category. Rather than infer one (for example, by treating `(f32, f32)` @@ -31,29 +35,40 @@ //! encoding. //! //! ### 2. Type encoding +//! //! The lowered representation is serialized into a byte stream using rules //! intended to match Clang's implementation in: //! `encodeTypeForFunctionPointerAuth`. The resulting encoding describes the //! function signature in a target-independent form suitable for hashing. //! //! ### 3. Discriminator hashing +//! //! The encoded byte stream is hashed using LLVM's stable SipHash-2-4 based //! discriminator algorithm. The implementation here is a direct translation //! of LLVM/Clang's logic and must remain bit-for-bit compatible. See: //! . //! Defined in `llvm_siphash.rs`. //! +//! In addition to computing discriminators for individual function pointer +//! types, this module can recursively walk Rust type layouts and produce a map +//! from byte offsets to discriminators for function pointer fields contained +//! within aggregates. +//! //! ## Module structure //! //! - High-level API //! - `FnPtrDiscriminatorSource` //! - `ptrauth_compute_fn_ptr_type_discriminator_for` //! - `ptrauth_clone_discriminated_schema_for` +//! - `ptrauth_collect_fn_ptr_discriminators` //! //! - Low-level API //! - `FnPtrTypeDiscriminatorInput` //! - `compute_fn_ptr_type_discriminator` //! +//! - Layout traversal +//! - `ptrauth_collect_fn_ptr_discriminators` +//! //! - Signature extraction //! - `extract_fn_ptr_type` //! @@ -68,19 +83,22 @@ //! //! ## Compatibility requirements //! -//! Any changes to the encoding or hashing logic should be validated against Clang's -//! discriminator computation. Divergence from Clang will result in incompatible -//! pointer authentication values across language boundaries. +//! Any changes to the encoding or hashing logic should be validated against +//! Clang's discriminator computation. Divergence from Clang will result in +//! incompatible pointer authentication values across language boundaries. //! -//! This implementation intentionally approximates Clang's behavior for extern "C" -//! function types only. It does NOT attempt to model full type system rules. +//! This implementation intentionally approximates Clang's behavior for +//! `extern "C"` and `extern "System"` function types only. It does NOT attempt +//! to model full Rust type system rules. -use rustc_abi::ExternAbi; +use rustc_abi::{ExternAbi, Size}; +use rustc_data_structures::fx::FxHashMap; use rustc_middle::ty::{self, Instance, Ty, TyCtxt, Unnormalized}; use rustc_session::PointerAuthSchema; use rustc_span::sym; use crate::ptrauth::llvm_siphash::llvm_pointer_auth_stable_siphash; +use crate::ty::consts::ConstExt; use crate::ty::layout::LayoutCx; /// Types that can serve as a source for function pointer type discrimination. @@ -256,6 +274,129 @@ fn extract_fn_ptr_type<'tcx>(tcx: TyCtxt<'tcx>, mut ty: Ty<'tcx>) -> Option( + tcx: TyCtxt<'tcx>, + typing_env: ty::TypingEnv<'tcx>, + ty: Ty<'tcx>, +) -> FxHashMap { + let mut map = FxHashMap::default(); + + collect_fn_ptr_discriminators_inner(tcx, typing_env, ty, Size::ZERO, &mut map); + + map +} + +fn collect_fn_ptr_discriminators_inner<'tcx>( + tcx: TyCtxt<'tcx>, + typing_env: ty::TypingEnv<'tcx>, + ty: Ty<'tcx>, + base_offset: Size, + map: &mut FxHashMap, +) { + // Direct function pointer. + if let Some(disc) = ptrauth_compute_fn_ptr_type_discriminator_for(tcx, ty) { + map.insert(base_offset, disc.into()); + + return; + } + + match ty.kind() { + ty::Ref(_, pointee, _) => { + collect_fn_ptr_discriminators_inner(tcx, typing_env, *pointee, base_offset, map); + } + ty::Adt(def, args) if def.is_struct() => { + let Ok(layout) = tcx.layout_of(typing_env.as_query_input(ty)) else { + return; + }; + + let variant = def.non_enum_variant(); + + for (idx, field_def) in variant.fields.iter_enumerated() { + let field_ty = tcx.normalize_erasing_regions(typing_env, field_def.ty(tcx, args)); + + let field_offset = layout.fields.offset(idx.into()); + + collect_fn_ptr_discriminators_inner( + tcx, + typing_env, + field_ty, + base_offset + field_offset, + map, + ); + } + } + ty::Tuple(fields) => { + let Ok(layout) = tcx.layout_of(typing_env.as_query_input(ty)) else { + return; + }; + + for (idx, field_ty) in fields.iter().enumerate() { + let field_offset = layout.fields.offset(idx); + + collect_fn_ptr_discriminators_inner( + tcx, + typing_env, + field_ty, + base_offset + field_offset, + map, + ); + } + } + ty::Array(elem_ty, len) => { + let count = match len.try_to_target_usize(tcx) { + Some(v) => v, + None => return, + }; + + let Ok(elem_layout) = tcx.layout_of(typing_env.as_query_input(*elem_ty)) else { + return; + }; + + let stride = elem_layout.size; + + // Collect discriminator of one element, so we don't have to recompute it for all the + // elements in the array. + let mut elem_map = FxHashMap::default(); + + collect_fn_ptr_discriminators_inner( + tcx, + typing_env, + *elem_ty, + Size::ZERO, + &mut elem_map, + ); + + // SAFETY: We immediately collect into a Vec and sort by offset. + // The HashMap iteration order is irrelevant and must not affect determinism. + #[allow(rustc::potential_query_instability)] + let mut entries: Vec<(Size, u64)> = elem_map.into_iter().collect(); + entries.sort_unstable_by_key(|(offset, _)| *offset); + + // Replicate for every array slot. + for i in 0..count { + let elem_base = base_offset + stride * i; + + for (inner_offset, discr) in entries.iter().copied() { + map.insert(elem_base + inner_offset, discr); + } + } + } + _ => {} + } +} + /// Computes the Clang-compatible function pointer type discriminator. /// /// This is the low-level discriminator computation routine operating on an diff --git a/compiler/rustc_middle/src/ptrauth/mod.rs b/compiler/rustc_middle/src/ptrauth/mod.rs index 0eeef5e07f61c..46b3068524be7 100644 --- a/compiler/rustc_middle/src/ptrauth/mod.rs +++ b/compiler/rustc_middle/src/ptrauth/mod.rs @@ -3,5 +3,5 @@ pub mod llvm_siphash; pub use discriminator::{ FnPtrDiscriminatorSource, FnPtrTypeDiscriminatorInput, ptrauth_clone_discriminated_schema_for, - ptrauth_compute_fn_ptr_type_discriminator_for, + ptrauth_collect_fn_ptr_discriminators, ptrauth_compute_fn_ptr_type_discriminator_for, }; diff --git a/compiler/rustc_middle/src/ty/vtable.rs b/compiler/rustc_middle/src/ty/vtable.rs index fb56bda7d4562..95176361eac3e 100644 --- a/compiler/rustc_middle/src/ty/vtable.rs +++ b/compiler/rustc_middle/src/ty/vtable.rs @@ -85,6 +85,27 @@ pub(super) fn vtable_allocation_provider<'tcx>( tcx: TyCtxt<'tcx>, key: (Ty<'tcx>, Option>), ) -> AllocId { + let ptrauth_assert_not_c_abi_fn_ptr = |instance: ty::Instance<'tcx>| { + if tcx.sess.pointer_authentication_fn_ptr_type_discrimination() { + let sig = tcx + .instantiate_and_normalize_erasing_regions( + instance.args, + ty::TypingEnv::fully_monomorphized(), + tcx.fn_sig(instance.def_id()), + ) + .skip_binder(); + + assert!( + !matches!( + sig.abi(), + rustc_abi::ExternAbi::C { .. } | rustc_abi::ExternAbi::System { .. } + ), + "vtable entry unexpectedly has a C ABI function pointer type: {:?}", + instance + ); + } + }; + let (ty, poly_trait_ref) = key; let vtable_entries = if let Some(poly_trait_ref) = poly_trait_ref { @@ -123,6 +144,7 @@ pub(super) fn vtable_allocation_provider<'tcx>( VtblEntry::MetadataDropInPlace => { if ty.needs_drop(tcx, ty::TypingEnv::fully_monomorphized()) { let instance = ty::Instance::resolve_drop_glue(tcx, ty); + ptrauth_assert_not_c_abi_fn_ptr(instance); let fn_alloc_id = tcx.reserve_and_set_fn_alloc(instance, CTFE_ALLOC_SALT); let fn_ptr = Pointer::from(fn_alloc_id); Scalar::from_pointer(fn_ptr, &tcx) @@ -134,6 +156,7 @@ pub(super) fn vtable_allocation_provider<'tcx>( VtblEntry::MetadataAlign => Scalar::from_uint(align, ptr_size), VtblEntry::Vacant => continue, VtblEntry::Method(instance) => { + ptrauth_assert_not_c_abi_fn_ptr(instance); // Prepare the fn ptr we write into the vtable. let fn_alloc_id = tcx.reserve_and_set_fn_alloc(instance, CTFE_ALLOC_SALT); let fn_ptr = Pointer::from(fn_alloc_id); From b39d7868b347a8299a62c86f4bbfb70249fe83a6 Mon Sep 17 00:00:00 2001 From: Jakub Chlanda Date: Thu, 10 Sep 2026 14:02:00 +0000 Subject: [PATCH 7/8] [PAC] Use scalar_to_backend_with_pac for const globals Also a fix for non function (closure, coroutines, etc) in discriminator_input. Fix in v-table assert. --- compiler/rustc_codegen_ssa/src/mir/operand.rs | 63 +++++++++++++------ .../rustc_middle/src/ptrauth/discriminator.rs | 32 +++++++--- compiler/rustc_middle/src/ty/vtable.rs | 15 ++--- 3 files changed, 72 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 0ebaa24af4cbc..80b61b68c5c30 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -200,7 +200,13 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { } else { None }; - let ptrauth_schema = bx.sess().pointer_authentication_functions(); + let mut ptrauth_schema = bx.sess().pointer_authentication_functions(); + if let Some(schema) = ptrauth_schema.as_mut() + && let Some(discr) = + ptrauth_discriminators.as_ref().and_then(|m| m.get(&Size::ZERO)) + { + schema.constant_discriminator = *discr as u16; + } bx.scalar_to_backend_with_pac( x, scalar, @@ -248,13 +254,44 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { let alloc_align = alloc.inner().align; assert!(alloc_align >= layout.align.abi, "{alloc_align:?} < {:?}", layout.align.abi); - let read_scalar = |start, size, s: abi::Scalar, ty| { + let ptrauth_discriminators = + if bx.tcx().sess.pointer_authentication_fn_ptr_type_discrimination() { + Some(ptrauth_collect_fn_ptr_discriminators(bx.tcx(), bx.typing_env(), layout.ty)) + } else { + None + }; + + // `start` is the absolute position to read from within `alloc` (which may be a larger, + // shared allocation). `local_offset` is this field's offset within the value's own layout, + // used only to key into `ptrauth_discriminators`. The two are NOT interchangeable whenever + // `offset != 0` (e.g. the `b` field of a ScalarPair, or a value that isn't at the start of + // its allocation). + let read_scalar = |start: Size, local_offset: Size, size, s: abi::Scalar, ty| { match alloc.0.read_scalar( bx, alloc_range(start, size), /*read_provenance*/ matches!(s.primitive(), abi::Primitive::Pointer(_)), ) { - Ok(val) => bx.scalar_to_backend(val, s, ty), + Ok(val) => { + if let abi::Primitive::Pointer(_) = s.primitive() { + let mut schema = bx.sess().pointer_authentication_functions(); + if let Some(schema) = schema.as_mut() + && let Some(discr) = + ptrauth_discriminators.as_ref().and_then(|m| m.get(&local_offset)) + { + schema.constant_discriminator = *discr as u16; + } + bx.scalar_to_backend_with_pac( + val, + s, + ty, + schema, + ptrauth_discriminators.as_ref(), + ) + } else { + bx.scalar_to_backend(val, s, ty) + } + } Err(_) => bx.const_poison(ty), } }; @@ -269,7 +306,8 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { BackendRepr::Scalar(s @ abi::Scalar::Initialized { .. }) => { let size = s.size(bx); assert_eq!(size, layout.size, "abi::Scalar size does not match layout size"); - let val = read_scalar(offset, size, s, bx.immediate_backend_type(layout)); + let val = + read_scalar(offset, Size::ZERO, size, s, bx.immediate_backend_type(layout)); OperandRef { val: OperandValue::Immediate(val), layout, move_annotation: None } } BackendRepr::ScalarPair { @@ -282,12 +320,14 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { assert!(alloc_b_offset.bytes() > 0); let a_val = read_scalar( offset, + Size::ZERO, a_size, a, bx.scalar_pair_element_backend_type(layout, 0, true), ); let b_val = read_scalar( alloc_b_offset, + local_b_offset, b_size, b, bx.scalar_pair_element_backend_type(layout, 1, true), @@ -296,26 +336,13 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { } _ if layout.is_zst() => OperandRef::zero_sized(layout), _ => { - let ptrauth_discriminators = - if bx.tcx().sess.pointer_authentication_fn_ptr_type_discrimination() { - Some(ptrauth_collect_fn_ptr_discriminators( - bx.tcx(), - bx.typing_env(), - layout.ty, - )) - } else { - None - }; - - // Neither a scalar nor scalar pair. Load from a place + // Neither a scalar nor scalar pair. Load from a place. let base_addr = bx.static_addr_of(alloc, None, ptrauth_discriminators.as_ref()); - let llval = bx.const_ptr_byte_offset(base_addr, offset); bx.load_operand(PlaceRef::new_sized(llval, layout)) } } } - /// Asserts that this operand refers to a scalar and returns /// a reference to its value. pub fn immediate(self) -> V { diff --git a/compiler/rustc_middle/src/ptrauth/discriminator.rs b/compiler/rustc_middle/src/ptrauth/discriminator.rs index b15c66f806172..f56b2bf96c760 100644 --- a/compiler/rustc_middle/src/ptrauth/discriminator.rs +++ b/compiler/rustc_middle/src/ptrauth/discriminator.rs @@ -63,7 +63,8 @@ //! - `ptrauth_collect_fn_ptr_discriminators` //! //! - Low-level API -//! - `FnPtrTypeDiscriminatorInput` +//! - `FnPtrTypeDiscriminatorInput` - canonical function signature input for +//! discriminator computation; exposes the function ABI through `abi()`. //! - `compute_fn_ptr_type_discriminator` //! //! - Layout traversal @@ -150,15 +151,22 @@ impl<'tcx> FnPtrDiscriminatorSource<'tcx> for Ty<'tcx> { /// normalized before constructing the canonical discriminator input. impl<'tcx> FnPtrDiscriminatorSource<'tcx> for Instance<'tcx> { fn discriminator_input(self, tcx: TyCtxt<'tcx>) -> Option> { - let sig = tcx - .instantiate_and_normalize_erasing_regions( - self.args, - ty::TypingEnv::fully_monomorphized(), - tcx.fn_sig(self.def_id()), - ) - .skip_binder(); - - Some(FnPtrTypeDiscriminatorInput::from_sig(sig)) + let typing_env = ty::TypingEnv::fully_monomorphized(); + + match self.ty(tcx, typing_env).kind() { + ty::FnDef(def_id, args) => { + let sig = tcx + .instantiate_and_normalize_erasing_regions( + args.skip_binder(), + typing_env, + tcx.fn_sig(*def_id), + ) + .skip_binder(); + Some(FnPtrTypeDiscriminatorInput::from_sig(sig)) + } + // Closures, coroutines, etc. are never called via an `extern "C"` function pointer. + _ => None, + } } } /// Enables discriminator computation directly from instantiated function @@ -232,6 +240,10 @@ pub struct FnPtrTypeDiscriminatorInput<'tcx> { } impl<'tcx> FnPtrTypeDiscriminatorInput<'tcx> { + pub fn abi(&self) -> ExternAbi { + self.abi + } + fn from_sig(sig: ty::FnSig<'tcx>) -> Self { FnPtrTypeDiscriminatorInput { inputs: sig.inputs(), diff --git a/compiler/rustc_middle/src/ty/vtable.rs b/compiler/rustc_middle/src/ty/vtable.rs index 95176361eac3e..b5ae8e7292a5b 100644 --- a/compiler/rustc_middle/src/ty/vtable.rs +++ b/compiler/rustc_middle/src/ty/vtable.rs @@ -7,6 +7,7 @@ use rustc_type_ir::elaborate; use crate::mir::interpret::{ AllocId, AllocInit, Allocation, CTFE_ALLOC_SALT, Pointer, Scalar, alloc_range, }; +use crate::ptrauth::discriminator::FnPtrDiscriminatorSource; use crate::ty::{self, Instance, TraitRef, Ty, TyCtxt}; #[derive(Clone, Copy, PartialEq, StableHash)] @@ -86,18 +87,12 @@ pub(super) fn vtable_allocation_provider<'tcx>( key: (Ty<'tcx>, Option>), ) -> AllocId { let ptrauth_assert_not_c_abi_fn_ptr = |instance: ty::Instance<'tcx>| { - if tcx.sess.pointer_authentication_fn_ptr_type_discrimination() { - let sig = tcx - .instantiate_and_normalize_erasing_regions( - instance.args, - ty::TypingEnv::fully_monomorphized(), - tcx.fn_sig(instance.def_id()), - ) - .skip_binder(); - + if tcx.sess.pointer_authentication_fn_ptr_type_discrimination() + && let Some(input) = instance.discriminator_input(tcx) + { assert!( !matches!( - sig.abi(), + input.abi(), rustc_abi::ExternAbi::C { .. } | rustc_abi::ExternAbi::System { .. } ), "vtable entry unexpectedly has a C ABI function pointer type: {:?}", From 8514ba34fdad7ea8cf95e7876cfd77757bd9187d Mon Sep 17 00:00:00 2001 From: Jakub Chlanda Date: Mon, 21 Sep 2026 10:18:24 +0000 Subject: [PATCH 8/8] [PAC] Make sure that the encoder honors ABI compatibility rules for fn Meaning if two types are ABI compatible they must have the same encoding and hash value. Provide a ui test which groups the function pointers by the ABI compatibility rules and enforces the rule. --- compiler/rustc_attr_ir/src/data_structures.rs | 9 + .../rustc_attr_ir/src/encode_cross_crate.rs | 2 + .../src/attributes/rustc_dump.rs | 52 +- compiler/rustc_attr_parsing/src/context.rs | 1 + compiler/rustc_feature/src/builtin_attrs.rs | 1 + compiler/rustc_interface/src/passes.rs | 3 +- .../rustc_middle/src/ptrauth/discriminator.rs | 131 +++-- compiler/rustc_passes/src/check_attr.rs | 1 + compiler/rustc_passes/src/lib.rs | 1 + compiler/rustc_passes/src/ptrauth_test.rs | 42 ++ compiler/rustc_span/src/symbol.rs | 3 + tests/ui/README.md | 4 + ...scriminator-abi-compat-encoder-and-hash.rs | 215 +++++++ ...minator-abi-compat-encoder-and-hash.stderr | 530 ++++++++++++++++++ 14 files changed, 951 insertions(+), 44 deletions(-) create mode 100644 compiler/rustc_passes/src/ptrauth_test.rs create mode 100644 tests/ui/ptrauth/discriminator-abi-compat-encoder-and-hash.rs create mode 100644 tests/ui/ptrauth/discriminator-abi-compat-encoder-and-hash.stderr diff --git a/compiler/rustc_attr_ir/src/data_structures.rs b/compiler/rustc_attr_ir/src/data_structures.rs index 712ed41ae7759..70d35bdc9477e 100644 --- a/compiler/rustc_attr_ir/src/data_structures.rs +++ b/compiler/rustc_attr_ir/src/data_structures.rs @@ -590,6 +590,12 @@ pub enum RustcDumpLayoutKind { Size, } +#[derive(Clone, Debug, StableHash, Encodable, Decodable, PrintAttribute)] +pub enum RustcDumpPtrauthDiscriminatorKind { + Encoding, + Hash, +} + #[derive(Clone, Debug, StableHash, Encodable, Decodable, PrintAttribute, PartialEq, Eq)] pub enum RustcMirKind { PeekMaybeInit, @@ -1252,6 +1258,9 @@ pub enum AttributeKind { /// Represents the [`rustc_dump_object_lifetime_defaults`](./attribute.rustc_dump_object_lifetime_defaults.html) attribute. RustcDumpObjectLifetimeDefaults, + /// Represents the [`rustc_dump_ptrauth_discriminator`](./attribute.:rustc_dump_ptrauth_discriminator.html) attribute. + RustcDumpPtrauthDiscriminator(ThinVec), + /// Represents the [`rustc_dump_symbol_name`](./attribute.rustc_dump_symbol_name.html) attribute. RustcDumpSymbolName(Span), diff --git a/compiler/rustc_attr_ir/src/encode_cross_crate.rs b/compiler/rustc_attr_ir/src/encode_cross_crate.rs index 66fbbc1e3cbf7..aca74ff9df8cd 100644 --- a/compiler/rustc_attr_ir/src/encode_cross_crate.rs +++ b/compiler/rustc_attr_ir/src/encode_cross_crate.rs @@ -140,6 +140,7 @@ impl AttributeKind { RustcDumpItemBounds => No, RustcDumpLayout(..) => No, RustcDumpObjectLifetimeDefaults => No, + RustcDumpPtrauthDiscriminator(..) => No, RustcDumpSymbolName(..) => Yes, RustcDumpUserArgs => No, RustcDumpVariances => No, @@ -355,6 +356,7 @@ impl AttributeKind { RustcDumpItemBounds => false, RustcDumpLayout(..) => false, RustcDumpObjectLifetimeDefaults => false, + RustcDumpPtrauthDiscriminator(..) => false, RustcDumpSymbolName(..) => false, RustcDumpUserArgs => false, RustcDumpVariances => false, diff --git a/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs index 99c7e933b07b4..66eb1168aa035 100644 --- a/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs +++ b/compiler/rustc_attr_parsing/src/attributes/rustc_dump.rs @@ -1,5 +1,5 @@ use rustc_attr_ir::target::{AssocCtxt, MethodKind, Target}; -use rustc_attr_ir::{AttributeKind, RustcDumpLayoutKind}; +use rustc_attr_ir::{AttributeKind, RustcDumpLayoutKind, RustcDumpPtrauthDiscriminatorKind}; use rustc_feature::AttributeStability; use rustc_span::{Span, Symbol, sym}; @@ -178,6 +178,56 @@ impl CombineAttributeParser for RustcDumpLayoutParser { } } +pub(crate) struct RustcDumpPtrauthDiscriminatorParser; + +impl CombineAttributeParser for RustcDumpPtrauthDiscriminatorParser { + const PATH: &[Symbol] = &[sym::rustc_dump_ptrauth_discriminator]; + + type Item = RustcDumpPtrauthDiscriminatorKind; + + const CONVERT: ConvertFn = + |items, _| AttributeKind::RustcDumpPtrauthDiscriminator(items); + + const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Fn)]); + + const TEMPLATE: AttributeTemplate = template!(List: &["encoding", "hash"]); + const STABILITY: AttributeStability = unstable!(rustc_attrs); + + fn extend( + cx: &mut AcceptContext<'_, '_>, + args: &ArgParser, + ) -> impl IntoIterator { + let Some(items) = cx.expect_list(args, cx.attr_span) else { + return vec![]; + }; + + let mut result = Vec::new(); + for item in items.mixed() { + let Some(arg) = item.meta_item_no_args() else { + cx.adcx().expected_not_literal(item.span()); + continue; + }; + let Some(ident) = arg.ident() else { + cx.adcx().expected_identifier(arg.span()); + return vec![]; + }; + let kind = match ident.name { + sym::ptrauth_encoding => RustcDumpPtrauthDiscriminatorKind::Encoding, + sym::ptrauth_hash => RustcDumpPtrauthDiscriminatorKind::Hash, + _ => { + cx.adcx().expected_specific_argument( + ident.span, + &[sym::ptrauth_encoding, sym::ptrauth_hash], + ); + continue; + } + }; + result.push(kind); + } + result + } +} + pub(crate) struct RustcDumpObjectLifetimeDefaultsParser; impl NoArgsAttributeParser for RustcDumpObjectLifetimeDefaultsParser { diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 72839643b4dc3..2698e6e4a42e8 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -194,6 +194,7 @@ attribute_parsers!( Combine, Combine, Combine, + Combine, Combine, Combine, Combine, diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 0f96eb7f158ed..5c0b337e5995e 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -396,6 +396,7 @@ pub static BUILTIN_ATTRIBUTES: &[Symbol] = &[ sym::rustc_dump_generics, sym::rustc_dump_hidden_type_of_opaques, sym::rustc_dump_layout, + sym::rustc_dump_ptrauth_discriminator, sym::rustc_abi, sym::rustc_regions, sym::rustc_delayed_bug_from_inside_query, diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 5ea1cb20990b5..8dc5fa827a692 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -34,7 +34,7 @@ use rustc_middle::ty::{self, RegisteredTools, TyCtxt}; use rustc_middle::util::Providers; use rustc_parse::lexer::StripTokens; use rustc_parse::{new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal}; -use rustc_passes::{abi_test, input_stats, layout_test}; +use rustc_passes::{abi_test, input_stats, layout_test, ptrauth_test}; use rustc_resolve::{Resolver, ResolverOutputs}; use rustc_session::config::{Input, OutFileName, OutputFilenames, OutputType}; use rustc_session::diagnostics::feature_err; @@ -1193,6 +1193,7 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { }); sess.time("layout_testing", || layout_test::test_layout(tcx)); + sess.time("ptrauth_testing", || ptrauth_test::test_ptrauth_discriminator(tcx)); sess.time("abi_testing", || abi_test::test_abi(tcx)); } diff --git a/compiler/rustc_middle/src/ptrauth/discriminator.rs b/compiler/rustc_middle/src/ptrauth/discriminator.rs index f56b2bf96c760..558a08a002620 100644 --- a/compiler/rustc_middle/src/ptrauth/discriminator.rs +++ b/compiler/rustc_middle/src/ptrauth/discriminator.rs @@ -21,11 +21,12 @@ //! //! ### 1. Type normalization and lowering //! -//! Rust types are converted into a language-independent representation -//! (`ClangDiscTy`) that mirrors the type categories used by Clang when computing -//! function pointer discriminators. This includes canonicalization such as -//! treating all pointer-like types uniformly and mapping Rust constructs onto -//! their closest C equivalents. +//! Rust types are first canonicalized according to ABI representation +//! (treating ABI-equivalent wrappers and niche representations as their +//! underlying representation, and treating pointer-like types uniformly), +//! then converted into a language-independent representation (`ClangDiscTy`) +//! that mirrors the type categories used by Clang when computing function +//! pointer discriminators. //! //! One notable exception is C `_Complex`. Rust has no corresponding native type, //! so there is no canonical Rust representation to map onto Clang's `_Complex` @@ -92,11 +93,10 @@ //! `extern "C"` and `extern "System"` function types only. It does NOT attempt //! to model full Rust type system rules. -use rustc_abi::{ExternAbi, Size}; +use rustc_abi::{ExternAbi, Size, TagEncoding, Variants}; use rustc_data_structures::fx::FxHashMap; use rustc_middle::ty::{self, Instance, Ty, TyCtxt, Unnormalized}; use rustc_session::PointerAuthSchema; -use rustc_span::sym; use crate::ptrauth::llvm_siphash::llvm_pointer_auth_stable_siphash; use crate::ty::consts::ConstExt; @@ -244,7 +244,7 @@ impl<'tcx> FnPtrTypeDiscriminatorInput<'tcx> { self.abi } - fn from_sig(sig: ty::FnSig<'tcx>) -> Self { + pub fn from_sig(sig: ty::FnSig<'tcx>) -> Self { FnPtrTypeDiscriminatorInput { inputs: sig.inputs(), output: sig.output(), @@ -409,16 +409,14 @@ fn collect_fn_ptr_discriminators_inner<'tcx>( } } -/// Computes the Clang-compatible function pointer type discriminator. -/// /// This is the low-level discriminator computation routine operating on an /// already constructed `FnPtrTypeDiscriminatorInput`. -fn compute_fn_ptr_type_discriminator<'tcx>( +fn encode_fn_ptr_type_discriminator<'tcx>( tcx: TyCtxt<'tcx>, input: &FnPtrTypeDiscriminatorInput<'tcx>, -) -> u16 { +) -> Option { if !matches!(input.abi, ExternAbi::C { .. } | ExternAbi::System { .. }) { - return 0; + return None; } let mut enc = PtrauthEncoder::new(); @@ -436,9 +434,30 @@ fn compute_fn_ptr_type_discriminator<'tcx>( enc.push(b'E'); - let hash = enc.finish(); + Some(enc) +} + +/// Computes the Clang-compatible function pointer type discriminator (hashed). +/// +/// Returns `0` for function ABIs that are not supported by the Clang-compatible +/// encoding. +pub fn compute_fn_ptr_type_discriminator<'tcx>( + tcx: TyCtxt<'tcx>, + input: &FnPtrTypeDiscriminatorInput<'tcx>, +) -> u16 { + encode_fn_ptr_type_discriminator(tcx, input).map(|enc| enc.finish().into()).unwrap_or(0) +} - hash.into() +/// Returns the raw Clang-compatible type encoding used as input to the +/// discriminator hash. +/// +/// This is primarily used for debugging and comparing Rust's encoding against +/// Clang's `encodeTypeForFunctionPointerAuth`. +pub fn debug_encode_fn_ptr_type<'tcx>( + tcx: TyCtxt<'tcx>, + input: &FnPtrTypeDiscriminatorInput<'tcx>, +) -> String { + encode_fn_ptr_type_discriminator(tcx, input).map(|enc| enc.debug_string()).unwrap_or_default() } // Clang disc type. @@ -454,6 +473,9 @@ enum ClangDiscTy<'tcx> { // - raw pointers (`*const T`, `*mut T`) // - Rust references (`&T`, `&mut T`) // - function pointers + // - `Box` (canonicalized to a raw pointer) + // - `NonNull` (canonicalized through its transparent representation) + // - DST pointer-like types (`dyn Trait`, slices, `str`) // All collapse to a single Clang-compatible 'P' node. Pointer, @@ -471,42 +493,62 @@ enum ClangDiscTy<'tcx> { Void, } -// Canonicalize types that are ABI-compatible with C's nullable pointer -// convention, so the rest of this encoder can treat them like the corresponding -// plain pointer type. -// -// Rust guarantees the null-pointer optimization for references, function -// pointers, Box, NonNull, and NonZero*. `Option` and `Option<&T>` are -// therefore unwrapped here. `Option<*mut T>` and `Option<*const T>` are -// deliberately left unchanged: raw pointers are not covered by the NPO -// guarantee and are handled by the general `Adt` arm in `to_clang_disc_ty`. -// -// Also peels `repr(transparent)` wrappers to canonicalize them to their -// underlying type. -fn canonicalize_c_type<'tcx>(tcx: TyCtxt<'tcx>, mut ty: Ty<'tcx>) -> Ty<'tcx> { +/// Canonicalizes Rust types that have the same ABI representation as a simpler +/// C-compatible type for discriminator purposes. +/// +/// This is intentionally representation-based rather than purely semantic: +/// types that have the same ABI representation are lowered to the same +/// discriminator type. This includes: +/// - pattern types, which are transparent with respect to representation; +/// - `Box`, which is represented as a thin pointer; +/// - size-0, alignment-1 types, which are represented like `()`; +/// - `repr(transparent)` wrappers, which are represented like their non-ZST +/// field; +/// - two-variant niche enums, which are represented like their payload field. +/// +/// The canonicalization is repeated until reaching a fixed point because one +/// transformation can expose another canonicalization opportunity. +fn canonicalize_abi_compatible_type<'tcx>(tcx: TyCtxt<'tcx>, mut ty: Ty<'tcx>) -> Ty<'tcx> { + let typing_env = ty::TypingEnv::fully_monomorphized(); + loop { let before = ty; - if let ty::Adt(def, args) = ty.kind() - && tcx.is_diagnostic_item(sym::Option, def.did()) - { - let inner = args.type_at(0); - if let ty::FnPtr(..) | ty::Ref(..) = inner.kind() { - ty = inner; - } + if let ty::Pat(base, _) = ty.kind() { + ty = *base; } - // Only ADTs can be repr(transparent); skip the layout query entirely - // for everything else. - if matches!(ty.kind(), ty::Adt(..)) { - let typing_env = ty::TypingEnv::fully_monomorphized(); + if ty.is_box_global(tcx) { + ty = Ty::new_imm_ptr( + tcx, + ty.boxed_ty().expect("is_box_global() returned true, so this must be a Box"), + ); + } - if let Ok(layout) = tcx.layout_of(typing_env.as_query_input(ty)) { + if let Ok(layout) = tcx.layout_of(typing_env.as_query_input(ty)) { + if layout.is_zst() && layout.align.abi.bytes() == 1 { + ty = tcx.types.unit; + } else if matches!(ty.kind(), ty::Adt(..)) { let cx = LayoutCx::new(tcx, typing_env); ty = layout.peel_transparent_wrappers(&cx).ty; } } + if let ty::Adt(def, args) = ty.kind() + && def.is_enum() + && def.variants().len() == 2 + && let Ok(layout) = tcx.layout_of(typing_env.as_query_input(ty)) + && let Variants::Multiple { + tag_encoding: TagEncoding::Niche { untagged_variant, .. }, + .. + } = layout.variants + { + let variant = def.variant(untagged_variant); + if let [field] = &variant.fields.raw[..] { + ty = tcx.normalize_erasing_regions(typing_env, field.ty(tcx, args)); + } + } + if ty == before { return ty; } @@ -533,7 +575,7 @@ fn canonicalize_c_type<'tcx>(tcx: TyCtxt<'tcx>, mut ty: Ty<'tcx>) -> Ty<'tcx> { /// `_Complex` types. /// This must remain in sync with Clang's `encodeTypeForFunctionPointerAuth`. fn to_clang_disc_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ClangDiscTy<'tcx> { - let ty = canonicalize_c_type(tcx, ty); + let ty = canonicalize_abi_compatible_type(tcx, ty); match ty.kind() { // C void / Rust () _ if ty.is_unit() => ClangDiscTy::Void, @@ -545,7 +587,8 @@ fn to_clang_disc_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ClangDiscTy<'tcx> ty::Int(_) | ty::Uint(_) => ClangDiscTy::Int, ty::Float(f) => ClangDiscTy::Float(f), - // everything pointer-like collapses + // Pointer-like types form a discriminator boundary: the pointee type + // does not participate in the encoding. ty::RawPtr(..) | ty::Ref(..) | ty::FnPtr(..) | ty::Dynamic(..) | ty::Slice(_) | ty::Str => { ClangDiscTy::Pointer } @@ -611,6 +654,10 @@ impl PtrauthEncoder { fn finish(&self) -> u16 { llvm_pointer_auth_stable_siphash(&self.buf) } + + fn debug_string(&self) -> String { + String::from_utf8_lossy(&self.buf).into_owned() + } } /// Encodes a ClangDiscTy into the discriminator byte stream. diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index ed5f6a83c06c1..4986f4e451c10 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -342,6 +342,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::RustcDumpItemBounds => (), AttributeKind::RustcDumpLayout(..) => (), AttributeKind::RustcDumpObjectLifetimeDefaults => (), + AttributeKind::RustcDumpPtrauthDiscriminator(..) => (), AttributeKind::RustcDumpSymbolName(..) => (), AttributeKind::RustcDumpUserArgs => (), AttributeKind::RustcDumpVariances => (), diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index 77bd179e8dd80..9c1f9c83e067d 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -28,6 +28,7 @@ pub mod input_stats; mod lang_items; pub mod layout_test; mod lib_features; +pub mod ptrauth_test; mod reachable; pub mod stability; mod upvars; diff --git a/compiler/rustc_passes/src/ptrauth_test.rs b/compiler/rustc_passes/src/ptrauth_test.rs new file mode 100644 index 0000000000000..668f57b148c19 --- /dev/null +++ b/compiler/rustc_passes/src/ptrauth_test.rs @@ -0,0 +1,42 @@ +use rustc_attr_ir::{RustcDumpPtrauthDiscriminatorKind, find_attr}; +use rustc_hir::def::DefKind; +use rustc_middle::ptrauth::FnPtrTypeDiscriminatorInput; +use rustc_middle::ptrauth::discriminator::{ + compute_fn_ptr_type_discriminator, debug_encode_fn_ptr_type, +}; +use rustc_middle::ty::TyCtxt; + +pub fn test_ptrauth_discriminator(tcx: TyCtxt<'_>) { + if !tcx.features().rustc_attrs() { + return; + } + for def_id in tcx.hir_crate_items(()).definitions() { + if tcx.def_kind(def_id) != DefKind::Fn { + continue; + } + let Some(kinds) = find_attr!(tcx, def_id, RustcDumpPtrauthDiscriminator(kinds) => kinds) + else { + continue; + }; + + let sig = tcx.fn_sig(def_id).instantiate_identity().skip_binder(); + let input = FnPtrTypeDiscriminatorInput::from_sig(sig); + let span = tcx.def_span(def_id); + + for kind in kinds { + let message = match kind { + RustcDumpPtrauthDiscriminatorKind::Encoding => { + format!( + "ptrauth discriminator encoding: \"{}\"", + debug_encode_fn_ptr_type(tcx, &input) + ) + } + RustcDumpPtrauthDiscriminatorKind::Hash => { + let res = compute_fn_ptr_type_discriminator(tcx, &input); + format!("ptrauth discriminator hash: {} (0x{:x})", res, res) + } + }; + tcx.dcx().span_err(span, message); + } + } +} diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 3debf3248ff80..16fe2fa16259a 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1690,6 +1690,8 @@ symbols! { ptr_write_bytes, ptr_write_unaligned, ptr_write_volatile, + ptrauth_encoding, + ptrauth_hash, pub_macro_rules, pub_restricted, public, @@ -1846,6 +1848,7 @@ symbols! { rustc_dump_item_bounds, rustc_dump_layout, rustc_dump_object_lifetime_defaults, + rustc_dump_ptrauth_discriminator, rustc_dump_symbol_name, rustc_dump_user_args, rustc_dump_variances, diff --git a/tests/ui/README.md b/tests/ui/README.md index 27995e0ab4cd5..9570cdee8b33c 100644 --- a/tests/ui/README.md +++ b/tests/ui/README.md @@ -1116,6 +1116,10 @@ Contains only 2 tests, related to a single issue, which was about an error cause **FIXME**: Probably rehome under some typecheck / binop directory. +## `tests/ui/ptrauth/`: Function pointer type discrimination + +Contain only 1 tests, related to how Rust computes function pointer type discriminators for pointer authenticated code. The test uses `ptrauth_encoding` and `ptrauth_hash` attributes to obtain string encoding and hashed value respectively. + ## `tests/ui/pub/`: `pub` keyword A large category about function and type public/private visibility, and its impact when using features across crates. Checks both visibility-related error messages and previously buggy cases. diff --git a/tests/ui/ptrauth/discriminator-abi-compat-encoder-and-hash.rs b/tests/ui/ptrauth/discriminator-abi-compat-encoder-and-hash.rs new file mode 100644 index 0000000000000..6c4b6225a775f --- /dev/null +++ b/tests/ui/ptrauth/discriminator-abi-compat-encoder-and-hash.rs @@ -0,0 +1,215 @@ +// Exercises the `fn` ABI-compatibility guarantees documented at +// https://doc.rust-lang.org/std/primitive.fn.html#abi-compatibility +// in the context of function pointer type discrimination. +// +// Within each group, every function's parameter type must be ABI-compatible +// with every other's, and must produce an identical discriminator. `*_neg` +// functions are negative controls and must NOT match the group they sit beside. +// +// NOTE: The doc's fourth compatibility rule +// "Any two fn (function pointer) types are ABI-compatible with each other if +// they have the same ABI string or the ABI string only differs in a trailing +// -unwind, independent of the rest of their signature. (This means you can pass +// fn() to a function expecting fn(i32), and the call will be valid ABI-wise. +// The callee receives the result of transmuting the function pointer from fn() +// to fn(i32); that transmutation is itself a well-defined operation, it’s just +// almost certainly UB to later call that function pointer.)" is +// satisfied for function pointer types used as VALUES (e.g. a callback parameter). +// Those collapse to 'P' via the same blanket pointer-merge that handles +// every other pointer-like type. It is deliberately *NOT HONORED* for the top-level signature +// being authenticated here. +// +// Honoring the rule fully would mean that every extern "C"/"System" function +// produces the identical discriminator, making function pointer type +// discrimination useless. + +//@ dont-require-annotations: ERROR +#![crate_type = "lib"] +#![feature(rustc_attrs)] +#![allow(dead_code)] +#![allow(improper_ctypes_definitions)] +#![feature(allocator_ext)] + +use std::alloc::{AllocError, Allocator, Global, Layout}; +use std::marker::PhantomData; +use std::num::NonZero; +use std::ptr::NonNull; + +struct SomeStruct { + _x: i32, +} + +// "*const T, *mut T, &T, &mut T, Box (specifically, only Box), +// and NonNull are all ABI-compatible with each other for all T. They are +// also ABI-compatible with each other for different T if they have the same +// metadata type (::Metadata)." +#[rustc_dump_ptrauth_discriminator(ptrauth_encoding, ptrauth_hash)] +extern "C" fn g1_a(_: *const i32) {} // expect: "FvPE": 10942 (0x2abe) +#[rustc_dump_ptrauth_discriminator(ptrauth_encoding, ptrauth_hash)] +extern "C" fn g1_b(_: *mut i32) {} // expect: "FvPE": 10942 (0x2abe) +#[rustc_dump_ptrauth_discriminator(ptrauth_encoding, ptrauth_hash)] +extern "C" fn g1_c(_: &i32) {} // expect: "FvPE": 10942 (0x2abe) +#[rustc_dump_ptrauth_discriminator(ptrauth_encoding, ptrauth_hash)] +extern "C" fn g1_d(_: &mut i32) {} // expect: "FvPE": 10942 (0x2abe) +#[rustc_dump_ptrauth_discriminator(ptrauth_encoding, ptrauth_hash)] +extern "C" fn g1_e(_: Box) {} // expect: "FvPE" 10942 (0x2abe) +#[rustc_dump_ptrauth_discriminator(ptrauth_encoding, ptrauth_hash)] +extern "C" fn g1_f(_: NonNull) {} // expect: "FvPE": 10942 (0x2abe) +#[rustc_dump_ptrauth_discriminator(ptrauth_encoding, ptrauth_hash)] +extern "C" fn g1_g(_: *const SomeStruct) {} // expect: "FvPE" 10942 (0x2abe) + +struct MyAlloc; +unsafe impl Allocator for MyAlloc { + fn allocate(&self, layout: Layout) -> Result, AllocError> { + Global.allocate(layout) + } + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + unsafe { Global.deallocate(ptr, layout) } + } +} +// negative test for "specifically, only Box" +#[rustc_dump_ptrauth_discriminator(ptrauth_encoding, ptrauth_hash)] +extern "C" fn g1_box_alloc_neg(_: Box) {} // expect: "Fv3BoxE": 3916 (0xf4c) + +// "usize is ABI-compatible with the uN integer type of the same size, and +// likewise isize is ABI-compatible with the iN integer type of the same size. +// and +// "char is ABI-compatible with u32." +#[rustc_dump_ptrauth_discriminator(ptrauth_encoding, ptrauth_hash)] +extern "C" fn g2_a(_: i32) {} // expect: "FviE": 2712 (0xa98) +#[rustc_dump_ptrauth_discriminator(ptrauth_encoding, ptrauth_hash)] +extern "C" fn g2_b(_: u64) {} // expect: "FviE": 2712 (0xa98) +#[rustc_dump_ptrauth_discriminator(ptrauth_encoding, ptrauth_hash)] +extern "C" fn g2_c(_: usize) {} // expect: "FviE": 2712 (0xa98) +#[rustc_dump_ptrauth_discriminator(ptrauth_encoding, ptrauth_hash)] +extern "C" fn g2_d(_: isize) {} // expect: "FviE": 2712 (0xa98) +#[rustc_dump_ptrauth_discriminator(ptrauth_encoding, ptrauth_hash)] +extern "C" fn g2_e(_: char) {} // expect: "FviE": 2712 (0xa98) +#[rustc_dump_ptrauth_discriminator(ptrauth_encoding, ptrauth_hash)] +extern "C" fn g2_f(_: bool) {} // expect: "FviE": 2712 (0xa98) + +// "Any two types with size 0 and alignment 1 are ABI-compatible." +struct Unit; +enum OneVariant { + A, +} +#[rustc_dump_ptrauth_discriminator(ptrauth_encoding, ptrauth_hash)] +extern "C" fn g3_a(_: ()) {} // expect: "FvvE": 61000 (0xee48) +#[rustc_dump_ptrauth_discriminator(ptrauth_encoding, ptrauth_hash)] +extern "C" fn g3_b(_: Unit) {} // expect: "FvvE": 61000 (0xee48) +#[rustc_dump_ptrauth_discriminator(ptrauth_encoding, ptrauth_hash)] +extern "C" fn g3_c(_: PhantomData) {} // expect: "FvvE": 61000 (0xee48) +#[rustc_dump_ptrauth_discriminator(ptrauth_encoding, ptrauth_hash)] +extern "C" fn g3_d(_: [u8; 0]) {} // expect: "FvvE": 61000 (0xee48) +#[rustc_dump_ptrauth_discriminator(ptrauth_encoding, ptrauth_hash)] +extern "C" fn g3_e(_: OneVariant) {} // expect: "FvvE": 61000 (0xee48) +// 1-ZST, not 4-ZST, must not match +#[repr(align(4))] +struct AlignedMarker; +#[rustc_dump_ptrauth_discriminator(ptrauth_encoding, ptrauth_hash)] +extern "C" fn g3_neg(_: AlignedMarker) {} // expect: "Fv13AlignedMarkerE": 49590 (0xc1b6) + +// "A repr(transparent) type T is ABI-compatible with its unique non-trivial +// field, i.e., the unique field that doesn’t have size 0 and alignment 1 (if +// there is such a field)." +#[repr(transparent)] +struct Wrapper(i32); +#[repr(transparent)] +struct WrapperWithZst(i32, PhantomData); +#[rustc_dump_ptrauth_discriminator(ptrauth_encoding, ptrauth_hash)] +extern "C" fn g4_a(_: i32) {} // expect: "FviE": 2712 (0xa98) +#[rustc_dump_ptrauth_discriminator(ptrauth_encoding, ptrauth_hash)] +extern "C" fn g4_b(_: Wrapper) {} // expect: "FviE": 2712 (0xa98) +#[rustc_dump_ptrauth_discriminator(ptrauth_encoding, ptrauth_hash)] +extern "C" fn g4_c(_: WrapperWithZst) {} // expect: "FviE": 2712 (0xa98) +// i32 wrapped in a non-transparent struct +struct NotTransparent(i32); +#[rustc_dump_ptrauth_discriminator(ptrauth_encoding, ptrauth_hash)] +extern "C" fn g4_neg(_: NotTransparent) {} // expect: "Fv14NotTransparentE": 37756 (0x937c) + +// "i32 is ABI-compatible with NonZero, and similar for all other integer +// types." +#[rustc_dump_ptrauth_discriminator(ptrauth_encoding, ptrauth_hash)] +extern "C" fn g5_a(_: i32) {} // expect: "FviE": 2712 (0xa98) +#[rustc_dump_ptrauth_discriminator(ptrauth_encoding, ptrauth_hash)] +extern "C" fn g5_b(_: NonZero) {} // expect: "FviE": 2712 (0xa98) +#[rustc_dump_ptrauth_discriminator(ptrauth_encoding, ptrauth_hash)] +extern "C" fn g5_c(_: i16) {} // expect: "FviE": 2712 (0xa98) +#[rustc_dump_ptrauth_discriminator(ptrauth_encoding, ptrauth_hash)] +extern "C" fn g5_d(_: NonZero) {} // expect: "FviE": 2712 (0xa98) + +// If T is guaranteed to be subject to the null pointer optimization, and E is +// an enum satisfying the following requirements, then T and E are +// ABI-compatible. Such an enum E is called “option-like”. +// * The enum E uses the Rust representation, and is not modified by the align +// or packed representation modifiers. +// * The enum E has exactly two variants. +// * One variant has exactly one field, of type T. +// * All fields of the other variant are zero-sized with 1-byte alignment. +enum MyOption { + None, + Some(T), +} +#[rustc_dump_ptrauth_discriminator(ptrauth_encoding, ptrauth_hash)] +extern "C" fn g6_ref_a(_: &i32) {} // expect: "FvPE": 10942 (0x2abe) +#[rustc_dump_ptrauth_discriminator(ptrauth_encoding, ptrauth_hash)] +extern "C" fn g6_ref_b(_: Option<&i32>) {} // expect: "FvPE": 10942 (0x2abe) + +#[rustc_dump_ptrauth_discriminator(ptrauth_encoding, ptrauth_hash)] +extern "C" fn g6_fn_a(_: fn()) {} // expect: "FvPE": 10942 (0x2abe) +#[rustc_dump_ptrauth_discriminator(ptrauth_encoding, ptrauth_hash)] +extern "C" fn g6_fn_b(_: Option) {} // expect: "FvPE": 10942 (0x2abe) + +#[rustc_dump_ptrauth_discriminator(ptrauth_encoding, ptrauth_hash)] +extern "C" fn g6_nn_a(_: NonNull) {} // expect: "FvPE": 10942 (0x2abe) +#[rustc_dump_ptrauth_discriminator(ptrauth_encoding, ptrauth_hash)] +extern "C" fn g6_nn_b(_: Option>) {} // expect: "FvPE": 10942 (0x2abe) +#[rustc_dump_ptrauth_discriminator(ptrauth_encoding, ptrauth_hash)] +extern "C" fn g6_nn_c(_: MyOption>) {} // expect: "FvPE": 10942 (0x2abe) + +#[rustc_dump_ptrauth_discriminator(ptrauth_encoding, ptrauth_hash)] +extern "C" fn g6_box_a(_: Box) {} // expect: "FvPE": 10942 (0x2abe) +#[rustc_dump_ptrauth_discriminator(ptrauth_encoding, ptrauth_hash)] +extern "C" fn g6_box_b(_: Option>) {} // expect: "FvPE": 10942 (0x2abe) +// matches g2/g4/g5 ("FviE": 2712 (0xa98)), NOT g6_ref/fn/nn/box ("FvPE": 10942 +// (0x2abe)) +#[rustc_dump_ptrauth_discriminator(ptrauth_encoding, ptrauth_hash)] +extern "C" fn g6_nz_a(_: NonZero) {} // expect: "FviE": 2712 (0xa98) +#[rustc_dump_ptrauth_discriminator(ptrauth_encoding, ptrauth_hash)] +extern "C" fn g6_nz_b(_: Option>) {} // expect: "FviE": 2712 (0xa98) + +// Option has no niche to exploit, NPO is not happening. +// Carries a real discriminant, must NOT match plain i32. +#[rustc_dump_ptrauth_discriminator(ptrauth_encoding, ptrauth_hash)] +extern "C" fn g6_neg(_: Option) {} // expect: "Fv6OptionE": 20395 (0x4fab) + +// Niche field and an extra field. Must NOT fold to NonZero (the second +// field changes the ABI) +enum WithExtraField { + A(NonZero, i32), + B, +} +#[rustc_dump_ptrauth_discriminator(ptrauth_encoding, ptrauth_hash)] +extern "C" fn g6_multifield_neg(_: WithExtraField) {} // expect: "Fv14WithExtraFieldE": 34575 (0x870f) + +// More than 2 variants sharing one niche field's spare values. +enum ThreeVariants { + A(bool), + B, + C, +} +#[rustc_dump_ptrauth_discriminator(ptrauth_encoding, ptrauth_hash)] +extern "C" fn g6_arity_neg(_: ThreeVariants) {} // expect: "Fv13ThreeVariantsE": 9871 (0x268f) + // +// "Any two fn (function pointer) types are ABI-compatible with each other if +// they have the same ABI string or the ABI string only differs in a trailing +// -unwind, independent of the rest of their signature." +// +// This is only true for the first part of the rule, if signature differs, the +// discriminator *must* differ (unless it the function pointer is used as an +// argument to a different function, in which case it is encoded as any other +// pointer like type: `P`). +#[rustc_dump_ptrauth_discriminator(ptrauth_encoding, ptrauth_hash)] +extern "C" fn g7_a(_: i32) {} // expect: "FviE": 2712 (0xa98) +#[rustc_dump_ptrauth_discriminator(ptrauth_encoding, ptrauth_hash)] +extern "C-unwind" fn g7_b(_: i32) {} // expect: "FviE": 2712 (0xa98) diff --git a/tests/ui/ptrauth/discriminator-abi-compat-encoder-and-hash.stderr b/tests/ui/ptrauth/discriminator-abi-compat-encoder-and-hash.stderr new file mode 100644 index 0000000000000..f5e84015d7799 --- /dev/null +++ b/tests/ui/ptrauth/discriminator-abi-compat-encoder-and-hash.stderr @@ -0,0 +1,530 @@ +error: ptrauth discriminator encoding: "FvPE" + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:47:1 + | +LL | extern "C" fn g1_a(_: *const i32) {} // expect: "FvPE": 10942 (0x2abe) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator hash: 10942 (0x2abe) + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:47:1 + | +LL | extern "C" fn g1_a(_: *const i32) {} // expect: "FvPE": 10942 (0x2abe) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator encoding: "FvPE" + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:49:1 + | +LL | extern "C" fn g1_b(_: *mut i32) {} // expect: "FvPE": 10942 (0x2abe) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator hash: 10942 (0x2abe) + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:49:1 + | +LL | extern "C" fn g1_b(_: *mut i32) {} // expect: "FvPE": 10942 (0x2abe) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator encoding: "FvPE" + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:51:1 + | +LL | extern "C" fn g1_c(_: &i32) {} // expect: "FvPE": 10942 (0x2abe) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator hash: 10942 (0x2abe) + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:51:1 + | +LL | extern "C" fn g1_c(_: &i32) {} // expect: "FvPE": 10942 (0x2abe) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator encoding: "FvPE" + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:53:1 + | +LL | extern "C" fn g1_d(_: &mut i32) {} // expect: "FvPE": 10942 (0x2abe) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator hash: 10942 (0x2abe) + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:53:1 + | +LL | extern "C" fn g1_d(_: &mut i32) {} // expect: "FvPE": 10942 (0x2abe) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator encoding: "FvPE" + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:55:1 + | +LL | extern "C" fn g1_e(_: Box) {} // expect: "FvPE" 10942 (0x2abe) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator hash: 10942 (0x2abe) + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:55:1 + | +LL | extern "C" fn g1_e(_: Box) {} // expect: "FvPE" 10942 (0x2abe) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator encoding: "FvPE" + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:57:1 + | +LL | extern "C" fn g1_f(_: NonNull) {} // expect: "FvPE": 10942 (0x2abe) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator hash: 10942 (0x2abe) + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:57:1 + | +LL | extern "C" fn g1_f(_: NonNull) {} // expect: "FvPE": 10942 (0x2abe) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator encoding: "FvPE" + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:59:1 + | +LL | extern "C" fn g1_g(_: *const SomeStruct) {} // expect: "FvPE" 10942 (0x2abe) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator hash: 10942 (0x2abe) + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:59:1 + | +LL | extern "C" fn g1_g(_: *const SomeStruct) {} // expect: "FvPE" 10942 (0x2abe) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator encoding: "Fv3BoxE" + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:72:1 + | +LL | extern "C" fn g1_box_alloc_neg(_: Box) {} // expect: "Fv3BoxE": 3916 (0xf4c) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator hash: 3916 (0xf4c) + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:72:1 + | +LL | extern "C" fn g1_box_alloc_neg(_: Box) {} // expect: "Fv3BoxE": 3916 (0xf4c) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator encoding: "FviE" + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:79:1 + | +LL | extern "C" fn g2_a(_: i32) {} // expect: "FviE": 2712 (0xa98) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator hash: 2712 (0xa98) + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:79:1 + | +LL | extern "C" fn g2_a(_: i32) {} // expect: "FviE": 2712 (0xa98) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator encoding: "FviE" + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:81:1 + | +LL | extern "C" fn g2_b(_: u64) {} // expect: "FviE": 2712 (0xa98) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator hash: 2712 (0xa98) + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:81:1 + | +LL | extern "C" fn g2_b(_: u64) {} // expect: "FviE": 2712 (0xa98) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator encoding: "FviE" + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:83:1 + | +LL | extern "C" fn g2_c(_: usize) {} // expect: "FviE": 2712 (0xa98) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator hash: 2712 (0xa98) + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:83:1 + | +LL | extern "C" fn g2_c(_: usize) {} // expect: "FviE": 2712 (0xa98) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator encoding: "FviE" + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:85:1 + | +LL | extern "C" fn g2_d(_: isize) {} // expect: "FviE": 2712 (0xa98) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator hash: 2712 (0xa98) + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:85:1 + | +LL | extern "C" fn g2_d(_: isize) {} // expect: "FviE": 2712 (0xa98) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator encoding: "FviE" + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:87:1 + | +LL | extern "C" fn g2_e(_: char) {} // expect: "FviE": 2712 (0xa98) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator hash: 2712 (0xa98) + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:87:1 + | +LL | extern "C" fn g2_e(_: char) {} // expect: "FviE": 2712 (0xa98) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator encoding: "FviE" + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:89:1 + | +LL | extern "C" fn g2_f(_: bool) {} // expect: "FviE": 2712 (0xa98) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator hash: 2712 (0xa98) + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:89:1 + | +LL | extern "C" fn g2_f(_: bool) {} // expect: "FviE": 2712 (0xa98) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator encoding: "FvvE" + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:97:1 + | +LL | extern "C" fn g3_a(_: ()) {} // expect: "FvvE": 61000 (0xee48) + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator hash: 61000 (0xee48) + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:97:1 + | +LL | extern "C" fn g3_a(_: ()) {} // expect: "FvvE": 61000 (0xee48) + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator encoding: "FvvE" + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:99:1 + | +LL | extern "C" fn g3_b(_: Unit) {} // expect: "FvvE": 61000 (0xee48) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator hash: 61000 (0xee48) + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:99:1 + | +LL | extern "C" fn g3_b(_: Unit) {} // expect: "FvvE": 61000 (0xee48) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator encoding: "FvvE" + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:101:1 + | +LL | extern "C" fn g3_c(_: PhantomData) {} // expect: "FvvE": 61000 (0xee48) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator hash: 61000 (0xee48) + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:101:1 + | +LL | extern "C" fn g3_c(_: PhantomData) {} // expect: "FvvE": 61000 (0xee48) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator encoding: "FvvE" + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:103:1 + | +LL | extern "C" fn g3_d(_: [u8; 0]) {} // expect: "FvvE": 61000 (0xee48) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator hash: 61000 (0xee48) + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:103:1 + | +LL | extern "C" fn g3_d(_: [u8; 0]) {} // expect: "FvvE": 61000 (0xee48) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator encoding: "FvvE" + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:105:1 + | +LL | extern "C" fn g3_e(_: OneVariant) {} // expect: "FvvE": 61000 (0xee48) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator hash: 61000 (0xee48) + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:105:1 + | +LL | extern "C" fn g3_e(_: OneVariant) {} // expect: "FvvE": 61000 (0xee48) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator encoding: "Fv13AlignedMarkerE" + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:110:1 + | +LL | extern "C" fn g3_neg(_: AlignedMarker) {} // expect: "Fv13AlignedMarkerE": 49590 (0xc1b6) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator hash: 49590 (0xc1b6) + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:110:1 + | +LL | extern "C" fn g3_neg(_: AlignedMarker) {} // expect: "Fv13AlignedMarkerE": 49590 (0xc1b6) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator encoding: "FviE" + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:120:1 + | +LL | extern "C" fn g4_a(_: i32) {} // expect: "FviE": 2712 (0xa98) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator hash: 2712 (0xa98) + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:120:1 + | +LL | extern "C" fn g4_a(_: i32) {} // expect: "FviE": 2712 (0xa98) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator encoding: "FviE" + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:122:1 + | +LL | extern "C" fn g4_b(_: Wrapper) {} // expect: "FviE": 2712 (0xa98) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator hash: 2712 (0xa98) + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:122:1 + | +LL | extern "C" fn g4_b(_: Wrapper) {} // expect: "FviE": 2712 (0xa98) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator encoding: "FviE" + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:124:1 + | +LL | extern "C" fn g4_c(_: WrapperWithZst) {} // expect: "FviE": 2712 (0xa98) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator hash: 2712 (0xa98) + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:124:1 + | +LL | extern "C" fn g4_c(_: WrapperWithZst) {} // expect: "FviE": 2712 (0xa98) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator encoding: "Fv14NotTransparentE" + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:128:1 + | +LL | extern "C" fn g4_neg(_: NotTransparent) {} // expect: "Fv14NotTransparentE": 37756 (0x937c) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator hash: 37756 (0x937c) + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:128:1 + | +LL | extern "C" fn g4_neg(_: NotTransparent) {} // expect: "Fv14NotTransparentE": 37756 (0x937c) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator encoding: "FviE" + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:133:1 + | +LL | extern "C" fn g5_a(_: i32) {} // expect: "FviE": 2712 (0xa98) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator hash: 2712 (0xa98) + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:133:1 + | +LL | extern "C" fn g5_a(_: i32) {} // expect: "FviE": 2712 (0xa98) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator encoding: "FviE" + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:135:1 + | +LL | extern "C" fn g5_b(_: NonZero) {} // expect: "FviE": 2712 (0xa98) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator hash: 2712 (0xa98) + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:135:1 + | +LL | extern "C" fn g5_b(_: NonZero) {} // expect: "FviE": 2712 (0xa98) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator encoding: "FviE" + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:137:1 + | +LL | extern "C" fn g5_c(_: i16) {} // expect: "FviE": 2712 (0xa98) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator hash: 2712 (0xa98) + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:137:1 + | +LL | extern "C" fn g5_c(_: i16) {} // expect: "FviE": 2712 (0xa98) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator encoding: "FviE" + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:139:1 + | +LL | extern "C" fn g5_d(_: NonZero) {} // expect: "FviE": 2712 (0xa98) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator hash: 2712 (0xa98) + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:139:1 + | +LL | extern "C" fn g5_d(_: NonZero) {} // expect: "FviE": 2712 (0xa98) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator encoding: "FvPE" + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:154:1 + | +LL | extern "C" fn g6_ref_a(_: &i32) {} // expect: "FvPE": 10942 (0x2abe) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator hash: 10942 (0x2abe) + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:154:1 + | +LL | extern "C" fn g6_ref_a(_: &i32) {} // expect: "FvPE": 10942 (0x2abe) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator encoding: "FvPE" + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:156:1 + | +LL | extern "C" fn g6_ref_b(_: Option<&i32>) {} // expect: "FvPE": 10942 (0x2abe) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator hash: 10942 (0x2abe) + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:156:1 + | +LL | extern "C" fn g6_ref_b(_: Option<&i32>) {} // expect: "FvPE": 10942 (0x2abe) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator encoding: "FvPE" + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:159:1 + | +LL | extern "C" fn g6_fn_a(_: fn()) {} // expect: "FvPE": 10942 (0x2abe) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator hash: 10942 (0x2abe) + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:159:1 + | +LL | extern "C" fn g6_fn_a(_: fn()) {} // expect: "FvPE": 10942 (0x2abe) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator encoding: "FvPE" + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:161:1 + | +LL | extern "C" fn g6_fn_b(_: Option) {} // expect: "FvPE": 10942 (0x2abe) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator hash: 10942 (0x2abe) + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:161:1 + | +LL | extern "C" fn g6_fn_b(_: Option) {} // expect: "FvPE": 10942 (0x2abe) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator encoding: "FvPE" + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:164:1 + | +LL | extern "C" fn g6_nn_a(_: NonNull) {} // expect: "FvPE": 10942 (0x2abe) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator hash: 10942 (0x2abe) + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:164:1 + | +LL | extern "C" fn g6_nn_a(_: NonNull) {} // expect: "FvPE": 10942 (0x2abe) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator encoding: "FvPE" + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:166:1 + | +LL | extern "C" fn g6_nn_b(_: Option>) {} // expect: "FvPE": 10942 (0x2abe) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator hash: 10942 (0x2abe) + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:166:1 + | +LL | extern "C" fn g6_nn_b(_: Option>) {} // expect: "FvPE": 10942 (0x2abe) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator encoding: "FvPE" + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:168:1 + | +LL | extern "C" fn g6_nn_c(_: MyOption>) {} // expect: "FvPE": 10942 (0x2abe) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator hash: 10942 (0x2abe) + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:168:1 + | +LL | extern "C" fn g6_nn_c(_: MyOption>) {} // expect: "FvPE": 10942 (0x2abe) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator encoding: "FvPE" + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:171:1 + | +LL | extern "C" fn g6_box_a(_: Box) {} // expect: "FvPE": 10942 (0x2abe) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator hash: 10942 (0x2abe) + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:171:1 + | +LL | extern "C" fn g6_box_a(_: Box) {} // expect: "FvPE": 10942 (0x2abe) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator encoding: "FvPE" + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:173:1 + | +LL | extern "C" fn g6_box_b(_: Option>) {} // expect: "FvPE": 10942 (0x2abe) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator hash: 10942 (0x2abe) + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:173:1 + | +LL | extern "C" fn g6_box_b(_: Option>) {} // expect: "FvPE": 10942 (0x2abe) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator encoding: "FviE" + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:177:1 + | +LL | extern "C" fn g6_nz_a(_: NonZero) {} // expect: "FviE": 2712 (0xa98) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator hash: 2712 (0xa98) + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:177:1 + | +LL | extern "C" fn g6_nz_a(_: NonZero) {} // expect: "FviE": 2712 (0xa98) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator encoding: "FviE" + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:179:1 + | +LL | extern "C" fn g6_nz_b(_: Option>) {} // expect: "FviE": 2712 (0xa98) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator hash: 2712 (0xa98) + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:179:1 + | +LL | extern "C" fn g6_nz_b(_: Option>) {} // expect: "FviE": 2712 (0xa98) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator encoding: "Fv6OptionE" + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:184:1 + | +LL | extern "C" fn g6_neg(_: Option) {} // expect: "Fv6OptionE": 20395 (0x4fab) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator hash: 20395 (0x4fab) + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:184:1 + | +LL | extern "C" fn g6_neg(_: Option) {} // expect: "Fv6OptionE": 20395 (0x4fab) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator encoding: "Fv14WithExtraFieldE" + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:193:1 + | +LL | extern "C" fn g6_multifield_neg(_: WithExtraField) {} // expect: "Fv14WithExtraFieldE": 34575 (0x870f) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator hash: 34575 (0x870f) + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:193:1 + | +LL | extern "C" fn g6_multifield_neg(_: WithExtraField) {} // expect: "Fv14WithExtraFieldE": 34575 (0x870f) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator encoding: "Fv13ThreeVariantsE" + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:202:1 + | +LL | extern "C" fn g6_arity_neg(_: ThreeVariants) {} // expect: "Fv13ThreeVariantsE": 9871 (0x268f) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator hash: 9871 (0x268f) + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:202:1 + | +LL | extern "C" fn g6_arity_neg(_: ThreeVariants) {} // expect: "Fv13ThreeVariantsE": 9871 (0x268f) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator encoding: "FviE" + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:213:1 + | +LL | extern "C" fn g7_a(_: i32) {} // expect: "FviE": 2712 (0xa98) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator hash: 2712 (0xa98) + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:213:1 + | +LL | extern "C" fn g7_a(_: i32) {} // expect: "FviE": 2712 (0xa98) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator encoding: "FviE" + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:215:1 + | +LL | extern "C-unwind" fn g7_b(_: i32) {} // expect: "FviE": 2712 (0xa98) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: ptrauth discriminator hash: 2712 (0xa98) + --> $DIR/discriminator-abi-compat-encoder-and-hash.rs:215:1 + | +LL | extern "C-unwind" fn g7_b(_: i32) {} // expect: "FviE": 2712 (0xa98) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 88 previous errors +