@@ -723,3 +723,52 @@ fn ensure_miri_valueitermut_not_violated() {
723723 * first += 10 ;
724724 * second += 20 ;
725725}
726+
727+ #[ test]
728+ fn into_iter_drop_panic_after_yielding_extra_value_double_drops ( ) {
729+ use std:: panic:: { catch_unwind, AssertUnwindSafe } ;
730+
731+ struct ManuallyAllocated {
732+ ptr : * mut u8 ,
733+ panic_on_drop : bool ,
734+ }
735+
736+ impl ManuallyAllocated {
737+ fn new ( byte : u8 , panic_on_drop : bool ) -> Self {
738+ Self {
739+ ptr : Box :: into_raw ( Box :: new ( byte) ) ,
740+ panic_on_drop,
741+ }
742+ }
743+ }
744+
745+ impl Drop for ManuallyAllocated {
746+ fn drop ( & mut self ) {
747+ unsafe {
748+ drop ( Box :: from_raw ( self . ptr ) ) ;
749+ }
750+
751+ if self . panic_on_drop {
752+ panic ! ( "intentional drop panic" ) ;
753+ }
754+ }
755+ }
756+
757+ let mut map: HeaderMap < ManuallyAllocated > = HeaderMap :: default ( ) ;
758+ map. append ( "x-first" , ManuallyAllocated :: new ( 1 , false ) ) ;
759+ map. append ( "x-first" , ManuallyAllocated :: new ( 2 , false ) ) ;
760+ map. insert ( "x-second" , ManuallyAllocated :: new ( 3 , true ) ) ;
761+
762+ let mut iter = map. into_iter ( ) ;
763+
764+ // HeaderMap::IntoIter yields extra values with ptr::read from
765+ // self.extra_values and relies on Drop setting self.extra_values.len() to
766+ // zero after the iterator has been fully consumed. If a later value's Drop
767+ // panics while IntoIter::drop is draining the iterator, that set_len(0) is
768+ // skipped. The Vec then drops already-yielded extra value slots again. The
769+ // safe sequence below therefore double-frees byte 2 under Miri.
770+ drop ( iter. next ( ) . unwrap ( ) ) ;
771+ drop ( iter. next ( ) . unwrap ( ) ) ;
772+
773+ let _ = catch_unwind ( AssertUnwindSafe ( || drop ( iter) ) ) ;
774+ }
0 commit comments