@@ -430,6 +430,93 @@ mod from_liballoc {
430430 d
431431 }
432432 }
433+
434+ // old binaryheap failed this test
435+ //
436+ // Integrity means that all elements are present after a comparison panics,
437+ // even if the order might not be correct.
438+ //
439+ // Destructors must be called exactly once per element.
440+ // FIXME: re-enable emscripten once it can unwind again
441+ #[ test]
442+ #[ cfg( not( target_os = "emscripten" ) ) ]
443+ fn panic_safe ( ) {
444+ use std:: cmp;
445+ use std:: panic:: { self , AssertUnwindSafe } ;
446+ use std:: sync:: atomic:: { AtomicUsize , Ordering } ;
447+
448+ use rand:: { seq:: SliceRandom , thread_rng} ;
449+
450+ static DROP_COUNTER : AtomicUsize = AtomicUsize :: new ( 0 ) ;
451+
452+ #[ derive( Eq , PartialEq , PartialOrd , Clone , Debug ) ]
453+ struct PanicOrd < T > ( T , bool ) ;
454+
455+ impl < T > Drop for PanicOrd < T > {
456+ fn drop ( & mut self ) {
457+ // update global drop count
458+ DROP_COUNTER . fetch_add ( 1 , Ordering :: SeqCst ) ;
459+ }
460+ }
461+
462+ impl < T : Ord > Ord for PanicOrd < T > {
463+ fn cmp ( & self , other : & Self ) -> cmp:: Ordering {
464+ if self . 1 || other. 1 {
465+ panic ! ( "Panicking comparison" ) ;
466+ }
467+ self . 0 . cmp ( & other. 0 )
468+ }
469+ }
470+ let mut rng = thread_rng ( ) ;
471+ const DATASZ : usize = 32 ;
472+ // Miri is too slow
473+ let ntest = if cfg ! ( miri) { 1 } else { 10 } ;
474+
475+ // don't use 0 in the data -- we want to catch the zeroed-out case.
476+ let data = ( 1 ..=DATASZ ) . collect :: < Vec < _ > > ( ) ;
477+
478+ // since it's a fuzzy test, run several tries.
479+ for _ in 0 ..ntest {
480+ for i in 1 ..=DATASZ {
481+ DROP_COUNTER . store ( 0 , Ordering :: SeqCst ) ;
482+
483+ let mut panic_ords: Vec < _ > = data
484+ . iter ( )
485+ . filter ( |& & x| x != i)
486+ . map ( |& x| PanicOrd ( x, false ) )
487+ . collect ( ) ;
488+ let panic_item = PanicOrd ( i, true ) ;
489+
490+ // heapify the sane items
491+ panic_ords. shuffle ( & mut rng) ;
492+ let mut heap = BinaryHeap :: from ( panic_ords) ;
493+ let inner_data;
494+
495+ {
496+ // push the panicking item to the heap and catch the panic
497+ let thread_result = {
498+ let mut heap_ref = AssertUnwindSafe ( & mut heap) ;
499+ panic:: catch_unwind ( move || {
500+ heap_ref. push ( panic_item) ;
501+ } )
502+ } ;
503+ assert ! ( thread_result. is_err( ) ) ;
504+
505+ // Assert no elements were dropped
506+ let drops = DROP_COUNTER . load ( Ordering :: SeqCst ) ;
507+ assert ! ( drops == 0 , "Must not drop items. drops={}" , drops) ;
508+ inner_data = heap. clone ( ) . into_vec ( ) ;
509+ drop ( heap) ;
510+ }
511+ let drops = DROP_COUNTER . load ( Ordering :: SeqCst ) ;
512+ assert_eq ! ( drops, DATASZ ) ;
513+
514+ let mut data_sorted = inner_data. into_iter ( ) . map ( |p| p. 0 ) . collect :: < Vec < _ > > ( ) ;
515+ data_sorted. sort ( ) ;
516+ assert_eq ! ( data_sorted, data) ;
517+ }
518+ }
519+ }
433520}
434521
435522#[ cfg( feature = "serde" ) ]
0 commit comments