2016-06-23 01:03:58 -06:00
use rustc ::hir ::def_id ::DefId ;
2016-11-03 10:38:08 +01:00
use rustc ::mir ;
2017-06-01 17:24:21 -07:00
use rustc ::ty ::{ self , TypeVariants , Ty } ;
2017-03-22 13:13:52 +01:00
use rustc ::ty ::layout ::Layout ;
2017-02-10 03:21:33 -08:00
use syntax ::codemap ::Span ;
use syntax ::attr ;
2017-03-02 13:11:33 +01:00
use syntax ::abi ::Abi ;
2016-06-23 01:03:58 -06:00
use error ::{ EvalError , EvalResult } ;
2017-02-09 18:12:59 +01:00
use eval_context ::{ EvalContext , IntegerExt , StackPopCleanup , is_inhabited } ;
2017-03-22 18:31:41 +01:00
use lvalue ::Lvalue ;
2017-05-25 16:40:13 -07:00
use memory ::{ Pointer , TlsKey } ;
2016-12-10 16:23:07 -08:00
use value ::PrimVal ;
2016-12-07 20:30:37 -08:00
use value ::Value ;
2017-03-23 13:36:13 +01:00
use rustc_data_structures ::indexed_vec ::Idx ;
2016-06-23 01:03:58 -06:00
2017-03-22 18:31:41 +01:00
mod drop ;
2016-12-10 16:27:45 -08:00
mod intrinsic ;
2016-09-20 16:05:30 +02:00
2016-06-23 01:03:58 -06:00
impl < ' a , ' tcx > EvalContext < ' a , ' tcx > {
2016-07-06 17:55:05 +02:00
pub ( super ) fn goto_block ( & mut self , target : mir ::BasicBlock ) {
self . frame_mut ( ) . block = target ;
self . frame_mut ( ) . stmt = 0 ;
}
2016-06-23 01:03:58 -06:00
pub ( super ) fn eval_terminator (
& mut self ,
terminator : & mir ::Terminator < ' tcx > ,
2017-02-04 13:09:10 -08:00
) -> EvalResult < ' tcx > {
2016-11-03 10:38:08 +01:00
use rustc ::mir ::TerminatorKind ::* ;
2016-06-23 01:03:58 -06:00
match terminator . kind {
2016-11-26 19:13:22 -08:00
Return = > {
2017-06-19 13:29:04 +02:00
self . dump_local ( self . frame ( ) . return_lvalue ) ;
2016-11-26 19:13:22 -08:00
self . pop_stack_frame ( ) ?
}
2016-06-23 01:03:58 -06:00
2016-07-06 17:55:05 +02:00
Goto { target } = > self . goto_block ( target ) ,
2016-06-23 01:03:58 -06:00
SwitchInt { ref discr , ref values , ref targets , .. } = > {
2017-06-28 09:40:25 +02:00
if self . const_env ( ) {
2017-06-26 17:58:47 +02:00
return Err ( EvalError ::NeedsRfc ( " branching (if, match, loop, ...) " . to_string ( ) ) ) ;
}
2017-02-24 10:39:55 +01:00
let discr_val = self . eval_operand ( discr ) ? ;
let discr_ty = self . operand_ty ( discr ) ;
2016-09-27 11:10:25 +02:00
let discr_prim = self . value_to_primval ( discr_val , discr_ty ) ? ;
2016-06-23 01:03:58 -06:00
// Branch to the `otherwise` case by default, if no match is found.
let mut target_block = targets [ targets . len ( ) - 1 ] ;
2017-02-24 10:39:55 +01:00
for ( index , const_int ) in values . iter ( ) . enumerate ( ) {
let prim = PrimVal ::Bytes ( const_int . to_u128_unchecked ( ) ) ;
2016-12-17 03:09:57 -08:00
if discr_prim . to_bytes ( ) ? = = prim . to_bytes ( ) ? {
2016-06-23 01:03:58 -06:00
target_block = targets [ index ] ;
break ;
}
}
2016-07-06 17:55:05 +02:00
self . goto_block ( target_block ) ;
2016-06-23 01:03:58 -06:00
}
Call { ref func , ref args , ref destination , .. } = > {
2016-07-06 17:55:05 +02:00
let destination = match * destination {
2016-10-14 03:31:45 -06:00
Some ( ( ref lv , target ) ) = > Some ( ( self . eval_lvalue ( lv ) ? , target ) ) ,
2016-07-06 17:55:05 +02:00
None = > None ,
} ;
2016-06-23 01:03:58 -06:00
let func_ty = self . operand_ty ( func ) ;
2017-03-22 14:19:29 +01:00
let ( fn_def , sig ) = match func_ty . sty {
2017-03-22 13:13:52 +01:00
ty ::TyFnPtr ( sig ) = > {
2016-12-16 22:01:01 -08:00
let fn_ptr = self . eval_operand_to_primval ( func ) ? . to_ptr ( ) ? ;
2017-06-21 21:45:51 -07:00
let instance = self . memory . get_fn ( fn_ptr ) ? ;
2017-03-23 17:57:40 +01:00
let instance_ty = instance . def . def_ty ( self . tcx ) ;
let instance_ty = self . monomorphize ( instance_ty , instance . substs ) ;
match instance_ty . sty {
2017-03-23 15:17:02 +01:00
ty ::TyFnDef ( _ , _ , real_sig ) = > {
let sig = self . erase_lifetimes ( & sig ) ;
let real_sig = self . erase_lifetimes ( & real_sig ) ;
2017-05-26 20:02:51 -07:00
if ! self . check_sig_compat ( sig , real_sig ) ? {
return Err ( EvalError ::FunctionPointerTyMismatch ( real_sig , sig ) ) ;
2017-03-23 15:17:02 +01:00
}
} ,
ref other = > bug! ( " instance def ty: {:?} " , other ) ,
}
( instance , sig )
2016-06-23 01:03:58 -06:00
} ,
2017-03-22 14:19:29 +01:00
ty ::TyFnDef ( def_id , substs , sig ) = > ( ::eval_context ::resolve ( self . tcx , def_id , substs ) , sig ) ,
2016-11-26 22:58:01 -08:00
_ = > {
let msg = format! ( " can't handle callee of type {:?} " , func_ty ) ;
return Err ( EvalError ::Unimplemented ( msg ) ) ;
}
2017-02-28 12:35:00 +01:00
} ;
2017-03-22 14:19:29 +01:00
let sig = self . erase_lifetimes ( & sig ) ;
self . eval_fn_call ( fn_def , destination , args , terminator . source_info . span , sig ) ? ;
2016-06-23 01:03:58 -06:00
}
2017-03-22 13:13:52 +01:00
Drop { ref location , target , .. } = > {
2017-03-22 17:32:20 +01:00
trace! ( " TerminatorKind::drop: {:?}, {:?} " , location , self . substs ( ) ) ;
2017-06-28 09:40:25 +02:00
if self . const_env ( ) {
2017-06-26 17:58:47 +02:00
return Err ( EvalError ::NeedsRfc ( " invoking `Drop::drop` " . to_string ( ) ) ) ;
}
2017-03-22 13:13:52 +01:00
let lval = self . eval_lvalue ( location ) ? ;
let ty = self . lvalue_ty ( location ) ;
2017-03-22 17:32:20 +01:00
self . goto_block ( target ) ;
2017-03-22 16:16:23 +01:00
let ty = ::eval_context ::apply_param_substs ( self . tcx , self . substs ( ) , & ty ) ;
2017-03-22 13:13:52 +01:00
2017-03-22 18:31:41 +01:00
let instance = ::eval_context ::resolve_drop_in_place ( self . tcx , ty ) ;
self . drop_lvalue ( lval , instance , ty , terminator . source_info . span ) ? ;
2017-03-22 13:13:52 +01:00
}
2016-06-23 01:03:58 -06:00
Assert { ref cond , expected , ref msg , target , .. } = > {
2016-12-16 22:01:01 -08:00
let cond_val = self . eval_operand_to_primval ( cond ) ? . to_bool ( ) ? ;
2016-09-19 02:19:31 -06:00
if expected = = cond_val {
2016-07-06 17:55:05 +02:00
self . goto_block ( target ) ;
2016-06-23 01:03:58 -06:00
} else {
return match * msg {
mir ::AssertMessage ::BoundsCheck { ref len , ref index } = > {
2016-09-19 19:01:28 -06:00
let span = terminator . source_info . span ;
2016-11-26 22:58:01 -08:00
let len = self . eval_operand_to_primval ( len )
. expect ( " can't eval len " )
2016-12-16 22:01:01 -08:00
. to_u64 ( ) ? ;
2016-09-19 19:01:28 -06:00
let index = self . eval_operand_to_primval ( index )
. expect ( " can't eval index " )
2016-12-16 22:01:01 -08:00
. to_u64 ( ) ? ;
2016-09-19 19:01:28 -06:00
Err ( EvalError ::ArrayIndexOutOfBounds ( span , len , index ) )
2016-06-23 01:03:58 -06:00
} ,
2016-09-19 19:01:28 -06:00
mir ::AssertMessage ::Math ( ref err ) = >
Err ( EvalError ::Math ( terminator . source_info . span , err . clone ( ) ) ) ,
2016-06-23 01:03:58 -06:00
}
}
} ,
DropAndReplace { .. } = > unimplemented! ( ) ,
Resume = > unimplemented! ( ) ,
2017-01-12 09:41:36 +01:00
Unreachable = > return Err ( EvalError ::Unreachable ) ,
2016-06-23 01:03:58 -06:00
}
Ok ( ( ) )
}
2017-05-30 10:24:37 -07:00
/// Decides whether it is okay to call the method with signature `real_sig` using signature `sig`.
/// FIXME: This should take into account the platform-dependent ABI description.
2017-05-26 20:02:51 -07:00
fn check_sig_compat (
& mut self ,
sig : ty ::FnSig < ' tcx > ,
real_sig : ty ::FnSig < ' tcx > ,
) -> EvalResult < ' tcx , bool > {
fn check_ty_compat < ' tcx > (
ty : ty ::Ty < ' tcx > ,
real_ty : ty ::Ty < ' tcx > ,
) -> bool {
if ty = = real_ty { return true ; } // This is actually a fast pointer comparison
return match ( & ty . sty , & real_ty . sty ) {
// Permit changing the pointer type of raw pointers and references as well as
// mutability of raw pointers.
// TODO: Should not be allowed when fat pointers are involved.
( & TypeVariants ::TyRawPtr ( _ ) , & TypeVariants ::TyRawPtr ( _ ) ) = > true ,
( & TypeVariants ::TyRef ( _ , _ ) , & TypeVariants ::TyRef ( _ , _ ) ) = >
ty . is_mutable_pointer ( ) = = real_ty . is_mutable_pointer ( ) ,
// rule out everything else
_ = > false
}
}
if sig . abi = = real_sig . abi & &
sig . variadic = = real_sig . variadic & &
sig . inputs_and_output . len ( ) = = real_sig . inputs_and_output . len ( ) & &
sig . inputs_and_output . iter ( ) . zip ( real_sig . inputs_and_output ) . all ( | ( ty , real_ty ) | check_ty_compat ( ty , real_ty ) ) {
// Definitely good.
return Ok ( true ) ;
}
if sig . variadic | | real_sig . variadic {
// We're not touching this
return Ok ( false ) ;
}
// We need to allow what comes up when a non-capturing closure is cast to a fn().
match ( sig . abi , real_sig . abi ) {
( Abi ::Rust , Abi ::RustCall ) // check the ABIs. This makes the test here non-symmetric.
if check_ty_compat ( sig . output ( ) , real_sig . output ( ) ) & & real_sig . inputs_and_output . len ( ) = = 3 = > {
// First argument of real_sig must be a ZST
let fst_ty = real_sig . inputs_and_output [ 0 ] ;
let layout = self . type_layout ( fst_ty ) ? ;
let size = layout . size ( & self . tcx . data_layout ) . bytes ( ) ;
if size = = 0 {
// Second argument must be a tuple matching the argument list of sig
let snd_ty = real_sig . inputs_and_output [ 1 ] ;
match snd_ty . sty {
TypeVariants ::TyTuple ( tys , _ ) if sig . inputs ( ) . len ( ) = = tys . len ( ) = >
if sig . inputs ( ) . iter ( ) . zip ( tys ) . all ( | ( ty , real_ty ) | check_ty_compat ( ty , real_ty ) ) {
return Ok ( true )
} ,
_ = > { }
}
}
}
_ = > { }
} ;
// Nope, this doesn't work.
return Ok ( false ) ;
}
2016-06-23 01:03:58 -06:00
fn eval_fn_call (
& mut self ,
2017-03-21 13:53:55 +01:00
instance : ty ::Instance < ' tcx > ,
2016-10-21 10:29:56 +02:00
destination : Option < ( Lvalue < ' tcx > , mir ::BasicBlock ) > ,
2016-09-19 19:40:56 -06:00
arg_operands : & [ mir ::Operand < ' tcx > ] ,
2016-06-23 01:03:58 -06:00
span : Span ,
2017-03-22 14:19:29 +01:00
sig : ty ::FnSig < ' tcx > ,
2017-02-04 13:09:10 -08:00
) -> EvalResult < ' tcx > {
2017-03-22 13:13:52 +01:00
trace! ( " eval_fn_call: {:#?} " , instance ) ;
match instance . def {
ty ::InstanceDef ::Intrinsic ( .. ) = > {
2017-01-12 09:59:00 +01:00
let ( ret , target ) = match destination {
2017-03-22 14:19:29 +01:00
Some ( dest ) = > dest ,
2017-01-12 10:37:14 +01:00
_ = > return Err ( EvalError ::Unreachable ) ,
2017-01-12 09:59:00 +01:00
} ;
2017-03-22 14:19:29 +01:00
let ty = sig . output ( ) ;
if ! is_inhabited ( self . tcx , ty ) {
return Err ( EvalError ::Unreachable ) ;
}
let layout = self . type_layout ( ty ) ? ;
2017-03-21 13:53:55 +01:00
self . call_intrinsic ( instance , arg_operands , ret , ty , layout , target ) ? ;
2017-02-07 01:03:40 -08:00
self . dump_local ( ret ) ;
2017-03-22 14:19:29 +01:00
Ok ( ( ) )
2017-02-28 12:35:00 +01:00
} ,
2017-03-22 13:13:52 +01:00
ty ::InstanceDef ::ClosureOnceShim { .. } = > {
2016-09-19 19:40:56 -06:00
let mut args = Vec ::new ( ) ;
for arg in arg_operands {
let arg_val = self . eval_operand ( arg ) ? ;
let arg_ty = self . operand_ty ( arg ) ;
args . push ( ( arg_val , arg_ty ) ) ;
2016-06-23 01:03:58 -06:00
}
2017-03-23 17:36:10 +01:00
if self . eval_fn_call_inner (
2017-03-22 13:13:52 +01:00
instance ,
destination ,
2017-05-26 12:25:25 -07:00
arg_operands ,
2017-03-22 13:13:52 +01:00
span ,
2017-05-26 12:25:25 -07:00
sig ,
2017-03-23 17:36:10 +01:00
) ? {
return Ok ( ( ) ) ;
}
2017-03-23 13:36:13 +01:00
let mut arg_locals = self . frame ( ) . mir . args_iter ( ) ;
match sig . abi {
// closure as closure once
Abi ::RustCall = > {
for ( arg_local , ( arg_val , arg_ty ) ) in arg_locals . zip ( args ) {
let dest = self . eval_lvalue ( & mir ::Lvalue ::Local ( arg_local ) ) ? ;
self . write_value ( arg_val , dest , arg_ty ) ? ;
}
} ,
// non capture closure as fn ptr
// need to inject zst ptr for closure object (aka do nothing)
// and need to pack arguments
Abi ::Rust = > {
trace! ( " arg_locals: {:?} " , self . frame ( ) . mir . args_iter ( ) . collect ::< Vec < _ > > ( ) ) ;
trace! ( " arg_operands: {:?} " , arg_operands ) ;
let local = arg_locals . nth ( 1 ) . unwrap ( ) ;
for ( i , ( arg_val , arg_ty ) ) in args . into_iter ( ) . enumerate ( ) {
let dest = self . eval_lvalue ( & mir ::Lvalue ::Local ( local ) . field ( mir ::Field ::new ( i ) , arg_ty ) ) ? ;
self . write_value ( arg_val , dest , arg_ty ) ? ;
}
} ,
_ = > bug! ( " bad ABI for ClosureOnceShim: {:?} " , sig . abi ) ,
}
Ok ( ( ) )
2017-03-22 13:13:52 +01:00
}
ty ::InstanceDef ::Item ( _ ) = > {
2017-03-23 13:36:13 +01:00
let mut args = Vec ::new ( ) ;
for arg in arg_operands {
let arg_val = self . eval_operand ( arg ) ? ;
let arg_ty = self . operand_ty ( arg ) ;
args . push ( ( arg_val , arg_ty ) ) ;
}
2017-05-25 22:38:07 -07:00
// Push the stack frame, and potentially be entirely done if the call got hooked
2017-03-23 17:36:10 +01:00
if self . eval_fn_call_inner (
2017-03-21 13:53:55 +01:00
instance ,
2017-02-28 12:35:00 +01:00
destination ,
2017-05-26 12:25:25 -07:00
arg_operands ,
2017-02-28 12:35:00 +01:00
span ,
2017-05-26 12:25:25 -07:00
sig ,
2017-03-23 17:36:10 +01:00
) ? {
return Ok ( ( ) ) ;
}
2017-03-23 13:36:13 +01:00
2017-05-25 22:38:07 -07:00
// Pass the arguments
2017-03-23 13:36:13 +01:00
let mut arg_locals = self . frame ( ) . mir . args_iter ( ) ;
2017-03-23 16:09:36 +01:00
trace! ( " ABI: {:?} " , sig . abi ) ;
trace! ( " arg_locals: {:?} " , self . frame ( ) . mir . args_iter ( ) . collect ::< Vec < _ > > ( ) ) ;
trace! ( " arg_operands: {:?} " , arg_operands ) ;
2017-03-23 13:36:13 +01:00
match sig . abi {
Abi ::RustCall = > {
assert_eq! ( args . len ( ) , 2 ) ;
{ // write first argument
let first_local = arg_locals . next ( ) . unwrap ( ) ;
let dest = self . eval_lvalue ( & mir ::Lvalue ::Local ( first_local ) ) ? ;
let ( arg_val , arg_ty ) = args . remove ( 0 ) ;
self . write_value ( arg_val , dest , arg_ty ) ? ;
}
// unpack and write all other args
let ( arg_val , arg_ty ) = args . remove ( 0 ) ;
let layout = self . type_layout ( arg_ty ) ? ;
if let ( & ty ::TyTuple ( fields , _ ) , & Layout ::Univariant { ref variant , .. } ) = ( & arg_ty . sty , layout ) {
2017-03-23 16:09:36 +01:00
trace! ( " fields: {:?} " , fields ) ;
2017-03-23 15:07:33 +01:00
if self . frame ( ) . mir . args_iter ( ) . count ( ) = = fields . len ( ) + 1 {
let offsets = variant . offsets . iter ( ) . map ( | s | s . bytes ( ) ) ;
2017-03-23 16:09:36 +01:00
match arg_val {
Value ::ByRef ( ptr ) = > {
for ( ( offset , ty ) , arg_local ) in offsets . zip ( fields ) . zip ( arg_locals ) {
2017-06-05 18:07:26 -07:00
let arg = Value ::ByRef ( ptr . offset ( offset , self . memory . layout ) ? ) ;
2017-03-23 16:09:36 +01:00
let dest = self . eval_lvalue ( & mir ::Lvalue ::Local ( arg_local ) ) ? ;
trace! ( " writing arg {:?} to {:?} (type: {}) " , arg , dest , ty ) ;
self . write_value ( arg , dest , ty ) ? ;
}
} ,
Value ::ByVal ( PrimVal ::Undef ) = > { } ,
other = > {
assert_eq! ( fields . len ( ) , 1 ) ;
let dest = self . eval_lvalue ( & mir ::Lvalue ::Local ( arg_locals . next ( ) . unwrap ( ) ) ) ? ;
self . write_value ( other , dest , fields [ 0 ] ) ? ;
2017-03-23 15:07:33 +01:00
}
2017-03-23 13:36:13 +01:00
}
2017-03-23 15:07:33 +01:00
} else {
2017-03-23 16:09:36 +01:00
trace! ( " manual impl of rust-call ABI " ) ;
2017-03-23 15:07:33 +01:00
// called a manual impl of a rust-call function
let dest = self . eval_lvalue ( & mir ::Lvalue ::Local ( arg_locals . next ( ) . unwrap ( ) ) ) ? ;
self . write_value ( arg_val , dest , arg_ty ) ? ;
2017-03-23 13:36:13 +01:00
}
} else {
bug! ( " rust-call ABI tuple argument was {:?}, {:?} " , arg_ty , layout ) ;
}
2017-05-30 10:24:37 -07:00
} ,
_ = > {
for ( arg_local , ( arg_val , arg_ty ) ) in arg_locals . zip ( args ) {
let dest = self . eval_lvalue ( & mir ::Lvalue ::Local ( arg_local ) ) ? ;
self . write_value ( arg_val , dest , arg_ty ) ? ;
}
2017-03-23 13:36:13 +01:00
}
}
Ok ( ( ) )
2017-02-28 12:35:00 +01:00
} ,
2017-03-22 18:31:41 +01:00
ty ::InstanceDef ::DropGlue ( .. ) = > {
assert_eq! ( arg_operands . len ( ) , 1 ) ;
assert_eq! ( sig . abi , Abi ::Rust ) ;
let val = self . eval_operand ( & arg_operands [ 0 ] ) ? ;
let ty = self . operand_ty ( & arg_operands [ 0 ] ) ;
let ( _ , target ) = destination . expect ( " diverging drop glue " ) ;
self . goto_block ( target ) ;
// FIXME: deduplicate these matches
let pointee_type = match ty . sty {
ty ::TyRawPtr ( ref tam ) |
ty ::TyRef ( _ , ref tam ) = > tam . ty ,
2017-04-26 12:15:42 +02:00
ty ::TyAdt ( def , _ ) if def . is_box ( ) = > ty . boxed_ty ( ) ,
2017-03-22 18:31:41 +01:00
_ = > bug! ( " can only deref pointer types " ) ,
} ;
self . drop ( val , instance , pointee_type , span )
2017-03-23 10:04:08 +01:00
} ,
ty ::InstanceDef ::FnPtrShim ( .. ) = > {
2017-03-23 13:36:13 +01:00
trace! ( " ABI: {} " , sig . abi ) ;
2017-03-23 10:04:08 +01:00
let mut args = Vec ::new ( ) ;
for arg in arg_operands {
let arg_val = self . eval_operand ( arg ) ? ;
let arg_ty = self . operand_ty ( arg ) ;
args . push ( ( arg_val , arg_ty ) ) ;
}
2017-03-23 17:36:10 +01:00
if self . eval_fn_call_inner (
2017-03-23 13:36:13 +01:00
instance ,
destination ,
2017-05-26 12:25:25 -07:00
arg_operands ,
2017-03-23 13:36:13 +01:00
span ,
2017-05-26 12:25:25 -07:00
sig ,
2017-03-23 17:36:10 +01:00
) ? {
return Ok ( ( ) ) ;
}
2017-03-23 13:36:13 +01:00
let arg_locals = self . frame ( ) . mir . args_iter ( ) ;
2017-03-23 10:04:08 +01:00
match sig . abi {
Abi ::Rust = > {
args . remove ( 0 ) ;
} ,
Abi ::RustCall = > { } ,
_ = > unimplemented! ( ) ,
2017-03-23 13:36:13 +01:00
} ;
for ( arg_local , ( arg_val , arg_ty ) ) in arg_locals . zip ( args ) {
let dest = self . eval_lvalue ( & mir ::Lvalue ::Local ( arg_local ) ) ? ;
self . write_value ( arg_val , dest , arg_ty ) ? ;
2017-03-23 10:04:08 +01:00
}
2017-03-23 13:36:13 +01:00
Ok ( ( ) )
2017-03-23 14:24:02 +01:00
} ,
ty ::InstanceDef ::Virtual ( _ , idx ) = > {
let ptr_size = self . memory . pointer_size ( ) ;
2017-03-23 14:57:11 +01:00
let ( _ , vtable ) = self . eval_operand ( & arg_operands [ 0 ] ) ? . expect_ptr_vtable_pair ( & self . memory ) ? ;
2017-06-05 18:07:26 -07:00
let fn_ptr = self . memory . read_ptr ( vtable . offset ( ptr_size * ( idx as u64 + 3 ) , self . memory . layout ) ? ) ? ;
2017-06-21 21:45:51 -07:00
let instance = self . memory . get_fn ( fn_ptr . to_ptr ( ) ? ) ? ;
2017-03-23 18:32:57 +01:00
let mut arg_operands = arg_operands . to_vec ( ) ;
let ty = self . operand_ty ( & arg_operands [ 0 ] ) ;
let ty = self . get_field_ty ( ty , 0 ) ? ;
match arg_operands [ 0 ] {
mir ::Operand ::Consume ( ref mut lval ) = > * lval = lval . clone ( ) . field ( mir ::Field ::new ( 0 ) , ty ) ,
_ = > bug! ( " virtual call first arg cannot be a constant " ) ,
}
2017-03-23 14:57:11 +01:00
// recurse with concrete function
self . eval_fn_call (
2017-03-23 14:24:02 +01:00
instance ,
destination ,
2017-03-23 18:32:57 +01:00
& arg_operands ,
2017-03-23 14:24:02 +01:00
span ,
2017-03-23 14:57:11 +01:00
sig ,
)
2017-03-23 14:24:02 +01:00
} ,
2017-02-28 12:35:00 +01:00
}
}
2016-06-23 01:03:58 -06:00
2017-03-23 17:36:10 +01:00
/// Returns Ok(true) when the function was handled completely due to mir not being available
2017-02-28 12:35:00 +01:00
fn eval_fn_call_inner (
& mut self ,
2017-03-21 13:53:55 +01:00
instance : ty ::Instance < ' tcx > ,
2017-02-28 12:35:00 +01:00
destination : Option < ( Lvalue < ' tcx > , mir ::BasicBlock ) > ,
2017-05-26 12:25:25 -07:00
arg_operands : & [ mir ::Operand < ' tcx > ] ,
2017-02-28 12:35:00 +01:00
span : Span ,
2017-05-26 12:25:25 -07:00
sig : ty ::FnSig < ' tcx > ,
2017-03-23 17:36:10 +01:00
) -> EvalResult < ' tcx , bool > {
2017-03-23 13:36:13 +01:00
trace! ( " eval_fn_call_inner: {:#?}, {:#?} " , instance , destination ) ;
2017-03-22 13:13:52 +01:00
// Only trait methods can have a Self parameter.
2017-02-28 12:35:00 +01:00
2017-03-21 13:53:55 +01:00
let mir = match self . load_mir ( instance . def ) {
2017-02-28 12:35:00 +01:00
Ok ( mir ) = > mir ,
Err ( EvalError ::NoMirFor ( path ) ) = > {
2017-06-28 09:40:25 +02:00
if self . const_env ( ) {
2017-06-26 17:58:47 +02:00
return Err ( EvalError ::NeedsRfc ( format! ( " calling extern function ` {} ` " , path ) ) ) ;
}
2017-05-26 12:25:25 -07:00
self . call_missing_fn ( instance , destination , arg_operands , sig , path ) ? ;
return Ok ( true ) ;
2017-02-28 12:35:00 +01:00
} ,
Err ( other ) = > return Err ( other ) ,
} ;
2017-06-26 17:58:47 +02:00
2017-06-28 09:40:25 +02:00
if self . const_env ( ) & & ! self . tcx . is_const_fn ( instance . def_id ( ) ) {
2017-06-26 17:58:47 +02:00
return Err ( EvalError ::NotConst ( format! ( " calling non-const fn ` {} ` " , instance ) ) ) ;
}
2017-02-28 12:35:00 +01:00
let ( return_lvalue , return_to_block ) = match destination {
2017-06-19 13:29:04 +02:00
Some ( ( lvalue , block ) ) = > ( lvalue , StackPopCleanup ::Goto ( block ) ) ,
None = > ( Lvalue ::undef ( ) , StackPopCleanup ::None ) ,
2017-02-28 12:35:00 +01:00
} ;
self . push_stack_frame (
2017-03-21 13:53:55 +01:00
instance ,
2017-02-28 12:35:00 +01:00
span ,
mir ,
return_lvalue ,
return_to_block ,
) ? ;
2017-03-23 17:36:10 +01:00
Ok ( false )
2016-06-23 01:03:58 -06:00
}
2017-02-24 10:39:55 +01:00
pub fn read_discriminant_value ( & self , adt_ptr : Pointer , adt_ty : Ty < ' tcx > ) -> EvalResult < ' tcx , u128 > {
2016-06-23 01:03:58 -06:00
use rustc ::ty ::layout ::Layout ::* ;
2016-11-17 17:23:40 +01:00
let adt_layout = self . type_layout ( adt_ty ) ? ;
2017-01-28 15:46:46 +01:00
trace! ( " read_discriminant_value {:#?} " , adt_layout ) ;
2016-06-23 01:03:58 -06:00
let discr_val = match * adt_layout {
2016-11-05 02:53:02 +00:00
General { discr , .. } | CEnum { discr , signed : false , .. } = > {
2016-06-23 01:03:58 -06:00
let discr_size = discr . size ( ) . bytes ( ) ;
2016-11-18 12:55:14 +01:00
self . memory . read_uint ( adt_ptr , discr_size ) ?
2016-06-23 01:03:58 -06:00
}
2016-11-05 02:53:02 +00:00
CEnum { discr , signed : true , .. } = > {
let discr_size = discr . size ( ) . bytes ( ) ;
2017-01-12 08:28:42 +01:00
self . memory . read_int ( adt_ptr , discr_size ) ? as u128
2016-11-05 02:53:02 +00:00
}
2016-11-11 13:10:47 +01:00
RawNullablePointer { nndiscr , value } = > {
2016-11-18 12:55:14 +01:00
let discr_size = value . size ( & self . tcx . data_layout ) . bytes ( ) ;
2016-11-17 14:48:34 +01:00
trace! ( " rawnullablepointer with size {} " , discr_size ) ;
2017-01-12 08:28:42 +01:00
self . read_nonnull_discriminant_value ( adt_ptr , nndiscr as u128 , discr_size ) ?
2016-06-23 01:03:58 -06:00
}
StructWrappedNullablePointer { nndiscr , ref discrfield , .. } = > {
2016-11-11 13:10:47 +01:00
let ( offset , ty ) = self . nonnull_offset_and_ty ( adt_ty , nndiscr , discrfield ) ? ;
2017-06-05 18:07:26 -07:00
let nonnull = adt_ptr . offset ( offset . bytes ( ) , self . memory . layout ) ? ;
2016-11-17 14:48:34 +01:00
trace! ( " struct wrapped nullable pointer type: {} " , ty ) ;
2016-11-11 13:10:47 +01:00
// only the pointer part of a fat pointer is used for this space optimization
2016-11-17 17:23:40 +01:00
let discr_size = self . type_size ( ty ) ? . expect ( " bad StructWrappedNullablePointer discrfield " ) ;
2017-01-12 08:28:42 +01:00
self . read_nonnull_discriminant_value ( nonnull , nndiscr as u128 , discr_size ) ?
2016-06-23 01:03:58 -06:00
}
// The discriminant_value intrinsic returns 0 for non-sum types.
Array { .. } | FatPointer { .. } | Scalar { .. } | Univariant { .. } |
2016-09-07 10:12:15 +02:00
Vector { .. } | UntaggedUnion { .. } = > 0 ,
2016-06-23 01:03:58 -06:00
} ;
Ok ( discr_val )
}
2017-01-12 08:28:42 +01:00
fn read_nonnull_discriminant_value ( & self , ptr : Pointer , nndiscr : u128 , discr_size : u64 ) -> EvalResult < ' tcx , u128 > {
2017-01-28 15:46:46 +01:00
trace! ( " read_nonnull_discriminant_value: {:?}, {}, {} " , ptr , nndiscr , discr_size ) ;
2016-11-11 13:10:47 +01:00
let not_null = match self . memory . read_uint ( ptr , discr_size ) {
2016-06-23 01:03:58 -06:00
Ok ( 0 ) = > false ,
Ok ( _ ) | Err ( EvalError ::ReadPointerAsBytes ) = > true ,
Err ( e ) = > return Err ( e ) ,
} ;
assert! ( nndiscr = = 0 | | nndiscr = = 1 ) ;
Ok ( if not_null { nndiscr } else { 1 - nndiscr } )
}
2017-05-26 12:25:25 -07:00
/// Returns Ok() when the function was handled, fail otherwise
fn call_missing_fn (
& mut self ,
instance : ty ::Instance < ' tcx > ,
destination : Option < ( Lvalue < ' tcx > , mir ::BasicBlock ) > ,
arg_operands : & [ mir ::Operand < ' tcx > ] ,
sig : ty ::FnSig < ' tcx > ,
path : String ,
) -> EvalResult < ' tcx > {
if sig . abi = = Abi ::C {
// An external C function
let ty = sig . output ( ) ;
let ( ret , target ) = destination . unwrap ( ) ;
2017-05-26 17:27:39 -07:00
self . call_c_abi ( instance . def_id ( ) , arg_operands , ret , ty , target ) ? ;
2017-05-26 12:25:25 -07:00
return Ok ( ( ) ) ;
}
// A Rust function is missing, which means we are running with MIR missing for libstd (or other dependencies).
// Still, we can make many things mostly work by "emulating" or ignoring some functions.
match & path [ .. ] {
" std::io::_print " = > {
2017-05-30 10:24:37 -07:00
trace! ( " Ignoring output. To run programs that print, make sure you have a libstd with full MIR. " ) ;
2017-05-26 12:25:25 -07:00
self . goto_block ( destination . unwrap ( ) . 1 ) ;
Ok ( ( ) )
} ,
" std::thread::Builder::new " = > Err ( EvalError ::Unimplemented ( " miri does not support threading " . to_owned ( ) ) ) ,
" std::env::args " = > Err ( EvalError ::Unimplemented ( " miri does not support program arguments " . to_owned ( ) ) ) ,
" std::panicking::rust_panic_with_hook " |
" std::rt::begin_panic_fmt " = > Err ( EvalError ::Panic ) ,
" std::panicking::panicking " |
" std::rt::panicking " = > {
let ( lval , block ) = destination . expect ( " std::rt::panicking does not diverge " ) ;
// we abort on panic -> `std::rt::panicking` always returns false
let bool = self . tcx . types . bool ;
self . write_primval ( lval , PrimVal ::from_bool ( false ) , bool ) ? ;
self . goto_block ( block ) ;
Ok ( ( ) )
}
_ = > Err ( EvalError ::NoMirFor ( path ) ) ,
}
}
2016-06-23 01:03:58 -06:00
fn call_c_abi (
& mut self ,
def_id : DefId ,
2017-05-25 16:40:13 -07:00
arg_operands : & [ mir ::Operand < ' tcx > ] ,
2016-10-21 10:29:56 +02:00
dest : Lvalue < ' tcx > ,
2016-11-26 22:58:01 -08:00
dest_ty : Ty < ' tcx > ,
2017-05-26 17:27:39 -07:00
dest_block : mir ::BasicBlock ,
2017-02-04 13:09:10 -08:00
) -> EvalResult < ' tcx > {
2016-06-23 01:03:58 -06:00
let name = self . tcx . item_name ( def_id ) ;
let attrs = self . tcx . get_attrs ( def_id ) ;
2016-11-26 17:36:31 -08:00
let link_name = attr ::first_attr_value_str_by_name ( & attrs , " link_name " )
. unwrap_or ( name )
. as_str ( ) ;
2016-06-23 01:03:58 -06:00
2017-05-25 16:40:13 -07:00
let args_res : EvalResult < Vec < Value > > = arg_operands . iter ( )
2016-09-23 10:27:14 +02:00
. map ( | arg | self . eval_operand ( arg ) )
2016-06-23 01:03:58 -06:00
. collect ( ) ;
let args = args_res ? ;
2016-09-23 10:27:14 +02:00
let usize = self . tcx . types . usize ;
2016-06-23 01:03:58 -06:00
match & link_name [ .. ] {
2017-06-21 15:51:42 +02:00
" malloc " = > {
let size = self . value_to_primval ( args [ 0 ] , usize ) ? . to_u64 ( ) ? ;
2017-06-22 08:52:53 +02:00
if size = = 0 {
self . write_primval ( dest , PrimVal ::Bytes ( 0 ) , dest_ty ) ? ;
} else {
let align = self . memory . pointer_size ( ) ;
let ptr = self . memory . allocate ( size , align ) ? ;
self . write_primval ( dest , PrimVal ::Ptr ( ptr ) , dest_ty ) ? ;
}
2017-06-21 15:51:42 +02:00
}
" free " = > {
2017-06-22 08:52:53 +02:00
let ptr = args [ 0 ] . read_ptr ( & self . memory ) ? ;
2017-06-22 11:40:06 +02:00
if ! ptr . is_null ( ) ? {
2017-06-22 08:52:53 +02:00
self . memory . deallocate ( ptr . to_ptr ( ) ? ) ? ;
}
2017-06-21 15:51:42 +02:00
}
2017-06-21 16:34:40 +02:00
" syscall " = > {
match self . value_to_primval ( args [ 0 ] , usize ) ? . to_u64 ( ) ? {
511 = > return Err ( EvalError ::Unimplemented ( " miri does not support random number generators " . to_owned ( ) ) ) ,
id = > return Err ( EvalError ::Unimplemented ( format! ( " miri does not support syscall id {} " , id ) ) ) ,
}
}
" dlsym " = > {
2017-06-22 11:33:39 -07:00
let _handle = args [ 0 ] . read_ptr ( & self . memory ) ? ;
let symbol = args [ 1 ] . read_ptr ( & self . memory ) ? . to_ptr ( ) ? ;
let symbol_name = self . memory . read_c_str ( symbol ) ? ;
let err = format! ( " bad c unicode symbol: {:?} " , symbol_name ) ;
let symbol_name = ::std ::str ::from_utf8 ( symbol_name ) . unwrap_or ( & err ) ;
return Err ( EvalError ::Unimplemented ( format! ( " miri does not support dynamically loading libraries (requested symbol: {} ) " , symbol_name ) ) ) ;
2017-06-21 16:34:40 +02:00
}
2016-06-23 01:03:58 -06:00
" __rust_allocate " = > {
2016-12-16 22:01:01 -08:00
let size = self . value_to_primval ( args [ 0 ] , usize ) ? . to_u64 ( ) ? ;
let align = self . value_to_primval ( args [ 1 ] , usize ) ? . to_u64 ( ) ? ;
2017-06-23 12:55:49 +02:00
if size = = 0 {
return Err ( EvalError ::HeapAllocZeroBytes ) ;
}
if ! align . is_power_of_two ( ) {
return Err ( EvalError ::HeapAllocNonPowerOfTwoAlignment ( align ) ) ;
}
2016-11-18 12:55:14 +01:00
let ptr = self . memory . allocate ( size , align ) ? ;
2016-12-15 23:55:00 -08:00
self . write_primval ( dest , PrimVal ::Ptr ( ptr ) , dest_ty ) ? ;
2016-06-23 01:03:58 -06:00
}
2017-05-21 15:48:31 -04:00
" __rust_allocate_zeroed " = > {
let size = self . value_to_primval ( args [ 0 ] , usize ) ? . to_u64 ( ) ? ;
let align = self . value_to_primval ( args [ 1 ] , usize ) ? . to_u64 ( ) ? ;
2017-06-23 12:55:49 +02:00
if size = = 0 {
return Err ( EvalError ::HeapAllocZeroBytes ) ;
}
if ! align . is_power_of_two ( ) {
return Err ( EvalError ::HeapAllocNonPowerOfTwoAlignment ( align ) ) ;
}
2017-05-21 15:48:31 -04:00
let ptr = self . memory . allocate ( size , align ) ? ;
self . memory . write_repeat ( ptr , 0 , size ) ? ;
self . write_primval ( dest , PrimVal ::Ptr ( ptr ) , dest_ty ) ? ;
}
2016-11-03 17:32:06 +01:00
" __rust_deallocate " = > {
2017-06-19 10:58:59 +02:00
let ptr = args [ 0 ] . read_ptr ( & self . memory ) ? . to_ptr ( ) ? ;
2016-11-03 17:32:06 +01:00
// FIXME: insert sanity check for size and align?
2017-06-23 12:55:49 +02:00
let old_size = self . value_to_primval ( args [ 1 ] , usize ) ? . to_u64 ( ) ? ;
let align = self . value_to_primval ( args [ 2 ] , usize ) ? . to_u64 ( ) ? ;
if old_size = = 0 {
return Err ( EvalError ::HeapAllocZeroBytes ) ;
}
if ! align . is_power_of_two ( ) {
return Err ( EvalError ::HeapAllocNonPowerOfTwoAlignment ( align ) ) ;
}
2016-11-03 17:32:06 +01:00
self . memory . deallocate ( ptr ) ? ;
} ,
2016-06-23 01:03:58 -06:00
" __rust_reallocate " = > {
2017-06-19 10:58:59 +02:00
let ptr = args [ 0 ] . read_ptr ( & self . memory ) ? . to_ptr ( ) ? ;
2016-12-16 22:01:01 -08:00
let size = self . value_to_primval ( args [ 2 ] , usize ) ? . to_u64 ( ) ? ;
let align = self . value_to_primval ( args [ 3 ] , usize ) ? . to_u64 ( ) ? ;
2017-06-23 12:55:49 +02:00
if size = = 0 {
return Err ( EvalError ::HeapAllocZeroBytes ) ;
}
if ! align . is_power_of_two ( ) {
return Err ( EvalError ::HeapAllocNonPowerOfTwoAlignment ( align ) ) ;
}
2016-11-18 12:55:14 +01:00
let new_ptr = self . memory . reallocate ( ptr , size , align ) ? ;
2016-12-15 23:55:00 -08:00
self . write_primval ( dest , PrimVal ::Ptr ( new_ptr ) , dest_ty ) ? ;
2016-06-23 01:03:58 -06:00
}
2017-05-26 17:27:39 -07:00
" __rust_maybe_catch_panic " = > {
2017-05-30 10:24:37 -07:00
// fn __rust_maybe_catch_panic(f: fn(*mut u8), data: *mut u8, data_ptr: *mut usize, vtable_ptr: *mut usize) -> u32
2017-05-26 17:27:39 -07:00
// We abort on panic, so not much is going on here, but we still have to call the closure
let u8_ptr_ty = self . tcx . mk_mut_ptr ( self . tcx . types . u8 ) ;
2017-06-19 10:58:59 +02:00
let f = args [ 0 ] . read_ptr ( & self . memory ) ? . to_ptr ( ) ? ;
2017-05-30 10:24:37 -07:00
let data = args [ 1 ] . read_ptr ( & self . memory ) ? ;
2017-06-21 21:45:51 -07:00
let f_instance = self . memory . get_fn ( f ) ? ;
2017-05-26 17:27:39 -07:00
self . write_primval ( dest , PrimVal ::Bytes ( 0 ) , dest_ty ) ? ;
2017-05-30 10:24:37 -07:00
// Now we make a function call. TODO: Consider making this re-usable? EvalContext::step does sth. similar for the TLS dtors,
// and of course eval_main.
2017-05-26 17:27:39 -07:00
let mir = self . load_mir ( f_instance . def ) ? ;
self . push_stack_frame (
f_instance ,
mir . span ,
mir ,
2017-06-23 12:55:49 +02:00
Lvalue ::undef ( ) ,
2017-05-26 17:27:39 -07:00
StackPopCleanup ::Goto ( dest_block ) ,
) ? ;
let arg_local = self . frame ( ) . mir . args_iter ( ) . next ( ) . ok_or ( EvalError ::AbiViolation ( " Argument to __rust_maybe_catch_panic does not take enough arguments. " . to_owned ( ) ) ) ? ;
2017-05-30 10:24:37 -07:00
let arg_dest = self . eval_lvalue ( & mir ::Lvalue ::Local ( arg_local ) ) ? ;
2017-06-19 10:58:59 +02:00
self . write_primval ( arg_dest , data , u8_ptr_ty ) ? ;
2017-05-30 10:24:37 -07:00
2017-06-21 19:24:21 -07:00
// We ourselves return 0
2017-05-30 10:24:37 -07:00
self . write_primval ( dest , PrimVal ::Bytes ( 0 ) , dest_ty ) ? ;
2017-05-26 17:27:39 -07:00
// Don't fall through
return Ok ( ( ) ) ;
}
2017-05-26 20:27:39 -07:00
" __rust_start_panic " = > {
return Err ( EvalError ::Panic ) ;
}
2016-06-23 01:03:58 -06:00
" memcmp " = > {
2017-06-20 16:26:53 +02:00
let left = args [ 0 ] . read_ptr ( & self . memory ) ? ;
let right = args [ 1 ] . read_ptr ( & self . memory ) ? ;
2016-12-16 22:01:01 -08:00
let n = self . value_to_primval ( args [ 2 ] , usize ) ? . to_u64 ( ) ? ;
2016-06-23 01:03:58 -06:00
let result = {
let left_bytes = self . memory . read_bytes ( left , n ) ? ;
let right_bytes = self . memory . read_bytes ( right , n ) ? ;
use std ::cmp ::Ordering ::* ;
match left_bytes . cmp ( right_bytes ) {
2017-01-12 08:28:42 +01:00
Less = > - 1 i8 ,
2016-06-23 01:03:58 -06:00
Equal = > 0 ,
Greater = > 1 ,
}
} ;
2017-01-12 08:28:42 +01:00
self . write_primval ( dest , PrimVal ::Bytes ( result as u128 ) , dest_ty ) ? ;
2016-06-23 01:03:58 -06:00
}
2017-01-12 09:26:22 +01:00
" memrchr " = > {
2017-06-20 16:26:53 +02:00
let ptr = args [ 0 ] . read_ptr ( & self . memory ) ? ;
2017-01-12 09:30:18 +01:00
let val = self . value_to_primval ( args [ 1 ] , usize ) ? . to_u64 ( ) ? as u8 ;
let num = self . value_to_primval ( args [ 2 ] , usize ) ? . to_u64 ( ) ? ;
2017-01-12 09:26:22 +01:00
if let Some ( idx ) = self . memory . read_bytes ( ptr , num ) ? . iter ( ) . rev ( ) . position ( | & c | c = = val ) {
2017-06-05 18:07:26 -07:00
let new_ptr = ptr . offset ( num - idx as u64 - 1 , self . memory . layout ) ? ;
2017-06-20 16:26:53 +02:00
self . write_primval ( dest , new_ptr , dest_ty ) ? ;
2017-01-12 09:26:22 +01:00
} else {
2017-05-25 16:40:13 -07:00
self . write_primval ( dest , PrimVal ::Bytes ( 0 ) , dest_ty ) ? ;
2017-01-12 09:26:22 +01:00
}
}
2016-12-16 17:10:16 -08:00
" memchr " = > {
2017-06-20 16:26:53 +02:00
let ptr = args [ 0 ] . read_ptr ( & self . memory ) ? ;
2016-12-16 22:01:01 -08:00
let val = self . value_to_primval ( args [ 1 ] , usize ) ? . to_u64 ( ) ? as u8 ;
let num = self . value_to_primval ( args [ 2 ] , usize ) ? . to_u64 ( ) ? ;
2016-12-16 17:10:16 -08:00
if let Some ( idx ) = self . memory . read_bytes ( ptr , num ) ? . iter ( ) . position ( | & c | c = = val ) {
2017-06-05 18:07:26 -07:00
let new_ptr = ptr . offset ( idx as u64 , self . memory . layout ) ? ;
2017-06-20 16:26:53 +02:00
self . write_primval ( dest , new_ptr , dest_ty ) ? ;
2016-12-16 17:10:16 -08:00
} else {
2017-05-25 16:40:13 -07:00
self . write_primval ( dest , PrimVal ::Bytes ( 0 ) , dest_ty ) ? ;
2016-12-16 17:10:16 -08:00
}
}
" getenv " = > {
2017-06-21 14:06:23 +02:00
let result = {
2017-06-19 10:58:59 +02:00
let name_ptr = args [ 0 ] . read_ptr ( & self . memory ) ? . to_ptr ( ) ? ;
2016-12-16 17:10:16 -08:00
let name = self . memory . read_c_str ( name_ptr ) ? ;
2017-06-21 14:06:23 +02:00
match self . env_vars . get ( name ) {
Some ( & var ) = > PrimVal ::Ptr ( var ) ,
None = > PrimVal ::Bytes ( 0 ) ,
}
} ;
self . write_primval ( dest , result , dest_ty ) ? ;
}
" unsetenv " = > {
let mut success = None ;
{
let name_ptr = args [ 0 ] . read_ptr ( & self . memory ) ? ;
if ! name_ptr . is_null ( ) ? {
let name = self . memory . read_c_str ( name_ptr . to_ptr ( ) ? ) ? ;
if ! name . is_empty ( ) & & ! name . contains ( & b '=' ) {
success = Some ( self . env_vars . remove ( name ) ) ;
}
}
}
if let Some ( old ) = success {
if let Some ( var ) = old {
self . memory . deallocate ( var ) ? ;
}
self . write_primval ( dest , PrimVal ::Bytes ( 0 ) , dest_ty ) ? ;
} else {
self . write_primval ( dest , PrimVal ::from_i128 ( - 1 ) , dest_ty ) ? ;
}
}
" setenv " = > {
let mut new = None ;
{
let name_ptr = args [ 0 ] . read_ptr ( & self . memory ) ? ;
let value_ptr = args [ 1 ] . read_ptr ( & self . memory ) ? . to_ptr ( ) ? ;
let value = self . memory . read_c_str ( value_ptr ) ? ;
if ! name_ptr . is_null ( ) ? {
let name = self . memory . read_c_str ( name_ptr . to_ptr ( ) ? ) ? ;
if ! name . is_empty ( ) & & ! name . contains ( & b '=' ) {
new = Some ( ( name . to_owned ( ) , value . to_owned ( ) ) ) ;
}
}
}
if let Some ( ( name , value ) ) = new {
// +1 for the null terminator
let value_copy = self . memory . allocate ( ( value . len ( ) + 1 ) as u64 , 1 ) ? ;
self . memory . write_bytes ( value_copy , & value ) ? ;
self . memory . write_bytes ( value_copy . offset ( value . len ( ) as u64 , self . memory . layout ) ? , & [ 0 ] ) ? ;
if let Some ( var ) = self . env_vars . insert ( name . to_owned ( ) , value_copy ) {
self . memory . deallocate ( var ) ? ;
}
self . write_primval ( dest , PrimVal ::Bytes ( 0 ) , dest_ty ) ? ;
} else {
self . write_primval ( dest , PrimVal ::from_i128 ( - 1 ) , dest_ty ) ? ;
2016-12-16 17:10:16 -08:00
}
}
2017-05-26 17:27:39 -07:00
2017-05-24 15:11:29 -07:00
" write " = > {
let fd = self . value_to_primval ( args [ 0 ] , usize ) ? . to_u64 ( ) ? ;
2017-06-20 16:26:53 +02:00
let buf = args [ 1 ] . read_ptr ( & self . memory ) ? ;
2017-05-24 15:11:29 -07:00
let n = self . value_to_primval ( args [ 2 ] , usize ) ? . to_u64 ( ) ? ;
trace! ( " Called write({:?}, {:?}, {:?}) " , fd , buf , n ) ;
2017-05-24 21:01:13 -07:00
let result = if fd = = 1 | | fd = = 2 { // stdout/stderr
2017-05-24 15:11:29 -07:00
use std ::io ::{ self , Write } ;
let buf_cont = self . memory . read_bytes ( buf , n ) ? ;
2017-05-24 21:01:13 -07:00
let res = if fd = = 1 { io ::stdout ( ) . write ( buf_cont ) } else { io ::stderr ( ) . write ( buf_cont ) } ;
2017-05-24 15:11:29 -07:00
match res { Ok ( n ) = > n as isize , Err ( _ ) = > - 1 }
} else {
info! ( " Ignored output to FD {} " , fd ) ;
n as isize // pretend it all went well
} ; // now result is the value we return back to the program
self . write_primval ( dest , PrimVal ::Bytes ( result as u128 ) , dest_ty ) ? ;
}
2016-12-16 17:10:16 -08:00
2017-06-21 14:06:23 +02:00
" strlen " = > {
let ptr = args [ 0 ] . read_ptr ( & self . memory ) ? . to_ptr ( ) ? ;
let n = self . memory . read_c_str ( ptr ) ? . len ( ) ;
self . write_primval ( dest , PrimVal ::Bytes ( n as u128 ) , dest_ty ) ? ;
}
2017-05-26 17:36:16 -07:00
// Some things needed for sys::thread initialization to go through
" signal " | " sigaction " | " sigaltstack " = > {
2016-12-16 22:01:01 -08:00
self . write_primval ( dest , PrimVal ::Bytes ( 0 ) , dest_ty ) ? ;
2016-12-16 17:10:16 -08:00
}
2017-05-26 17:36:16 -07:00
" sysconf " = > {
let name = self . value_to_primval ( args [ 0 ] , usize ) ? . to_u64 ( ) ? ;
trace! ( " sysconf() called with name {} " , name ) ;
let result = match name {
2017-06-21 14:06:23 +02:00
30 = > PrimVal ::Bytes ( 4096 ) , // _SC_PAGESIZE
70 = > PrimVal ::from_i128 ( - 1 ) , // _SC_GETPW_R_SIZE_MAX
2017-05-26 17:36:16 -07:00
_ = > return Err ( EvalError ::Unimplemented ( format! ( " Unimplemented sysconf name: {} " , name ) ) )
} ;
2017-06-21 14:06:23 +02:00
self . write_primval ( dest , result , dest_ty ) ? ;
2017-05-26 17:36:16 -07:00
}
" mmap " = > {
// This is a horrible hack, but well... the guard page mechanism calls mmap and expects a particular return value, so we give it that value
let addr = args [ 0 ] . read_ptr ( & self . memory ) ? ;
2017-06-19 10:58:59 +02:00
self . write_primval ( dest , addr , dest_ty ) ? ;
2017-05-26 17:36:16 -07:00
}
2017-05-25 16:40:13 -07:00
// Hook pthread calls that go to the thread-local storage memory subsystem
" pthread_key_create " = > {
let key_ptr = args [ 0 ] . read_ptr ( & self . memory ) ? ;
2017-05-31 10:43:36 -04:00
2017-05-25 22:38:07 -07:00
// Extract the function type out of the signature (that seems easier than constructing it ourselves...)
2017-06-19 10:58:59 +02:00
let dtor = match args [ 1 ] . read_ptr ( & self . memory ) ? {
2017-06-21 21:45:51 -07:00
PrimVal ::Ptr ( dtor_ptr ) = > Some ( self . memory . get_fn ( dtor_ptr ) ? ) ,
2017-06-19 10:58:59 +02:00
PrimVal ::Bytes ( 0 ) = > None ,
PrimVal ::Bytes ( _ ) = > return Err ( EvalError ::ReadBytesAsPointer ) ,
PrimVal ::Undef = > return Err ( EvalError ::ReadUndefBytes ) ,
} ;
2017-05-31 10:43:36 -04:00
2017-05-25 16:40:13 -07:00
// Figure out how large a pthread TLS key actually is. This is libc::pthread_key_t.
2017-06-01 17:24:21 -07:00
let key_type = self . operand_ty ( & arg_operands [ 0 ] ) . builtin_deref ( true , ty ::LvaluePreference ::NoPreference )
. ok_or ( EvalError ::AbiViolation ( " Wrong signature used for pthread_key_create: First argument must be a raw pointer. " . to_owned ( ) ) ) ? . ty ;
let key_size = {
let layout = self . type_layout ( key_type ) ? ;
layout . size ( & self . tcx . data_layout )
2017-05-25 16:40:13 -07:00
} ;
2017-05-31 10:43:36 -04:00
2017-05-25 22:38:07 -07:00
// Create key and write it into the memory where key_ptr wants it
2017-05-31 10:43:36 -04:00
let key = self . memory . create_tls_key ( dtor ) as u128 ;
if key_size . bits ( ) < 128 & & key > = ( 1 u128 < < key_size . bits ( ) as u128 ) {
2017-05-25 16:40:13 -07:00
return Err ( EvalError ::OutOfTls ) ;
}
2017-06-02 18:35:33 -07:00
// TODO: Does this need checking for alignment?
2017-06-19 10:58:59 +02:00
self . memory . write_uint ( key_ptr . to_ptr ( ) ? , key , key_size . bytes ( ) ) ? ;
2017-05-31 10:43:36 -04:00
2017-05-25 16:40:13 -07:00
// Return success (0)
self . write_primval ( dest , PrimVal ::Bytes ( 0 ) , dest_ty ) ? ;
}
" pthread_key_delete " = > {
// The conversion into TlsKey here is a little fishy, but should work as long as usize >= libc::pthread_key_t
let key = self . value_to_primval ( args [ 0 ] , usize ) ? . to_u64 ( ) ? as TlsKey ;
self . memory . delete_tls_key ( key ) ? ;
// Return success (0)
self . write_primval ( dest , PrimVal ::Bytes ( 0 ) , dest_ty ) ? ;
}
" pthread_getspecific " = > {
// The conversion into TlsKey here is a little fishy, but should work as long as usize >= libc::pthread_key_t
let key = self . value_to_primval ( args [ 0 ] , usize ) ? . to_u64 ( ) ? as TlsKey ;
let ptr = self . memory . load_tls ( key ) ? ;
2017-06-19 10:58:59 +02:00
self . write_primval ( dest , ptr , dest_ty ) ? ;
2017-05-25 16:40:13 -07:00
}
" pthread_setspecific " = > {
// The conversion into TlsKey here is a little fishy, but should work as long as usize >= libc::pthread_key_t
let key = self . value_to_primval ( args [ 0 ] , usize ) ? . to_u64 ( ) ? as TlsKey ;
let new_ptr = args [ 1 ] . read_ptr ( & self . memory ) ? ;
self . memory . store_tls ( key , new_ptr ) ? ;
// Return success (0)
self . write_primval ( dest , PrimVal ::Bytes ( 0 ) , dest_ty ) ? ;
}
2017-05-26 17:36:16 -07:00
// Stub out all the other pthread calls to just return 0
2016-12-16 17:10:16 -08:00
link_name if link_name . starts_with ( " pthread_ " ) = > {
warn! ( " ignoring C ABI call: {} " , link_name ) ;
2017-05-26 17:36:16 -07:00
self . write_primval ( dest , PrimVal ::Bytes ( 0 ) , dest_ty ) ? ;
2016-12-16 17:10:16 -08:00
} ,
2016-06-23 01:03:58 -06:00
_ = > {
return Err ( EvalError ::Unimplemented ( format! ( " can't call C ABI function: {} " , link_name ) ) ) ;
}
}
// Since we pushed no stack frame, the main loop will act
// as if the call just completed and it's returning to the
// current frame.
2017-05-26 17:27:39 -07:00
self . dump_local ( dest ) ;
self . goto_block ( dest_block ) ;
2016-06-23 01:03:58 -06:00
Ok ( ( ) )
2017-05-26 17:27:39 -07:00
}
2016-09-20 12:52:01 +02:00
}