Skip to content

Commit 71a11a0

Browse files
committed
Fix transmute::<T, U> where T requires a bigger alignment than U
For transmute::<T, U> we simply pointercast the destination from a U pointer to a T pointer, without providing any alignment information, thus LLVM assumes that the destination is aligned to hold a value of type T, which is not necessarily true. This can lead to LLVM emitting machine instructions that assume said alignment, and thus cause aborts. To fix this, we need to provide the actual alignment to store_operand() and in turn to store() so they can set the proper alignment information on the stores and LLVM can emit the proper machine instructions. Fixes #32947
1 parent 82801b5 commit 71a11a0

File tree

11 files changed

+97
-65
lines changed

11 files changed

+97
-65
lines changed

src/librustc_trans/abi.rs

+3-6
Original file line numberDiff line numberDiff line change
@@ -248,11 +248,8 @@ impl ArgType {
248248
let can_store_through_cast_ptr = false;
249249
if can_store_through_cast_ptr {
250250
let cast_dst = bcx.pointercast(dst, ty.ptr_to());
251-
let store = bcx.store(val, cast_dst);
252251
let llalign = llalign_of_min(ccx, self.ty);
253-
unsafe {
254-
llvm::LLVMSetAlignment(store, llalign);
255-
}
252+
bcx.store(val, cast_dst, Some(llalign));
256253
} else {
257254
// The actual return type is a struct, but the ABI
258255
// adaptation code has cast it into some scalar type. The
@@ -273,7 +270,7 @@ impl ArgType {
273270
base::Lifetime::Start.call(bcx, llscratch);
274271

275272
// ...where we first store the value...
276-
bcx.store(val, llscratch);
273+
bcx.store(val, llscratch, None);
277274

278275
// ...and then memcpy it to the intended destination.
279276
base::call_memcpy(bcx,
@@ -289,7 +286,7 @@ impl ArgType {
289286
if self.original_ty == Type::i1(ccx) {
290287
val = bcx.zext(val, Type::i8(ccx));
291288
}
292-
bcx.store(val, dst);
289+
bcx.store(val, dst, None);
293290
}
294291
}
295292

src/librustc_trans/adt.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -443,11 +443,11 @@ pub fn trans_set_discr<'a, 'tcx>(
443443
layout::CEnum{ discr, min, max, .. } => {
444444
assert_discr_in_range(Disr(min), Disr(max), to);
445445
bcx.store(C_integral(Type::from_integer(bcx.ccx, discr), to.0, true),
446-
val);
446+
val, None);
447447
}
448448
layout::General{ discr, .. } => {
449449
bcx.store(C_integral(Type::from_integer(bcx.ccx, discr), to.0, true),
450-
bcx.struct_gep(val, 0));
450+
bcx.struct_gep(val, 0), None);
451451
}
452452
layout::Univariant { .. }
453453
| layout::UntaggedUnion { .. }
@@ -458,7 +458,7 @@ pub fn trans_set_discr<'a, 'tcx>(
458458
let nnty = compute_fields(bcx.ccx, t, nndiscr as usize, false)[0];
459459
if to.0 != nndiscr {
460460
let llptrty = type_of::sizing_type_of(bcx.ccx, nnty);
461-
bcx.store(C_null(llptrty), val);
461+
bcx.store(C_null(llptrty), val, None);
462462
}
463463
}
464464
layout::StructWrappedNullablePointer { nndiscr, ref discrfield, ref nonnull, .. } => {
@@ -476,7 +476,7 @@ pub fn trans_set_discr<'a, 'tcx>(
476476
let path = discrfield.iter().map(|&i| i as usize).collect::<Vec<_>>();
477477
let llptrptr = bcx.gepi(val, &path[..]);
478478
let llptrty = val_ty(llptrptr).element_type();
479-
bcx.store(C_null(llptrty), llptrptr);
479+
bcx.store(C_null(llptrty), llptrptr, None);
480480
}
481481
}
482482
}

src/librustc_trans/asm.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ pub fn trans_inline_asm<'a, 'tcx>(
105105
let outputs = ia.outputs.iter().zip(&outputs).filter(|&(ref o, _)| !o.is_indirect);
106106
for (i, (_, &(val, _))) in outputs.enumerate() {
107107
let v = if num_outputs == 1 { r } else { bcx.extract_value(r, i) };
108-
bcx.store(v, val);
108+
bcx.store(v, val, None);
109109
}
110110

111111
// Store expn_id in a metadata node so we can map LLVM errors

src/librustc_trans/base.rs

+13-18
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ pub fn coerce_unsized_into<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
290290
let src_f = adt::trans_field_ptr(bcx, src_ty, src, Disr(0), i);
291291
let dst_f = adt::trans_field_ptr(bcx, dst_ty, dst, Disr(0), i);
292292
if src_fty == dst_fty {
293-
memcpy_ty(bcx, dst_f, src_f, src_fty);
293+
memcpy_ty(bcx, dst_f, src_f, src_fty, None);
294294
} else {
295295
coerce_unsized_into(bcx, src_f, src_fty, dst_f, dst_fty);
296296
}
@@ -429,7 +429,7 @@ pub fn store_ty<'a, 'tcx>(cx: &BlockAndBuilder<'a, 'tcx>, v: ValueRef, dst: Valu
429429
let llextra = cx.extract_value(v, abi::FAT_PTR_EXTRA);
430430
store_fat_ptr(cx, lladdr, llextra, dst, t);
431431
} else {
432-
cx.store(from_immediate(cx, v), dst);
432+
cx.store(from_immediate(cx, v), dst, None);
433433
}
434434
}
435435

@@ -439,8 +439,8 @@ pub fn store_fat_ptr<'a, 'tcx>(cx: &BlockAndBuilder<'a, 'tcx>,
439439
dst: ValueRef,
440440
_ty: Ty<'tcx>) {
441441
// FIXME: emit metadata
442-
cx.store(data, get_dataptr(cx, dst));
443-
cx.store(extra, get_meta(cx, dst));
442+
cx.store(data, get_dataptr(cx, dst), None);
443+
cx.store(extra, get_meta(cx, dst), None);
444444
}
445445

446446
pub fn load_fat_ptr<'a, 'tcx>(
@@ -523,26 +523,21 @@ pub fn call_memcpy<'a, 'tcx>(b: &Builder<'a, 'tcx>,
523523
b.call(memcpy, &[dst_ptr, src_ptr, size, align, volatile], None);
524524
}
525525

526-
pub fn memcpy_ty<'a, 'tcx>(
527-
bcx: &BlockAndBuilder<'a, 'tcx>, dst: ValueRef, src: ValueRef, t: Ty<'tcx>
528-
) {
526+
pub fn memcpy_ty<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
527+
dst: ValueRef,
528+
src: ValueRef,
529+
t: Ty<'tcx>,
530+
align: Option<u32>) {
529531
let ccx = bcx.ccx;
530532

531533
if type_is_zero_size(ccx, t) {
532534
return;
533535
}
534536

535-
if t.is_structural() {
536-
let llty = type_of::type_of(ccx, t);
537-
let llsz = llsize_of(ccx, llty);
538-
let llalign = type_of::align_of(ccx, t);
539-
call_memcpy(bcx, dst, src, llsz, llalign as u32);
540-
} else if common::type_is_fat_ptr(bcx.ccx, t) {
541-
let (data, extra) = load_fat_ptr(bcx, src, t);
542-
store_fat_ptr(bcx, data, extra, dst, t);
543-
} else {
544-
store_ty(bcx, load_ty(bcx, src, t), dst, t);
545-
}
537+
let llty = type_of::type_of(ccx, t);
538+
let llsz = llsize_of(ccx, llty);
539+
let llalign = align.unwrap_or_else(|| type_of::align_of(ccx, t));
540+
call_memcpy(bcx, dst, src, llsz, llalign as u32);
546541
}
547542

548543
pub fn call_memset<'a, 'tcx>(b: &Builder<'a, 'tcx>,

src/librustc_trans/builder.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -512,13 +512,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
512512
value
513513
}
514514

515-
pub fn store(&self, val: ValueRef, ptr: ValueRef) -> ValueRef {
515+
pub fn store(&self, val: ValueRef, ptr: ValueRef, align: Option<u32>) -> ValueRef {
516516
debug!("Store {:?} -> {:?}", Value(val), Value(ptr));
517517
assert!(!self.llbuilder.is_null());
518518
self.count_insn("store");
519519
let ptr = self.check_store(val, ptr);
520520
unsafe {
521-
llvm::LLVMBuildStore(self.llbuilder, val, ptr)
521+
let store = llvm::LLVMBuildStore(self.llbuilder, val, ptr);
522+
if let Some(align) = align {
523+
llvm::LLVMSetAlignment(store, align as c_uint);
524+
}
525+
store
522526
}
523527
}
524528

src/librustc_trans/intrinsic.rs

+12-15
Original file line numberDiff line numberDiff line change
@@ -288,8 +288,8 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
288288
let val = bcx.call(llfn, &[llargs[0], llargs[1]], None);
289289
let result = bcx.extract_value(val, 0);
290290
let overflow = bcx.zext(bcx.extract_value(val, 1), Type::bool(ccx));
291-
bcx.store(result, bcx.struct_gep(llresult, 0));
292-
bcx.store(overflow, bcx.struct_gep(llresult, 1));
291+
bcx.store(result, bcx.struct_gep(llresult, 0), None);
292+
bcx.store(overflow, bcx.struct_gep(llresult, 1), None);
293293

294294
C_nil(bcx.ccx)
295295
},
@@ -407,8 +407,8 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
407407
failorder, weak);
408408
let result = bcx.extract_value(val, 0);
409409
let success = bcx.zext(bcx.extract_value(val, 1), Type::bool(bcx.ccx));
410-
bcx.store(result, bcx.struct_gep(llresult, 0));
411-
bcx.store(success, bcx.struct_gep(llresult, 1));
410+
bcx.store(result, bcx.struct_gep(llresult, 0), None);
411+
bcx.store(success, bcx.struct_gep(llresult, 1), None);
412412
} else {
413413
invalid_monomorphization(sty);
414414
}
@@ -613,7 +613,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
613613

