@@ -520,37 +520,111 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
520
520
sig : ty:: FnSig < ' tcx > ,
521
521
path : String ,
522
522
) -> EvalResult < ' tcx > {
523
+ // In some cases in non-MIR libstd-mode, not having a destination is legit. Handle these early.
524
+ match & path[ ..] {
525
+ "std::panicking::rust_panic_with_hook" |
526
+ "std::rt::begin_panic_fmt" => return Err ( EvalError :: Panic ) ,
527
+ _ => { } ,
528
+ }
529
+
530
+ let dest_ty = sig. output ( ) ;
531
+ let ( dest, dest_block) = destination. ok_or_else ( || EvalError :: NoMirFor ( path. clone ( ) ) ) ?;
532
+
523
533
if sig. abi == Abi :: C {
524
534
// An external C function
525
- let ty = sig . output ( ) ;
526
- let ( ret , target ) = destination . unwrap ( ) ;
527
- self . call_c_abi ( instance. def_id ( ) , arg_operands, ret , ty , target ) ?;
535
+ // TODO: That functions actually has a similar preamble to what follows here. May make sense to
536
+ // unify these two mechanisms for "hooking into missing functions".
537
+ self . call_c_abi ( instance. def_id ( ) , arg_operands, dest , dest_ty , dest_block ) ?;
528
538
return Ok ( ( ) ) ;
529
539
}
540
+
541
+ let args_res: EvalResult < Vec < Value > > = arg_operands. iter ( )
542
+ . map ( |arg| self . eval_operand ( arg) )
543
+ . collect ( ) ;
544
+ let args = args_res?;
545
+
546
+ let usize = self . tcx . types . usize ;
530
547
531
- // A Rust function is missing, which means we are running with MIR missing for libstd (or other dependencies).
532
- // Still, we can make many things mostly work by "emulating" or ignoring some functions.
533
548
match & path[ ..] {
549
+ // Allocators are magic. They have no MIR, even when the rest of libstd does.
550
+ "alloc::heap::::__rust_alloc" => {
551
+ let size = self . value_to_primval ( args[ 0 ] , usize) ?. to_u64 ( ) ?;
552
+ let align = self . value_to_primval ( args[ 1 ] , usize) ?. to_u64 ( ) ?;
553
+ if size == 0 {
554
+ return Err ( EvalError :: HeapAllocZeroBytes ) ;
555
+ }
556
+ if !align. is_power_of_two ( ) {
557
+ return Err ( EvalError :: HeapAllocNonPowerOfTwoAlignment ( align) ) ;
558
+ }
559
+ let ptr = self . memory . allocate ( size, align) ?;
560
+ self . write_primval ( dest, PrimVal :: Ptr ( ptr) , dest_ty) ?;
561
+ }
562
+ "alloc::heap::::__rust_alloc_zeroed" => {
563
+ let size = self . value_to_primval ( args[ 0 ] , usize) ?. to_u64 ( ) ?;
564
+ let align = self . value_to_primval ( args[ 1 ] , usize) ?. to_u64 ( ) ?;
565
+ if size == 0 {
566
+ return Err ( EvalError :: HeapAllocZeroBytes ) ;
567
+ }
568
+ if !align. is_power_of_two ( ) {
569
+ return Err ( EvalError :: HeapAllocNonPowerOfTwoAlignment ( align) ) ;
570
+ }
571
+ let ptr = self . memory . allocate ( size, align) ?;
572
+ self . memory . write_repeat ( PrimVal :: Ptr ( ptr) , 0 , size) ?;
573
+ self . write_primval ( dest, PrimVal :: Ptr ( ptr) , dest_ty) ?;
574
+ }
575
+ "alloc::heap::::__rust_dealloc" => {
576
+ let ptr = args[ 0 ] . read_ptr ( & self . memory ) ?. to_ptr ( ) ?;
577
+ let old_size = self . value_to_primval ( args[ 1 ] , usize) ?. to_u64 ( ) ?;
578
+ let align = self . value_to_primval ( args[ 2 ] , usize) ?. to_u64 ( ) ?;
579
+ if old_size == 0 {
580
+ return Err ( EvalError :: HeapAllocZeroBytes ) ;
581
+ }
582
+ if !align. is_power_of_two ( ) {
583
+ return Err ( EvalError :: HeapAllocNonPowerOfTwoAlignment ( align) ) ;
584
+ }
585
+ self . memory . deallocate ( ptr, Some ( ( old_size, align) ) ) ?;
586
+ }
587
+ "alloc::heap::::__rust_realloc" => {
588
+ let ptr = args[ 0 ] . read_ptr ( & self . memory ) ?. to_ptr ( ) ?;
589
+ let old_size = self . value_to_primval ( args[ 1 ] , usize) ?. to_u64 ( ) ?;
590
+ let old_align = self . value_to_primval ( args[ 2 ] , usize) ?. to_u64 ( ) ?;
591
+ let new_size = self . value_to_primval ( args[ 3 ] , usize) ?. to_u64 ( ) ?;
592
+ let new_align = self . value_to_primval ( args[ 4 ] , usize) ?. to_u64 ( ) ?;
593
+ if old_size == 0 || new_size == 0 {
594
+ return Err ( EvalError :: HeapAllocZeroBytes ) ;
595
+ }
596
+ if !old_align. is_power_of_two ( ) {
597
+ return Err ( EvalError :: HeapAllocNonPowerOfTwoAlignment ( old_align) ) ;
598
+ }
599
+ if !new_align. is_power_of_two ( ) {
600
+ return Err ( EvalError :: HeapAllocNonPowerOfTwoAlignment ( new_align) ) ;
601
+ }
602
+ let new_ptr = self . memory . reallocate ( ptr, old_size, old_align, new_size, new_align) ?;
603
+ self . write_primval ( dest, PrimVal :: Ptr ( new_ptr) , dest_ty) ?;
604
+ }
605
+
606
+ // A Rust function is missing, which means we are running with MIR missing for libstd (or other dependencies).
607
+ // Still, we can make many things mostly work by "emulating" or ignoring some functions.
534
608
"std::io::_print" => {
535
609
trace ! ( "Ignoring output. To run programs that print, make sure you have a libstd with full MIR." ) ;
536
- self . goto_block ( destination. unwrap ( ) . 1 ) ;
537
- Ok ( ( ) )
538
- } ,
539
- "std::thread::Builder::new" => Err ( EvalError :: Unimplemented ( "miri does not support threading" . to_owned ( ) ) ) ,
540
- "std::env::args" => Err ( EvalError :: Unimplemented ( "miri does not support program arguments" . to_owned ( ) ) ) ,
541
- "std::panicking::rust_panic_with_hook" |
542
- "std::rt::begin_panic_fmt" => Err ( EvalError :: Panic ) ,
610
+ }
611
+ "std::thread::Builder::new" => return Err ( EvalError :: Unimplemented ( "miri does not support threading" . to_owned ( ) ) ) ,
612
+ "std::env::args" => return Err ( EvalError :: Unimplemented ( "miri does not support program arguments" . to_owned ( ) ) ) ,
543
613
"std::panicking::panicking" |
544
614
"std::rt::panicking" => {
545
- let ( lval, block) = destination. expect ( "std::rt::panicking does not diverge" ) ;
546
615
// we abort on panic -> `std::rt::panicking` always returns false
547
616
let bool = self . tcx . types . bool ;
548
- self . write_primval ( lval, PrimVal :: from_bool ( false ) , bool) ?;
549
- self . goto_block ( block) ;
550
- Ok ( ( ) )
617
+ self . write_primval ( dest, PrimVal :: from_bool ( false ) , bool) ?;
551
618
}
552
- _ => Err ( EvalError :: NoMirFor ( path) ) ,
619
+ _ => return Err ( EvalError :: NoMirFor ( path) ) ,
553
620
}
621
+
622
+ // Since we pushed no stack frame, the main loop will act
623
+ // as if the call just completed and it's returning to the
624
+ // current frame.
625
+ self . dump_local ( dest) ;
626
+ self . goto_block ( dest_block) ;
627
+ return Ok ( ( ) ) ;
554
628
}
555
629
556
630
fn call_c_abi (
@@ -609,61 +683,6 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
609
683
return Err ( EvalError :: Unimplemented ( format ! ( "miri does not support dynamically loading libraries (requested symbol: {})" , symbol_name) ) ) ;
610
684
}
611
685
612
- "__rust_allocate" => {
613
- let size = self . value_to_primval ( args[ 0 ] , usize) ?. to_u64 ( ) ?;
614
- let align = self . value_to_primval ( args[ 1 ] , usize) ?. to_u64 ( ) ?;
615
- if size == 0 {
616
- return Err ( EvalError :: HeapAllocZeroBytes ) ;
617
- }
618
- if !align. is_power_of_two ( ) {
619
- return Err ( EvalError :: HeapAllocNonPowerOfTwoAlignment ( align) ) ;
620
- }
621
- let ptr = self . memory . allocate ( size, align) ?;
622
- self . write_primval ( dest, PrimVal :: Ptr ( ptr) , dest_ty) ?;
623
- }
624
-
625
- "__rust_allocate_zeroed" => {
626
- let size = self . value_to_primval ( args[ 0 ] , usize) ?. to_u64 ( ) ?;
627
- let align = self . value_to_primval ( args[ 1 ] , usize) ?. to_u64 ( ) ?;
628
- if size == 0 {
629
- return Err ( EvalError :: HeapAllocZeroBytes ) ;
630
- }
631
- if !align. is_power_of_two ( ) {
632
- return Err ( EvalError :: HeapAllocNonPowerOfTwoAlignment ( align) ) ;
633
- }
634
- let ptr = self . memory . allocate ( size, align) ?;
635
- self . memory . write_repeat ( PrimVal :: Ptr ( ptr) , 0 , size) ?;
636
- self . write_primval ( dest, PrimVal :: Ptr ( ptr) , dest_ty) ?;
637
- }
638
-
639
- "__rust_deallocate" => {
640
- let ptr = args[ 0 ] . read_ptr ( & self . memory ) ?. to_ptr ( ) ?;
641
- let old_size = self . value_to_primval ( args[ 1 ] , usize) ?. to_u64 ( ) ?;
642
- let align = self . value_to_primval ( args[ 2 ] , usize) ?. to_u64 ( ) ?;
643
- if old_size == 0 {
644
- return Err ( EvalError :: HeapAllocZeroBytes ) ;
645
- }
646
- if !align. is_power_of_two ( ) {
647
- return Err ( EvalError :: HeapAllocNonPowerOfTwoAlignment ( align) ) ;
648
- }
649
- self . memory . deallocate ( ptr, Some ( ( old_size, align) ) ) ?;
650
- } ,
651
-
652
- "__rust_reallocate" => {
653
- let ptr = args[ 0 ] . read_ptr ( & self . memory ) ?. to_ptr ( ) ?;
654
- let old_size = self . value_to_primval ( args[ 1 ] , usize) ?. to_u64 ( ) ?;
655
- let size = self . value_to_primval ( args[ 2 ] , usize) ?. to_u64 ( ) ?;
656
- let align = self . value_to_primval ( args[ 3 ] , usize) ?. to_u64 ( ) ?;
657
- if old_size == 0 || size == 0 {
658
- return Err ( EvalError :: HeapAllocZeroBytes ) ;
659
- }
660
- if !align. is_power_of_two ( ) {
661
- return Err ( EvalError :: HeapAllocNonPowerOfTwoAlignment ( align) ) ;
662
- }
663
- let new_ptr = self . memory . reallocate ( ptr, old_size, size, align) ?;
664
- self . write_primval ( dest, PrimVal :: Ptr ( new_ptr) , dest_ty) ?;
665
- }
666
-
667
686
"__rust_maybe_catch_panic" => {
668
687
// fn __rust_maybe_catch_panic(f: fn(*mut u8), data: *mut u8, data_ptr: *mut usize, vtable_ptr: *mut usize) -> u32
669
688
// We abort on panic, so not much is going on here, but we still have to call the closure
0 commit comments