@@ -16,9 +16,9 @@ use tracing::field::Empty;
1616use tracing:: { info_span, instrument, trace} ;
1717
1818use 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} ;
2323use 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