614614
for i in 0..elems.len() {
615615
let val = bcx.extract_value(val, i);
616-
bcx.store(val, bcx.struct_gep(llresult, i));
616+
bcx.store(val, bcx.struct_gep(llresult, i), None);
617617
}
618618
C_nil(ccx)
619619
}
@@ -625,10 +625,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
625625
if val_ty(llval) != Type::void(ccx) && machine::llsize_of_alloc(ccx, val_ty(llval)) != 0 {
626626
if let Some(ty) = fn_ty.ret.cast {
627627
let ptr = bcx.pointercast(llresult, ty.ptr_to());
628-
let store = bcx.store(llval, ptr);
629-
unsafe {
630-
llvm::LLVMSetAlignment(store, type_of::align_of(ccx, ret_ty));
631-
}
628+
bcx.store(llval, ptr, Some(type_of::align_of(ccx, ret_ty)));
632629
} else {
633630
store_ty(bcx, llval, llresult, ret_ty);
634631
}
@@ -695,7 +692,7 @@ fn try_intrinsic<'a, 'tcx>(
695692
) {
696693
if bcx.sess().no_landing_pads() {
697694
bcx.call(func, &[data], None);
698-
bcx.store(C_null(Type::i8p(&bcx.ccx)), dest);
695+
bcx.store(C_null(Type::i8p(&bcx.ccx)), dest, None);
699696
} else if wants_msvc_seh(bcx.sess()) {
700697
trans_msvc_try(bcx, func, data, local_ptr, dest);
701698
} else {
@@ -789,8 +786,8 @@ fn trans_msvc_try<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
789786
let val1 = C_i32(ccx, 1);
790787
let arg2 = catchpad.load(catchpad.inbounds_gep(addr, &[val1]));
791788
let local_ptr = catchpad.bitcast(local_ptr, i64p);
792-
catchpad.store(arg1, local_ptr);
793-
catchpad.store(arg2, catchpad.inbounds_gep(local_ptr, &[val1]));
789+
catchpad.store(arg1, local_ptr, None);
790+
catchpad.store(arg2, catchpad.inbounds_gep(local_ptr, &[val1]), None);
794791
catchpad.catch_ret(tok, caught.llbb());
795792

796793
caught.ret(C_i32(ccx, 1));
@@ -799,7 +796,7 @@ fn trans_msvc_try<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
799796
// Note that no invoke is used here because by definition this function
800797
// can't panic (that's what it's catching).
801798
let ret = bcx.call(llfn, &[func, data, local_ptr], None);
802-
bcx.store(ret, dest);
799+
bcx.store(ret, dest, None);
803800
}
804801

805802
// Definition of the standard "try" function for Rust using the GNU-like model
@@ -858,14 +855,14 @@ fn trans_gnu_try<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
858855
let vals = catch.landing_pad(lpad_ty, bcx.ccx.eh_personality(), 1, catch.fcx().llfn);
859856
catch.add_clause(vals, C_null(Type::i8p(ccx)));
860857
let ptr = catch.extract_value(vals, 0);
861-
catch.store(ptr, catch.bitcast(local_ptr, Type::i8p(ccx).ptr_to()));
858+
catch.store(ptr, catch.bitcast(local_ptr, Type::i8p(ccx).ptr_to()), None);
862859
catch.ret(C_i32(ccx, 1));
863860
});
864861

