@@ -126,6 +126,7 @@ impl Default for ResourceLimits {
126
126
127
127
impl < ' a , ' tcx > EvalContext < ' a , ' tcx > {
128
128
pub fn new ( tcx : TyCtxt < ' a , ' tcx , ' tcx > , limits : ResourceLimits ) -> Self {
129
+ // Register array drop glue code
129
130
let source_info = mir:: SourceInfo {
130
131
span : DUMMY_SP ,
131
132
scope : mir:: ARGUMENT_VISIBILITY_SCOPE
@@ -852,7 +853,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
852
853
let fn_ptr = self . memory . create_fn_alloc ( instance) ;
853
854
self . write_value ( Value :: ByVal ( PrimVal :: Ptr ( fn_ptr) ) , dest, dest_ty) ?;
854
855
} ,
855
- ref other => bug ! ( "reify fn pointer on {:?}" , other) ,
856
+ ref other => bug ! ( "closure fn pointer on {:?}" , other) ,
856
857
} ,
857
858
}
858
859
}
@@ -1676,62 +1677,120 @@ impl<'tcx> Frame<'tcx> {
1676
1677
1677
1678
pub fn eval_main < ' a , ' tcx : ' a > (
1678
1679
tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
1679
- def_id : DefId ,
1680
+ main_id : DefId ,
1681
+ start_wrapper : Option < DefId > ,
1680
1682
limits : ResourceLimits ,
1681
1683
) {
1682
- let mut ecx = EvalContext :: new ( tcx, limits) ;
1683
- let instance = ty:: Instance :: mono ( tcx, def_id) ;
1684
- let mir = ecx. load_mir ( instance. def ) . expect ( "main function's MIR not found" ) ;
1685
-
1686
- if !mir. return_ty . is_nil ( ) || mir. arg_count != 0 {
1687
- let msg = "miri does not support main functions without `fn()` type signatures" ;
1688
- tcx. sess . err ( & EvalError :: Unimplemented ( String :: from ( msg) ) . to_string ( ) ) ;
1689
- return ;
1690
- }
1691
-
1692
- ecx. push_stack_frame (
1693
- instance,
1694
- DUMMY_SP ,
1695
- mir,
1696
- Lvalue :: from_ptr ( Pointer :: zst_ptr ( ) ) ,
1697
- StackPopCleanup :: None ,
1698
- ) . expect ( "could not allocate first stack frame" ) ;
1699
-
1700
- loop {
1701
- match ecx. step ( ) {
1702
- Ok ( true ) => { }
1703
- Ok ( false ) => {
1704
- let leaks = ecx. memory . leak_report ( ) ;
1705
- if leaks != 0 {
1706
- tcx. sess . err ( "the evaluated program leaked memory" ) ;
1707
- }
1708
- return ;
1684
+ fn run_main < ' a , ' tcx : ' a > (
1685
+ ecx : & mut EvalContext < ' a , ' tcx > ,
1686
+ main_id : DefId ,
1687
+ start_wrapper : Option < DefId > ,
1688
+ ) -> EvalResult < ' tcx > {
1689
+ let main_instance = ty:: Instance :: mono ( ecx. tcx , main_id) ;
1690
+ let main_mir = ecx. load_mir ( main_instance. def ) ?;
1691
+
1692
+ if !main_mir. return_ty . is_nil ( ) || main_mir. arg_count != 0 {
1693
+ return Err ( EvalError :: Unimplemented ( "miri does not support main functions without `fn()` type signatures" . to_owned ( ) ) ) ;
1694
+ }
1695
+
1696
+ if let Some ( start_id) = start_wrapper {
1697
+ let start_instance = ty:: Instance :: mono ( ecx. tcx , start_id) ;
1698
+ let start_mir = ecx. load_mir ( start_instance. def ) ?;
1699
+
1700
+ if start_mir. arg_count != 3 {
1701
+ return Err ( EvalError :: AbiViolation ( format ! ( "'start' lang item should have three arguments, but has {}" , start_mir. arg_count) ) ) ;
1709
1702
}
1710
- Err ( e) => {
1711
- report ( tcx, & ecx, e) ;
1712
- return ;
1703
+
1704
+ // Push our stack frame
1705
+ ecx. push_stack_frame (
1706
+ start_instance,
1707
+ start_mir. span ,
1708
+ start_mir,
1709
+ Lvalue :: from_ptr ( Pointer :: zst_ptr ( ) ) , // we'll fix the return lvalue later
1710
+ StackPopCleanup :: None ,
1711
+ ) ?;
1712
+
1713
+ let mut args = ecx. frame ( ) . mir . args_iter ( ) ;
1714
+
1715
+ // First argument: pointer to main()
1716
+ let main_ptr = ecx. memory . create_fn_alloc ( main_instance) ;
1717
+ let dest = ecx. eval_lvalue ( & mir:: Lvalue :: Local ( args. next ( ) . unwrap ( ) ) ) ?;
1718
+ let main_ty = main_instance. def . def_ty ( ecx. tcx ) ;
1719
+ let main_ptr_ty = ecx. tcx . mk_fn_ptr ( main_ty. fn_sig ( ) ) ;
1720
+ ecx. write_value ( Value :: ByVal ( PrimVal :: Ptr ( main_ptr) ) , dest, main_ptr_ty) ?;
1721
+
1722
+ // Second argument (argc): 0
1723
+ let dest = ecx. eval_lvalue ( & mir:: Lvalue :: Local ( args. next ( ) . unwrap ( ) ) ) ?;
1724
+ let ty = ecx. tcx . types . isize ;
1725
+ ecx. write_value ( Value :: ByVal ( PrimVal :: Bytes ( 0 ) ) , dest, ty) ?;
1726
+
1727
+ // Third argument (argv): 0
1728
+ let dest = ecx. eval_lvalue ( & mir:: Lvalue :: Local ( args. next ( ) . unwrap ( ) ) ) ?;
1729
+ let ty = ecx. tcx . mk_imm_ptr ( ecx. tcx . mk_imm_ptr ( ecx. tcx . types . u8 ) ) ;
1730
+ ecx. write_value ( Value :: ByVal ( PrimVal :: Bytes ( 0 ) ) , dest, ty) ?;
1731
+ } else {
1732
+ ecx. push_stack_frame (
1733
+ main_instance,
1734
+ main_mir. span ,
1735
+ main_mir,
1736
+ Lvalue :: from_ptr ( Pointer :: zst_ptr ( ) ) ,
1737
+ StackPopCleanup :: None ,
1738
+ ) ?;
1739
+ }
1740
+
1741
+ // Allocate memory for the return value. We have to do this when a stack frame was already pushed as the type code below
1742
+ // calls EvalContext::substs, which needs a frame to be allocated (?!?)
1743
+ let ret_ptr = {
1744
+ let ty = ecx. tcx . types . isize ;
1745
+ let layout = ecx. type_layout ( ty) ?;
1746
+ let size = layout. size ( & ecx. tcx . data_layout ) . bytes ( ) ;
1747
+ let align = layout. align ( & ecx. tcx . data_layout ) . pref ( ) ; // FIXME is this right?
1748
+ ecx. memory . allocate ( size, align) ?
1749
+ } ;
1750
+ ecx. frame_mut ( ) . return_lvalue = Lvalue :: from_ptr ( ret_ptr) ;
1751
+
1752
+ loop {
1753
+ if !ecx. step ( ) ? {
1754
+ ecx. memory . deallocate ( ret_ptr) ?;
1755
+ return Ok ( ( ) ) ;
1756
+ }
1757
+ }
1758
+ }
1759
+
1760
+ let mut ecx = EvalContext :: new ( tcx, limits) ;
1761
+ match run_main ( & mut ecx, main_id, start_wrapper) {
1762
+ Ok ( ( ) ) => {
1763
+ let leaks = ecx. memory . leak_report ( ) ;
1764
+ if leaks != 0 {
1765
+ tcx. sess . err ( "the evaluated program leaked memory" ) ;
1713
1766
}
1714
1767
}
1768
+ Err ( e) => {
1769
+ report ( tcx, & ecx, e) ;
1770
+ }
1715
1771
}
1716
1772
}
1717
1773
1718
1774
fn report ( tcx : TyCtxt , ecx : & EvalContext , e : EvalError ) {
1719
- let frame = ecx. stack ( ) . last ( ) . expect ( "stackframe was empty" ) ;
1720
- let block = & frame. mir . basic_blocks ( ) [ frame. block ] ;
1721
- let span = if frame. stmt < block. statements . len ( ) {
1722
- block. statements [ frame. stmt ] . source_info . span
1723
- } else {
1724
- block. terminator ( ) . source_info . span
1725
- } ;
1726
- let mut err = tcx. sess . struct_span_err ( span, & e. to_string ( ) ) ;
1727
- for & Frame { instance, span, .. } in ecx. stack ( ) . iter ( ) . rev ( ) {
1728
- if tcx. def_key ( instance. def_id ( ) ) . disambiguated_data . data == DefPathData :: ClosureExpr {
1729
- err. span_note ( span, "inside call to closure" ) ;
1730
- continue ;
1775
+ if let Some ( frame) = ecx. stack ( ) . last ( ) {
1776
+ let block = & frame. mir . basic_blocks ( ) [ frame. block ] ;
1777
+ let span = if frame. stmt < block. statements . len ( ) {
1778
+ block. statements [ frame. stmt ] . source_info . span
1779
+ } else {
1780
+ block. terminator ( ) . source_info . span
1781
+ } ;
1782
+ let mut err = tcx. sess . struct_span_err ( span, & e. to_string ( ) ) ;
1783
+ for & Frame { instance, span, .. } in ecx. stack ( ) . iter ( ) . rev ( ) {
1784
+ if tcx. def_key ( instance. def_id ( ) ) . disambiguated_data . data == DefPathData :: ClosureExpr {
1785
+ err. span_note ( span, "inside call to closure" ) ;
1786
+ continue ;
1787
+ }
1788
+ err. span_note ( span, & format ! ( "inside call to {}" , instance) ) ;
1731
1789
}
1732
- err. span_note ( span, & format ! ( "inside call to {}" , instance) ) ;
1790
+ err. emit ( ) ;
1791
+ } else {
1792
+ tcx. sess . err ( & e. to_string ( ) ) ;
1733
1793
}
1734
- err. emit ( ) ;
1735
1794
}
1736
1795
1737
1796
// TODO(solson): Upstream these methods into rustc::ty::layout.
0 commit comments