Skip to content

Commit 4c27a6c

Browse files
committed
Auto merge of #154972 - chorman0773:return_address, r=<try>
Implement `core::arch::return_address` and tests try-job: x86_64-gnu-aux
2 parents 44860d3 + 706d098 commit 4c27a6c

8 files changed

Lines changed: 81 additions & 1 deletion

File tree

compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1523,6 +1523,12 @@ fn codegen_regular_intrinsic_call<'tcx>(
15231523
fx.bcx.set_cold_block(fx.bcx.current_block().unwrap());
15241524
}
15251525

1526+
sym::return_address => {
1527+
let val = fx.bcx.ins().get_return_address(fx.pointer_type);
1528+
let val = CValue::by_val(val, ret.layout());
1529+
ret.write_cvalue(fx, val);
1530+
}
1531+
15261532
// Unimplemented intrinsics must have a fallback body. The fallback body is obtained
15271533
// by converting the `InstanceKind::Intrinsic` to an `InstanceKind::Item`.
15281534
_ => {

compiler/rustc_codegen_llvm/src/intrinsic.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -838,6 +838,22 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
838838
}
839839
}
840840

841+
sym::return_address => {
842+
match self.sess().target.arch {
843+
// Expand this list as needed
844+
| Arch::Wasm32
845+
| Arch::Wasm64 => {
846+
let ty = self.type_ptr();
847+
self.const_null(ty)
848+
}
849+
_ => {
850+
let ty = self.type_ix(32);
851+
let val = self.const_int(ty, 0);
852+
self.call_intrinsic("llvm.returnaddress", &[], &[val])
853+
}
854+
}
855+
}
856+
841857
_ => {
842858
debug!("unknown intrinsic '{}' -- falling back to default body", name);
843859
// Call the fallback body instead of generating the intrinsic code

compiler/rustc_codegen_ssa/src/mir/intrinsic.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
121121
| sym::contract_checks
122122
| sym::atomic_fence
123123
| sym::atomic_singlethreadfence
124-
| sym::caller_location => {}
124+
| sym::caller_location
125+
| sym::return_address => {}
125126
_ => {
126127
span_bug!(
127128
span,

compiler/rustc_hir_analysis/src/check/intrinsic.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hi
180180
| sym::ptr_guaranteed_cmp
181181
| sym::ptr_mask
182182
| sym::ptr_metadata
183+
| sym::return_address
183184
| sym::rotate_left
184185
| sym::rotate_right
185186
| sym::round_ties_even_f16
@@ -803,6 +804,8 @@ pub(crate) fn check_intrinsic_type(
803804
| sym::atomic_xor => (2, 1, vec![Ty::new_mut_ptr(tcx, param(0)), param(1)], param(0)),
804805
sym::atomic_fence | sym::atomic_singlethreadfence => (0, 1, Vec::new(), tcx.types.unit),
805806

807+
sym::return_address => (0, 0, vec![], Ty::new_imm_ptr(tcx, tcx.types.unit)),
808+
806809
other => {
807810
tcx.dcx().emit_err(UnrecognizedIntrinsicFunction { span, name: other });
808811
return;

compiler/rustc_span/src/symbol.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1660,6 +1660,7 @@ symbols! {
16601660
residual,
16611661
result,
16621662
result_ffi_guarantees,
1663+
return_address,
16631664
return_position_impl_trait_in_trait,
16641665
return_type_notation,
16651666
riscv32,

library/core/src/arch.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,31 @@ pub macro global_asm("assembly template", $(operands,)* $(options($(option),*))?
7676
pub fn breakpoint() {
7777
core::intrinsics::breakpoint();
7878
}
79+
80+
/// The `core::arch::return_address!()` macro returns a pointer with an address that corresponds to the caller of the function that invoked the `return_address!()` macro.
81+
/// The pointer has no provenance, as if created by `core::ptr::without_provenance`. It cannot be used to read memory (other than ZSTs).
82+
///
83+
/// The value returned by the macro depends highly on the architecture and compiler (including any options set).
84+
/// In particular, it is allowed to be wrong (particularly if inlining is involved), or even contain a nonsense value.
85+
/// The result of this macro must not be relied upon for soundness or correctness, only for debugging purposes.
86+
///
87+
/// As a best effort, if a useful value cannot be determined (for example, due to limitations on the current codegen),
88+
/// this macro tries to return a null pointer instead of nonsense (this cannot be relied upon for correctness, however).
89+
///
90+
/// Formally, this function returns a pointer with a non-deterministic address and no provenance.
91+
///
92+
/// This is equivalent to the gcc `__builtin_return_address(0)` intrinsic (other forms of the intrinsic are not supported).
93+
/// Because the operation can be always performed by the compiler without crashing or causing undefined behaviour, invoking the macro is a safe operation.
94+
///
95+
/// ## Example
96+
/// ```
97+
/// #![feature(return_address)]
98+
/// # #[cfg(not(miri))] // FIXME: Figure out how to make miri work before stabilizing this macro
99+
/// # {
100+
/// let addr = core::arch::return_address!();
101+
/// println!("Caller is {addr:p}");
102+
/// # }
103+
/// ```
104+
#[unstable(feature = "return_address", issue = "154966")]
105+
#[allow_internal_unstable(core_intrinsics)]
106+
pub macro return_address() {{ core::intrinsics::return_address() }}

library/core/src/intrinsics/mod.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3589,3 +3589,16 @@ pub const fn va_copy<'f>(src: &VaList<'f>) -> VaList<'f> {
35893589
pub const unsafe fn va_end(ap: &mut VaList<'_>) {
35903590
/* deliberately does nothing */
35913591
}
3592+
3593+
/// Returns the return address of the caller function (after inlining) in a best-effort manner or a null pointer if it is not supported on the current backend.
3594+
/// Returning an accurate value is a quality-of-implementation concern, but no hard guarantees are
3595+
/// made about the return value: formally, the intrinsic non-deterministically returns
3596+
/// an arbitrary pointer without provenance.
3597+
///
3598+
/// Note that unlike most intrinsics, this is safe to call. This is because it only finds the return address of the immediate caller, which is guaranteed to be possible.
3599+
/// Other forms of the corresponding gcc or llvm intrinsic (which can have wildly unpredictable results or even crash at runtime) are not exposed.
3600+
#[rustc_intrinsic]
3601+
#[rustc_nounwind]
3602+
pub fn return_address() -> *const () {
3603+
core::ptr::null()
3604+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//@ ignore-wasm
2+
3+
#![crate_type = "lib"]
4+
#![feature(core_intrinsics, return_address)]
5+
6+
// CHECK-LABEL: @call_return_address_intrinsic
7+
#[no_mangle]
8+
#[inline(never)]
9+
pub fn call_return_address_intrinsic() -> *const () {
10+
// CHECK: call ptr @llvm.returnaddress(i32 0)
11+
core::intrinsics::return_address()
12+
}

0 commit comments

Comments
 (0)