Skip to content

Commit dd453a6

Browse files
committed
miri: protect Move() function arguments during the call
1 parent 3ea096a commit dd453a6

32 files changed

+607
-154
lines changed

compiler/rustc_const_eval/src/const_eval/machine.rs

+7-5
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use rustc_target::spec::abi::Abi as CallAbi;
2222

2323
use crate::errors::{LongRunning, LongRunningWarn};
2424
use crate::interpret::{
25-
self, compile_time_machine, AllocId, ConstAllocation, FnVal, Frame, ImmTy, InterpCx,
25+
self, compile_time_machine, AllocId, ConstAllocation, FnArg, FnVal, Frame, ImmTy, InterpCx,
2626
InterpResult, OpTy, PlaceTy, Pointer, Scalar,
2727
};
2828
use crate::{errors, fluent_generated as fluent};
@@ -201,7 +201,7 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
201201
fn hook_special_const_fn(
202202
&mut self,
203203
instance: ty::Instance<'tcx>,
204-
args: &[OpTy<'tcx>],
204+
args: &[FnArg<'tcx>],
205205
dest: &PlaceTy<'tcx>,
206206
ret: Option<mir::BasicBlock>,
207207
) -> InterpResult<'tcx, Option<ty::Instance<'tcx>>> {
@@ -210,6 +210,7 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
210210
if Some(def_id) == self.tcx.lang_items().panic_display()
211211
|| Some(def_id) == self.tcx.lang_items().begin_panic_fn()
212212
{
213+
let args = self.copy_fn_args(args)?;
213214
// &str or &&str
214215
assert!(args.len() == 1);
215216

@@ -236,8 +237,9 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
236237

237238
return Ok(Some(new_instance));
238239
} else if Some(def_id) == self.tcx.lang_items().align_offset_fn() {
240+
let args = self.copy_fn_args(args)?;
239241
// For align_offset, we replace the function call if the pointer has no address.
240-
match self.align_offset(instance, args, dest, ret)? {
242+
match self.align_offset(instance, &args, dest, ret)? {
241243
ControlFlow::Continue(()) => return Ok(Some(instance)),
242244
ControlFlow::Break(()) => return Ok(None),
243245
}
@@ -293,7 +295,7 @@ impl<'mir, 'tcx: 'mir> CompileTimeEvalContext<'mir, 'tcx> {
293295
self.eval_fn_call(
294296
FnVal::Instance(instance),
295297
(CallAbi::Rust, fn_abi),
296-
&[addr, align],
298+
&[FnArg::Copy(addr), FnArg::Copy(align)],
297299
/* with_caller_location = */ false,
298300
dest,
299301
ret,
@@ -427,7 +429,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
427429
ecx: &mut InterpCx<'mir, 'tcx, Self>,
428430
instance: ty::Instance<'tcx>,
429431
_abi: CallAbi,
430-
args: &[OpTy<'tcx>],
432+
args: &[FnArg<'tcx>],
431433
dest: &PlaceTy<'tcx>,
432434
ret: Option<mir::BasicBlock>,
433435
_unwind: mir::UnwindAction, // unwinding is not supported in consts

compiler/rustc_const_eval/src/interpret/eval_context.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -682,11 +682,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
682682
return_to_block: StackPopCleanup,
683683
) -> InterpResult<'tcx> {
684684
trace!("body: {:#?}", body);
685-
// Clobber previous return place contents, nobody is supposed to be able to see them any more
686-
// This also checks dereferenceable, but not align. We rely on all constructed places being
687-
// sufficiently aligned (in particular we rely on `deref_operand` checking alignment).
688-
self.write_uninit(return_place)?;
689-
// first push a stack frame so we have access to the local substs
685+
// First push a stack frame so we have access to the local substs
690686
let pre_frame = Frame {
691687
body,
692688
loc: Right(body.span), // Span used for errors caused during preamble.
@@ -805,6 +801,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
805801
throw_ub_custom!(fluent::const_eval_unwind_past_top);
806802
}
807803

804+
M::before_stack_pop(self, self.frame())?;
805+
808806
// Copy return value. Must of course happen *before* we deallocate the locals.
809807
let copy_ret_result = if !unwinding {
810808
let op = self

compiler/rustc_const_eval/src/interpret/intern.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use super::{
3030
use crate::const_eval;
3131
use crate::errors::{DanglingPtrInFinal, UnsupportedUntypedPointer};
3232

33-
pub trait CompileTimeMachine<'mir, 'tcx, T> = Machine<
33+
pub trait CompileTimeMachine<'mir, 'tcx: 'mir, T> = Machine<
3434
'mir,
3535
'tcx,
3636
MemoryKind = T,

compiler/rustc_const_eval/src/interpret/machine.rs

+25-5
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use rustc_target::spec::abi::Abi as CallAbi;
1717
use crate::const_eval::CheckAlignment;
1818

1919
use super::{
20-
AllocBytes, AllocId, AllocRange, Allocation, ConstAllocation, Frame, ImmTy, InterpCx,
20+
AllocBytes, AllocId, AllocRange, Allocation, ConstAllocation, FnArg, Frame, ImmTy, InterpCx,
2121
InterpResult, MemoryKind, OpTy, Operand, PlaceTy, Pointer, Provenance, Scalar,
2222
};
2323

@@ -84,7 +84,7 @@ pub trait AllocMap<K: Hash + Eq, V> {
8484

8585
/// Methods of this trait signifies a point where CTFE evaluation would fail
8686
/// and some use case dependent behaviour can instead be applied.
87-
pub trait Machine<'mir, 'tcx>: Sized {
87+
pub trait Machine<'mir, 'tcx: 'mir>: Sized {
8888
/// Additional memory kinds a machine wishes to distinguish from the builtin ones
8989
type MemoryKind: Debug + std::fmt::Display + MayLeak + Eq + 'static;
9090

@@ -182,7 +182,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
182182
ecx: &mut InterpCx<'mir, 'tcx, Self>,
183183
instance: ty::Instance<'tcx>,
184184
abi: CallAbi,
185-
args: &[OpTy<'tcx, Self::Provenance>],
185+
args: &[FnArg<'tcx, Self::Provenance>],
186186
destination: &PlaceTy<'tcx, Self::Provenance>,
187187
target: Option<mir::BasicBlock>,
188188
unwind: mir::UnwindAction,
@@ -194,7 +194,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
194194
ecx: &mut InterpCx<'mir, 'tcx, Self>,
195195
fn_val: Self::ExtraFnVal,
196196
abi: CallAbi,
197-
args: &[OpTy<'tcx, Self::Provenance>],
197+
args: &[FnArg<'tcx, Self::Provenance>],
198198
destination: &PlaceTy<'tcx, Self::Provenance>,
199199
target: Option<mir::BasicBlock>,
200200
unwind: mir::UnwindAction,
@@ -418,6 +418,18 @@ pub trait Machine<'mir, 'tcx>: Sized {
418418
Ok(())
419419
}
420420

421+
/// Called on places used for in-place function argument and return value handling.
422+
///
423+
/// These places need to be protected to make sure the program cannot tell whether the
424+
/// argument/return value was actually copied or passed in-place..
425+
fn protect_in_place_function_argument(
426+
ecx: &mut InterpCx<'mir, 'tcx, Self>,
427+
place: &PlaceTy<'tcx, Self::Provenance>,
428+
) -> InterpResult<'tcx> {
429+
// Without an aliasing model, all we can do is put `Uninit` into the place.
430+
ecx.write_uninit(place)
431+
}
432+
421433
/// Called immediately before a new stack frame gets pushed.
422434
fn init_frame_extra(
423435
ecx: &mut InterpCx<'mir, 'tcx, Self>,
@@ -439,6 +451,14 @@ pub trait Machine<'mir, 'tcx>: Sized {
439451
Ok(())
440452
}
441453

454+
/// Called just before the return value is copied to the caller-provided return place.
455+
fn before_stack_pop(
456+
_ecx: &InterpCx<'mir, 'tcx, Self>,
457+
_frame: &Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>,
458+
) -> InterpResult<'tcx> {
459+
Ok(())
460+
}
461+
442462
/// Called immediately after a stack frame got popped, but before jumping back to the caller.
443463
/// The `locals` have already been destroyed!
444464
fn after_stack_pop(
@@ -484,7 +504,7 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) {
484504
_ecx: &mut InterpCx<$mir, $tcx, Self>,
485505
fn_val: !,
486506
_abi: CallAbi,
487-
_args: &[OpTy<$tcx>],
507+
_args: &[FnArg<$tcx>],
488508
_destination: &PlaceTy<$tcx, Self::Provenance>,
489509
_target: Option<mir::BasicBlock>,
490510
_unwind: mir::UnwindAction,

compiler/rustc_const_eval/src/interpret/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ pub use self::machine::{compile_time_machine, AllocMap, Machine, MayLeak, StackP
2626
pub use self::memory::{AllocKind, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind};
2727
pub use self::operand::{ImmTy, Immediate, OpTy, Operand};
2828
pub use self::place::{MPlaceTy, MemPlace, MemPlaceMeta, Place, PlaceTy};
29+
pub use self::terminator::FnArg;
2930
pub use self::validity::{CtfeValidationMode, RefTracking};
3031
pub use self::visitor::{MutValueVisitor, Value, ValueVisitor};
3132

compiler/rustc_const_eval/src/interpret/operand.rs

-8
Original file line numberDiff line numberDiff line change
@@ -575,14 +575,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
575575
Ok(op)
576576
}
577577

578-
/// Evaluate a bunch of operands at once
579-
pub(super) fn eval_operands(
580-
&self,
581-
ops: &[mir::Operand<'tcx>],
582-
) -> InterpResult<'tcx, Vec<OpTy<'tcx, M::Provenance>>> {
583-
ops.iter().map(|op| self.eval_operand(op, None)).collect()
584-
}
585-
586578
fn eval_ty_constant(
587579
&self,
588580
val: ty::Const<'tcx>,

compiler/rustc_const_eval/src/interpret/place.rs

+12-10
Original file line numberDiff line numberDiff line change
@@ -354,25 +354,27 @@ where
354354
#[inline]
355355
pub(super) fn get_place_alloc(
356356
&self,
357-
place: &MPlaceTy<'tcx, M::Provenance>,
357+
mplace: &MPlaceTy<'tcx, M::Provenance>,
358358
) -> InterpResult<'tcx, Option<AllocRef<'_, 'tcx, M::Provenance, M::AllocExtra, M::Bytes>>>
359359
{
360-
assert!(place.layout.is_sized());
361-
assert!(!place.meta.has_meta());
362-
let size = place.layout.size;
363-
self.get_ptr_alloc(place.ptr, size, place.align)
360+
let (size, _align) = self
361+
.size_and_align_of_mplace(&mplace)?
362+
.unwrap_or((mplace.layout.size, mplace.layout.align.abi));
363+
// Due to packed places, only `mplace.align` matters.
364+
self.get_ptr_alloc(mplace.ptr, size, mplace.align)
364365
}
365366

366367
#[inline]
367368
pub(super) fn get_place_alloc_mut(
368369
&mut self,
369-
place: &MPlaceTy<'tcx, M::Provenance>,
370+
mplace: &MPlaceTy<'tcx, M::Provenance>,
370371
) -> InterpResult<'tcx, Option<AllocRefMut<'_, 'tcx, M::Provenance, M::AllocExtra, M::Bytes>>>
371372
{
372-
assert!(place.layout.is_sized());
373-
assert!(!place.meta.has_meta());
374-
let size = place.layout.size;
375-
self.get_ptr_alloc_mut(place.ptr, size, place.align)
373+
let (size, _align) = self
374+
.size_and_align_of_mplace(&mplace)?
375+
.unwrap_or((mplace.layout.size, mplace.layout.align.abi));
376+
// Due to packed places, only `mplace.align` matters.
377+
self.get_ptr_alloc_mut(mplace.ptr, size, mplace.align)
376378
}
377379

378380
/// Check if this mplace is dereferenceable and sufficiently aligned.

0 commit comments

Comments
 (0)