Skip to content

Commit

Permalink
Inline the function with_lvalue_ref into trans_transmute
Browse files Browse the repository at this point in the history
The function was a footgun because it created `undef` references to
ZSTs, which could cause trouble were they to leak to user code.
  • Loading branch information
arielb1 committed Feb 8, 2017
1 parent 7ce1f51 commit ffcfdcf
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 49 deletions.
36 changes: 30 additions & 6 deletions src/librustc_trans/mir/block.rs
Expand Up @@ -11,7 +11,7 @@
use llvm::{self, ValueRef, BasicBlockRef};
use rustc_const_eval::{ErrKind, ConstEvalErr, note_const_eval_err};
use rustc::middle::lang_items;
use rustc::ty::{self, layout};
use rustc::ty::{self, layout, TypeFoldable};
use rustc::mir;
use abi::{Abi, FnType, ArgType};
use adt;
Expand Down Expand Up @@ -435,10 +435,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {

if intrinsic == Some("transmute") {
let &(ref dest, target) = destination.as_ref().unwrap();
self.with_lvalue_ref(&bcx, dest, |this, dest| {
this.trans_transmute(&bcx, &args[0], dest);
});

self.trans_transmute(&bcx, &args[0], dest);
funclet_br(self, bcx, target);
return;
}
Expand Down Expand Up @@ -877,7 +874,34 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
}

fn trans_transmute(&mut self, bcx: &Builder<'a, 'tcx>,
src: &mir::Operand<'tcx>, dst: LvalueRef<'tcx>) {
src: &mir::Operand<'tcx>,
dst: &mir::Lvalue<'tcx>) {
if let mir::Lvalue::Local(index) = *dst {
match self.locals[index] {
LocalRef::Lvalue(lvalue) => self.trans_transmute_into(bcx, src, &lvalue),
LocalRef::Operand(None) => {
let lvalue_ty = self.monomorphized_lvalue_ty(dst);
assert!(!lvalue_ty.has_erasable_regions());
let lvalue = LvalueRef::alloca(bcx, lvalue_ty, "transmute_temp");
self.trans_transmute_into(bcx, src, &lvalue);
let op = self.trans_load(bcx, lvalue.llval, lvalue.alignment, lvalue_ty);
self.locals[index] = LocalRef::Operand(Some(op));
}
LocalRef::Operand(Some(_)) => {
let ty = self.monomorphized_lvalue_ty(dst);
assert!(common::type_is_zero_size(bcx.ccx, ty),
"assigning to initialized SSAtemp");
}
}
} else {
let dst = self.trans_lvalue(bcx, dst);
self.trans_transmute_into(bcx, src, &dst);
}
}

fn trans_transmute_into(&mut self, bcx: &Builder<'a, 'tcx>,
src: &mir::Operand<'tcx>,
dst: &LvalueRef<'tcx>) {
let mut val = self.trans_operand(bcx, src);
if let ty::TyFnDef(def_id, substs, _) = val.ty.sty {
let llouttype = type_of::type_of(bcx.ccx, dst.ty.to_ty(bcx.tcx()));
Expand Down
44 changes: 1 addition & 43 deletions src/librustc_trans/mir/lvalue.rs
Expand Up @@ -15,10 +15,9 @@ use rustc::mir::tcx::LvalueTy;
use rustc_data_structures::indexed_vec::Idx;
use adt;
use builder::Builder;
use common::{self, CrateContext, C_uint, C_undef};
use common::{self, CrateContext, C_uint};
use consts;
use machine;
use type_of::type_of;
use type_of;
use type_::Type;
use value::Value;
Expand Down Expand Up @@ -416,47 +415,6 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
result
}

// Perform an action using the given Lvalue.
// If the Lvalue is an empty LocalRef::Operand, then a temporary stack slot
// is created first, then used as an operand to update the Lvalue.
//
// FIXME: this is only called from transmute; please remove it.
pub fn with_lvalue_ref<F, U>(&mut self, bcx: &Builder<'a, 'tcx>,
lvalue: &mir::Lvalue<'tcx>, f: F) -> U
where F: FnOnce(&mut Self, LvalueRef<'tcx>) -> U
{
if let mir::Lvalue::Local(index) = *lvalue {
match self.locals[index] {
LocalRef::Lvalue(lvalue) => f(self, lvalue),
LocalRef::Operand(None) => {
let lvalue_ty = self.monomorphized_lvalue_ty(lvalue);
assert!(!lvalue_ty.has_erasable_regions());
let lvalue = LvalueRef::alloca(bcx, lvalue_ty, "lvalue_temp");
let ret = f(self, lvalue);
let op = self.trans_load(bcx, lvalue.llval, lvalue.alignment, lvalue_ty);
self.locals[index] = LocalRef::Operand(Some(op));
ret
}
LocalRef::Operand(Some(_)) => {
// See comments in LocalRef::new_operand as to why
// we always have Some in a ZST LocalRef::Operand.
let ty = self.monomorphized_lvalue_ty(lvalue);
if common::type_is_zero_size(bcx.ccx, ty) {
// Pass an undef pointer as no stores can actually occur.
let llptr = C_undef(type_of(bcx.ccx, ty).ptr_to());
f(self, LvalueRef::new_sized(llptr, LvalueTy::from_ty(ty),
Alignment::AbiAligned))
} else {
bug!("Lvalue local already set");
}
}
}
} else {
let lvalue = self.trans_lvalue(bcx, lvalue);
f(self, lvalue)
}
}

/// Adjust the bitwidth of an index since LLVM is less forgiving
/// than we are.
///
Expand Down

0 comments on commit ffcfdcf

Please sign in to comment.