865862
// Note that no invoke is used here because by definition this function
866863
// can't panic (that's what it's catching).
867864
let ret = bcx.call(llfn, &[func, data, local_ptr], None);
868-
bcx.store(ret, dest);
865+
bcx.store(ret, dest, None);
869866
}
870867

871868
// Helper function to give a Block to a closure to translate a shim function.

src/librustc_trans/mir/block.rs

+11-6
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,16 @@ use consts;
2323
use Disr;
2424
use machine::{llalign_of_min, llbitsize_of_real};
2525
use meth;
26-
use type_of;
26+
use type_of::{self, align_of};
2727
use glue;
2828
use type_::Type;
2929

3030
use rustc_data_structures::indexed_vec::IndexVec;
3131
use rustc_data_structures::fx::FxHashMap;
3232
use syntax::symbol::Symbol;
3333

34+
use std::cmp;
35+
3436
use super::{MirContext, LocalRef};
3537
use super::analyze::CleanupKind;
3638
use super::constant::Const;
@@ -207,7 +209,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
207209
let llslot = match op.val {
208210
Immediate(_) | Pair(..) => {
209211
let llscratch = bcx.fcx().alloca(ret.original_ty, "ret");
210-
self.store_operand(&bcx, llscratch, op);
212+
self.store_operand(&bcx, llscratch, op, None);
211213
llscratch
212214
}
213215
Ref(llval) => llval
@@ -426,7 +428,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
426428
// The first argument is a thin destination pointer.
427429
let llptr = self.trans_operand(&bcx, &args[0]).immediate();
428430
let val = self.trans_operand(&bcx, &args[1]);
429-
self.store_operand(&bcx, llptr, val);
431+
self.store_operand(&bcx, llptr, val, None);
430432
funclet_br(self, bcx, target);
431433
return;
432434
}
@@ -659,7 +661,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
659661
Immediate(_) | Pair(..) => {
660662
if arg.is_indirect() || arg.cast.is_some() {
661663
let llscratch = bcx.fcx().alloca(arg.original_ty, "arg");
662-
self.store_operand(bcx, llscratch, op);
664+
self.store_operand(bcx, llscratch, op, None);
663665
(llscratch, true)
664666
} else {
665667
(op.pack_if_pair(bcx).immediate(), false)
@@ -801,7 +803,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
801803
let llretval = bcx.landing_pad(llretty, llpersonality, 1, self.fcx.llfn);
802804
bcx.set_cleanup(llretval);
803805
let slot = self.get_personality_slot(&bcx);
804-
bcx.store(llretval, slot);
806+
bcx.store(llretval, slot, None);
805807
bcx.br(target.llbb());
806808
bcx.llbb()
807809
}
@@ -886,7 +888,10 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
886888

887889
let llty = type_of::type_of(bcx.ccx, val.ty);
888890
let cast_ptr = bcx.pointercast(dst.llval, llty.ptr_to());
889-
self.store_operand(bcx, cast_ptr, val);
891+
let in_type = val.ty;
892+
let out_type = dst.ty.to_ty(bcx.tcx());;
893+
let llalign = cmp::min(align_of(bcx.ccx, in_type), align_of(bcx.ccx, out_type));
894+
self.store_operand(bcx, cast_ptr, val, Some(llalign));
890895
}
891896

