Skip to content

Commit b6654ef

Browse files
committed
set up VaList global storage
1 parent 23fa1b4 commit b6654ef

3 files changed

Lines changed: 75 additions & 11 deletions

File tree

compiler/rustc_const_eval/src/interpret/call.rs

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ use std::assert_matches::assert_matches;
44
use std::borrow::Cow;
55

66
use either::{Left, Right};
7-
use rustc_abi::{self as abi, ExternAbi, FieldIdx, Integer, VariantIdx};
7+
use rustc_abi::{self as abi, ExternAbi, FieldIdx, HasDataLayout, Integer, Size, VariantIdx};
88
use rustc_hir::def_id::DefId;
9-
use rustc_middle::ty::layout::{IntegerExt, TyAndLayout};
9+
use rustc_middle::ty::layout::{HasTyCtxt, IntegerExt, TyAndLayout};
1010
use rustc_middle::ty::{self, AdtDef, Instance, Ty, VariantDef};
1111
use rustc_middle::{bug, mir, span_bug};
1212
use rustc_span::sym;
@@ -15,9 +15,9 @@ use tracing::field::Empty;
1515
use tracing::{info, instrument, trace};
1616

1717
use super::{
18-
CtfeProvenance, FnVal, ImmTy, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, PlaceTy,
19-
Projectable, Provenance, ReturnAction, ReturnContinuation, Scalar, StackPopInfo, interp_ok,
20-
throw_ub, throw_ub_custom,
18+
CtfeProvenance, FnVal, ImmTy, InterpCx, InterpResult, MPlaceTy, Machine, MemoryKind, OpTy,
19+
PlaceTy, Pointer, Projectable, Provenance, ReturnAction, ReturnContinuation, Scalar,
20+
StackPopInfo, interp_ok, throw_ub, throw_ub_custom,
2121
};
2222
use crate::interpret::EnteredTraceSpan;
2323
use crate::{enter_trace_span, fluent_generated as fluent};
@@ -470,7 +470,38 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
470470
let place = self.eval_place(dest)?;
471471
let mplace = self.force_allocation(&place)?;
472472

