Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions compiler/rustc_codegen_gcc/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1850,6 +1850,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> {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_gcc/src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> {
cv: Scalar,
layout: abi::Scalar,
ty: Type<'gcc>,
_schema: Option<&PointerAuthSchema>,
_ptrauth_schema: Option<PointerAuthSchema>,
) -> RValue<'gcc> {
let bitsize = if layout.is_bool() { 1 } else { layout.size(self).bits() };
match cv {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_gcc/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,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<PointerAuthSchema>,
) -> RValue<'gcc> {
let func_name = self.tcx.symbol_name(instance).name;

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_codegen_gcc/src/int.rs
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
fixed_count: 3,
conv: CanonAbi::C,
can_unwind: false,
ptrauth_discriminator: None,
};
fn_abi.adjust_for_foreign_abi(self.cx, ExternAbi::C { unwind: false });

Expand Down
33 changes: 31 additions & 2 deletions compiler/rustc_codegen_llvm/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1553,6 +1553,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, '_> {
Expand Down Expand Up @@ -2171,8 +2195,13 @@ 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: <https://github.com/rust-lang/rust/issues/152532>
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 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",
&[self.const_u32(key), self.const_u64(discriminator)],
Expand Down
23 changes: 13 additions & 10 deletions compiler/rustc_codegen_llvm/src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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) => {
Expand All @@ -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,
)
}

/*
Expand Down Expand Up @@ -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<PointerAuthSchema>,
) -> 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));
Expand Down Expand Up @@ -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<PointerAuthSchema>,
) -> &'ll Value {
let bitsize = if layout.is_bool() { 1 } else { layout.size(self).bits() };
match cv {
Expand All @@ -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());
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_codegen_llvm/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -938,7 +938,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<PointerAuthSchema>,
) -> &'ll Value {
// When pointer authentication metadata is provided, `get_fn_addr` will
// attempt to sign the pointer using LLVM's `ConstPtrAuth` constant
Expand All @@ -953,7 +953,7 @@ impl<'ll, 'tcx> MiscCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
// <https://github.com/rust-lang/rust/issues/152532>, 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,
}
Expand Down
9 changes: 9 additions & 0 deletions compiler/rustc_codegen_ssa/src/traits/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -667,4 +667,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;
}
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_ssa/src/traits/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ pub trait ConstCodegenMethods: BackendTypes {
cv: Scalar,
layout: abi::Scalar,
llty: Self::Type,
schema: Option<&PointerAuthSchema>,
ptrauth_schema: Option<PointerAuthSchema>,
) -> Self::Value;

fn const_ptr_byte_offset(&self, val: Self::Value, offset: abi::Size) -> Self::Value;
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_codegen_ssa/src/traits/misc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<PointerAuthSchema>,
) -> Self::Value;
fn eh_personality(&self) -> Self::Function;
fn sess(&self) -> &Session;
Expand Down
72 changes: 45 additions & 27 deletions compiler/rustc_middle/src/ptrauth/discriminator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand Down Expand Up @@ -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<fn>` 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<fn>` 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.
Expand Down Expand Up @@ -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
Expand Down
6 changes: 0 additions & 6 deletions compiler/rustc_session/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -381,12 +381,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"
Expand Down
Loading
Loading