From 0169aaea3152cc4c906aa2a4f7cfdf346c68b33a Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Fri, 13 Feb 2026 14:09:26 +0100 Subject: [PATCH 1/3] va_arg: fix potential misaligned load --- compiler/rustc_codegen_llvm/src/va_arg.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs index 19735a29dfb2..6f05872ac93e 100644 --- a/compiler/rustc_codegen_llvm/src/va_arg.rs +++ b/compiler/rustc_codegen_llvm/src/va_arg.rs @@ -69,7 +69,8 @@ fn emit_direct_ptr_va_arg<'ll, 'tcx>( { let adjusted_size = bx.cx().const_i32((slot_size.bytes() - size.bytes()) as i32); let adjusted = bx.inbounds_ptradd(addr, adjusted_size); - (adjusted, addr_align) + // We're in the middle of a slot now, so use the type's alignment, not the slot's. + (adjusted, align) } else { (addr, addr_align) } From 45f98b9aa703f9783807e2ec958e8ec6f38a98e4 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Fri, 13 Feb 2026 13:10:46 +0100 Subject: [PATCH 2/3] va_arg: remove unused argument --- compiler/rustc_codegen_llvm/src/va_arg.rs | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs index 6f05872ac93e..931f8bae1acd 100644 --- a/compiler/rustc_codegen_llvm/src/va_arg.rs +++ b/compiler/rustc_codegen_llvm/src/va_arg.rs @@ -11,7 +11,7 @@ use rustc_target::spec::{Arch, Env, LlvmAbi, RustcAbi}; use crate::builder::Builder; -use crate::llvm::{Type, Value}; +use crate::llvm::Value; use crate::type_of::LayoutLlvmExt; fn round_up_to_alignment<'ll>( @@ -27,12 +27,11 @@ fn round_pointer_up_to_alignment<'ll>( bx: &mut Builder<'_, 'll, '_>, addr: &'ll Value, align: Align, - ptr_ty: &'ll Type, ) -> &'ll Value { let ptr = bx.inbounds_ptradd(addr, bx.const_i32(align.bytes() as i32 - 1)); bx.call_intrinsic( "llvm.ptrmask", - &[ptr_ty, bx.type_i32()], + &[bx.type_ptr(), bx.type_i32()], &[ptr, bx.const_int(bx.isize_ty, -(align.bytes() as isize) as i64)], ) } @@ -53,7 +52,7 @@ fn emit_direct_ptr_va_arg<'ll, 'tcx>( let ptr = bx.load(va_list_ty, va_list_addr, ptr_align_abi); let (addr, addr_align) = if allow_higher_align && align > slot_size { - (round_pointer_up_to_alignment(bx, ptr, align, bx.type_ptr()), align) + (round_pointer_up_to_alignment(bx, ptr, align), align) } else { (ptr, slot_size) }; @@ -358,12 +357,8 @@ fn emit_powerpc_va_arg<'ll, 'tcx>( // Round up address of argument to alignment if layout.layout.align.abi > overflow_area_align { - overflow_area = round_pointer_up_to_alignment( - bx, - overflow_area, - layout.layout.align.abi, - bx.type_ptr(), - ); + overflow_area = + round_pointer_up_to_alignment(bx, overflow_area, layout.layout.align.abi); } let mem_addr = overflow_area; @@ -828,7 +823,7 @@ fn emit_hexagon_va_arg_musl<'ll, 'tcx>( } else { Align::from_bytes(4).unwrap() }; - let aligned_current = round_pointer_up_to_alignment(bx, current_ptr, arg_align, bx.type_ptr()); + let aligned_current = round_pointer_up_to_alignment(bx, current_ptr, arg_align); // Calculate next pointer position (following LLVM's logic) // Arguments <= 32 bits take 4 bytes, > 32 bits take 8 bytes @@ -850,8 +845,7 @@ fn emit_hexagon_va_arg_musl<'ll, 'tcx>( bx.switch_to_block(from_overflow); // Align overflow pointer using the same alignment rules - let aligned_overflow = - round_pointer_up_to_alignment(bx, overflow_ptr, arg_align, bx.type_ptr()); + let aligned_overflow = round_pointer_up_to_alignment(bx, overflow_ptr, arg_align); let overflow_value_addr = aligned_overflow; // Update overflow pointer - use the same size calculation @@ -891,7 +885,7 @@ fn emit_hexagon_va_arg_bare_metal<'ll, 'tcx>( let aligned_ptr = if ty_align.bytes() > 4 { // Ensure alignment is a power of 2 debug_assert!(ty_align.bytes().is_power_of_two(), "Alignment is not power of 2!"); - round_pointer_up_to_alignment(bx, current_ptr, ty_align, bx.type_ptr()) + round_pointer_up_to_alignment(bx, current_ptr, ty_align) } else { current_ptr }; From 5149a31515f2bb1ae9c1923acdc80b82531ad52b Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 22 Apr 2026 00:09:41 +0200 Subject: [PATCH 3/3] change `llvm.ptrmask` argument to `isize` we were saying that the type is i32, but would often provide an i64. That never failed so far, but starts failing (like, crashing LLVM) when working with 128-bit values that are 16-byte aligned. So, we may as well use the more robust approach now. --- compiler/rustc_codegen_llvm/src/va_arg.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs index 931f8bae1acd..be1733086c83 100644 --- a/compiler/rustc_codegen_llvm/src/va_arg.rs +++ b/compiler/rustc_codegen_llvm/src/va_arg.rs @@ -29,10 +29,12 @@ fn round_pointer_up_to_alignment<'ll>( align: Align, ) -> &'ll Value { let ptr = bx.inbounds_ptradd(addr, bx.const_i32(align.bytes() as i32 - 1)); + let pointer_width = bx.tcx().sess.target.pointer_width; + let mask = align.bytes().wrapping_neg() & (u64::MAX >> (64 - pointer_width)); bx.call_intrinsic( "llvm.ptrmask", - &[bx.type_ptr(), bx.type_i32()], - &[ptr, bx.const_int(bx.isize_ty, -(align.bytes() as isize) as i64)], + &[bx.type_ptr(), bx.type_isize()], + &[ptr, bx.const_usize(mask)], ) }