473-
let _ = mplace;
473+
// This global allocation is used as a key so `va_arg` can look up the variable
474+
// argument list corresponding to a `VaList` value.
475+
let alloc_id = self.tcx().reserve_and_set_va_list_alloc();
476+
477+
// Consume the remaining arguments and store them in a global allocation.
478+
let mut varargs = Vec::new();
479+
for (fn_arg, abi) in &mut caller_args {
480+
let op = self.copy_fn_arg(fn_arg);
481+
let mplace = self.allocate(abi.layout, MemoryKind::Stack)?;
482+
self.copy_op(&op, &mplace)?;
483+
484+
varargs.push(mplace);
485+
}
486+
487+
// When the frame is dropped, this ID is used to deallocate the variable arguments list.
488+
self.frame_mut().va_list = Some(alloc_id);
489+
490+
// A global map that is used to implement `va_arg`.
491+
self.memory.va_list_map.insert(alloc_id, varargs);
492+
493+
// A VaList is a global allocation, so make sure we get the right root pointer.
494+
// We know this is not an `extern static` so this cannot fail.
495+
let ptr = self.global_root_pointer(Pointer::from(alloc_id)).unwrap();
496+
let addr = Scalar::from_pointer(ptr, self);
497+
498+
// Store the pointer to the global variable arguments list allocation in the
499+
// first bytes of the `VaList` value.
500+
let mut alloc = self
501+
.get_ptr_alloc_mut(mplace.ptr(), self.data_layout().pointer_size())?
502+
.expect("not a ZST");
503+
504+
alloc.write_ptr_sized(Size::ZERO, addr)?;
474505
} else if Some(local) == body.spread_arg {
475506
// Make the local live once, then fill in the value field by field.
476507
self.storage_live(local)?;

compiler/rustc_const_eval/src/interpret/memory.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ use tracing::{debug, instrument, trace};
2222

2323
use super::{
2424
AllocBytes, AllocId, AllocInit, AllocMap, AllocRange, Allocation, CheckAlignMsg,
25-
CheckInAllocMsg, CtfeProvenance, GlobalAlloc, InterpCx, InterpResult, Machine, MayLeak,
26-
Misalignment, Pointer, PointerArithmetic, Provenance, Scalar, alloc_range, err_ub,
25+
CheckInAllocMsg, CtfeProvenance, GlobalAlloc, InterpCx, InterpResult, MPlaceTy, Machine,
26+
MayLeak, Misalignment, Pointer, PointerArithmetic, Provenance, Scalar, alloc_range, err_ub,
2727
err_ub_custom, interp_ok, throw_ub, throw_ub_custom, throw_unsup, throw_unsup_format,
2828
};
2929
use crate::const_eval::ConstEvalErrKind;
@@ -128,6 +128,8 @@ pub struct Memory<'tcx, M: Machine<'tcx>> {
128128
/// Map for "extra" function pointers.
129129
extra_fn_ptr_map: FxIndexMap<AllocId, M::ExtraFnVal>,
130130

131+
pub(super) va_list_map: FxIndexMap<AllocId, Vec<MPlaceTy<'tcx, M::Provenance>>>,
132+
131133
/// To be able to compare pointers with null, and to check alignment for accesses
132134
/// to ZSTs (where pointers may dangle), we keep track of the size even for allocations
133135
/// that do not exist any more.
@@ -163,6 +165,7 @@ impl<'tcx, M: Machine<'tcx>> Memory<'tcx, M> {
163165
Memory {
164166
alloc_map: M::MemoryMap::default(),
165167
extra_fn_ptr_map: FxIndexMap::default(),
168+
va_list_map: FxIndexMap::default(),
166169
dead_alloc_map: FxIndexMap::default(),
167170
validation_in_progress: Cell::new(false),
168171
}

compiler/rustc_const_eval/src/interpret/stack.rs

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ use tracing::field::Empty;
1616
use tracing::{info_span, instrument, trace};
1717

1818
use super::{
19-
AllocId, CtfeProvenance, Immediate, InterpCx, InterpResult, Machine, MemPlace, MemPlaceMeta,
20-
MemoryKind, Operand, PlaceTy, Pointer, Provenance, ReturnAction, Scalar, from_known_layout,
21-
interp_ok, throw_ub, throw_unsup,
19+
AllocId, CtfeProvenance, Immediate, InterpCx, InterpResult, MPlaceTy, Machine, MemPlace,
20+
MemPlaceMeta, MemoryKind, Operand, PlaceTy, Pointer, Provenance, ReturnAction, Scalar,
21+
from_known_layout, interp_ok, throw_ub, throw_unsup,
2222
};
2323
use crate::{enter_trace_span, errors};
2424

@@ -91,6 +91,10 @@ pub struct Frame<'tcx, Prov: Provenance = CtfeProvenance, Extra = ()> {
9191
/// Do *not* access this directly; always go through the machine hook!
9292
pub locals: IndexVec<mir::Local, LocalState<'tcx, Prov>>,
9393

94+
/// Key into `Memory`'s `va_list_map` field. When this frame is popped the key should be
95+
/// removed from `va_list_map` and the elements deallocated.
96+
pub(super) va_list: Option<AllocId>,
97+
9498
/// The span of the `tracing` crate is stored here.
9599
/// When the guard is dropped, the span is exited. This gives us
96100
/// a full stack trace on all tracing statements.
@@ -259,6 +263,7 @@ impl<'tcx, Prov: Provenance> Frame<'tcx, Prov> {
259263
return_cont: self.return_cont,
260264
return_place: self.return_place,
261265
locals: self.locals,
266+
va_list: self.va_list,
262267
loc: self.loc,
263268
extra,
264269
tracing_span: self.tracing_span,
@@ -377,6 +382,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
377382
return_cont,
378383
return_place: return_place.clone(),
379384
locals,
385+
va_list: None,
380386
instance,
381387
tracing_span: SpanGuard::new(),
382388
extra: (),
@@ -454,6 +460,14 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
454460
self.deallocate_local(local.value)?;
455461
}
456462

463+
// Deallocate any c-variadic arguments.
464+
if let Some(alloc_id) = frame.va_list {
465+
let arguments = self.memory.va_list_map.shift_remove(&alloc_id).unwrap();
466+
for mplace in arguments {
467+
self.deallocate_vararg(&mplace)?;
468+
}
469+
}
470+
457471
// Call the machine hook, which determines the next steps.
458472
let return_action = M::after_stack_pop(self, frame, unwinding)?;
459473
assert_ne!(return_action, ReturnAction::NoCleanup);
@@ -599,6 +613,22 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
599613
interp_ok(())
600614
}
601615

616+
fn deallocate_vararg(&mut self, vararg: &MPlaceTy<'tcx, M::Provenance>) -> InterpResult<'tcx> {
617+
let ptr = vararg.ptr();
618+
619+
// FIXME: is the `unwrap` valid here?
620+
trace!(
621+
"deallocating vararg {:?}: {:?}",
622+
vararg,
623+
// FIXME: what do we do with this comment?
624+
// Locals always have a `alloc_id` (they are never the result of a int2ptr).
625+
self.dump_alloc(ptr.provenance.unwrap().get_alloc_id().unwrap())
626+
);
627+
self.deallocate_ptr(ptr, None, MemoryKind::Stack)?;
628+
629+
interp_ok(())
630+
}
631+
602632
/// This is public because it is used by [Aquascope](https://github.com/cognitive-engineering-lab/aquascope/)
603633
/// to analyze all the locals in a stack frame.
604634
#[inline(always)]

0 commit comments

Comments
 (0)