892897

src/librustc_trans/mir/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -514,7 +514,7 @@ fn arg_local_refs<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
514514
// environment into its components so it ends up out of bounds.
515515
let env_ptr = if !env_ref {
516516
let alloc = bcx.fcx().alloca(common::val_ty(llval), "__debuginfo_env_ptr");
517-
bcx.store(llval, alloc);
517+
bcx.store(llval, alloc, None);
518518
alloc
519519
} else {
520520
llval

src/librustc_trans/mir/operand.rs

+9-6
Original file line numberDiff line numberDiff line change
@@ -244,21 +244,24 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
244244
pub fn store_operand(&mut self,
245245
bcx: &BlockAndBuilder<'a, 'tcx>,
246246
lldest: ValueRef,
247-
operand: OperandRef<'tcx>) {
248-
debug!("store_operand: operand={:?}", operand);
247+
operand: OperandRef<'tcx>,
248+
align: Option<u32>) {
249+
debug!("store_operand: operand={:?}, align={:?}", operand, align);
249250
// Avoid generating stores of zero-sized values, because the only way to have a zero-sized
250251
// value is through `undef`, and store itself is useless.
251252
if common::type_is_zero_size(bcx.ccx, operand.ty) {
252253
return;
253254
}
254255
match operand.val {
255-
OperandValue::Ref(r) => base::memcpy_ty(bcx, lldest, r, operand.ty),
256-
OperandValue::Immediate(s) => base::store_ty(bcx, s, lldest, operand.ty),
256+
OperandValue::Ref(r) => base::memcpy_ty(bcx, lldest, r, operand.ty, align),
257+
OperandValue::Immediate(s) => {
258+
bcx.store(base::from_immediate(bcx, s), lldest, align);
259+
}
257260
OperandValue::Pair(a, b) => {
258261
let a = base::from_immediate(bcx, a);
259262
let b = base::from_immediate(bcx, b);
260-
bcx.store(a, bcx.struct_gep(lldest, 0));
261-
bcx.store(b, bcx.struct_gep(lldest, 1));
263+
bcx.store(a, bcx.struct_gep(lldest, 0), align);
264+
bcx.store(b, bcx.struct_gep(lldest, 1), align);
262265
}
263266
}
264267
}

0 commit comments

Comments
 (0)