@@ -76,7 +76,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
7676 & mut self ,
7777 link_name : Symbol ,
7878 dest : & MPlaceTy < ' tcx > ,
79- ptr : CodePtr ,
79+ fun : CodePtr ,
8080 libffi_args : & mut [ OwnedArg ] ,
8181 ) -> InterpResult < ' tcx , ( crate :: ImmTy < ' tcx > , Option < MemEvents > ) > {
8282 let this = self . eval_context_mut ( ) ;
@@ -95,54 +95,54 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
9595 // Unsafe because of the call to native code.
9696 // Because this is calling a C function it is not necessarily sound,
9797 // but there is no way around this and we've checked as much as we can.
98- let x = unsafe { ffi:: call :: < i8 > ( ptr , libffi_args) } ;
98+ let x = unsafe { ffi:: call :: < i8 > ( fun , libffi_args) } ;
9999 Scalar :: from_i8 ( x)
100100 }
101101 ty:: Int ( IntTy :: I16 ) => {
102- let x = unsafe { ffi:: call :: < i16 > ( ptr , libffi_args) } ;
102+ let x = unsafe { ffi:: call :: < i16 > ( fun , libffi_args) } ;
103103 Scalar :: from_i16 ( x)
104104 }
105105 ty:: Int ( IntTy :: I32 ) => {
106- let x = unsafe { ffi:: call :: < i32 > ( ptr , libffi_args) } ;
106+ let x = unsafe { ffi:: call :: < i32 > ( fun , libffi_args) } ;
107107 Scalar :: from_i32 ( x)
108108 }
109109 ty:: Int ( IntTy :: I64 ) => {
110- let x = unsafe { ffi:: call :: < i64 > ( ptr , libffi_args) } ;
110+ let x = unsafe { ffi:: call :: < i64 > ( fun , libffi_args) } ;
111111 Scalar :: from_i64 ( x)
112112 }
113113 ty:: Int ( IntTy :: Isize ) => {
114- let x = unsafe { ffi:: call :: < isize > ( ptr , libffi_args) } ;
114+ let x = unsafe { ffi:: call :: < isize > ( fun , libffi_args) } ;
115115 Scalar :: from_target_isize ( x. try_into ( ) . unwrap ( ) , this)
116116 }
117117 // uints
118118 ty:: Uint ( UintTy :: U8 ) => {
119- let x = unsafe { ffi:: call :: < u8 > ( ptr , libffi_args) } ;
119+ let x = unsafe { ffi:: call :: < u8 > ( fun , libffi_args) } ;
120120 Scalar :: from_u8 ( x)
121121 }
122122 ty:: Uint ( UintTy :: U16 ) => {
123- let x = unsafe { ffi:: call :: < u16 > ( ptr , libffi_args) } ;
123+ let x = unsafe { ffi:: call :: < u16 > ( fun , libffi_args) } ;
124124 Scalar :: from_u16 ( x)
125125 }
126126 ty:: Uint ( UintTy :: U32 ) => {
127- let x = unsafe { ffi:: call :: < u32 > ( ptr , libffi_args) } ;
127+ let x = unsafe { ffi:: call :: < u32 > ( fun , libffi_args) } ;
128128 Scalar :: from_u32 ( x)
129129 }
130130 ty:: Uint ( UintTy :: U64 ) => {
131- let x = unsafe { ffi:: call :: < u64 > ( ptr , libffi_args) } ;
131+ let x = unsafe { ffi:: call :: < u64 > ( fun , libffi_args) } ;
132132 Scalar :: from_u64 ( x)
133133 }
134134 ty:: Uint ( UintTy :: Usize ) => {
135- let x = unsafe { ffi:: call :: < usize > ( ptr , libffi_args) } ;
135+ let x = unsafe { ffi:: call :: < usize > ( fun , libffi_args) } ;
136136 Scalar :: from_target_usize ( x. try_into ( ) . unwrap ( ) , this)
137137 }
138138 // Functions with no declared return type (i.e., the default return)
139139 // have the output_type `Tuple([])`.
140140 ty:: Tuple ( t_list) if ( * t_list) . deref ( ) . is_empty ( ) => {
141- unsafe { ffi:: call :: < ( ) > ( ptr , libffi_args) } ;
141+ unsafe { ffi:: call :: < ( ) > ( fun , libffi_args) } ;
142142 return interp_ok ( ImmTy :: uninit ( dest. layout ) ) ;
143143 }
144144 ty:: RawPtr ( ..) => {
145- let x = unsafe { ffi:: call :: < * const ( ) > ( ptr , libffi_args) } ;
145+ let x = unsafe { ffi:: call :: < * const ( ) > ( fun , libffi_args) } ;
146146 let ptr = StrictPointer :: new ( Provenance :: Wildcard , Size :: from_bytes ( x. addr ( ) ) ) ;
147147 Scalar :: from_pointer ( ptr, this)
148148 }
@@ -279,63 +279,68 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
279279 // of extra work for types that aren't supported yet.
280280 let ty = this. ty_to_ffitype ( v. layout . ty ) ?;
281281
282- // Now grab the bytes of the argument.
282+ // Helper to print a warning when a pointer is shared with the native code.
283+ let expose = |prov : Provenance | -> InterpResult < ' tcx > {
284+ // The first time this happens, print a warning.
285+ if !this. machine . native_call_mem_warned . replace ( true ) {
286+ // Newly set, so first time we get here.
287+ this. emit_diagnostic ( NonHaltingDiagnostic :: NativeCallSharedMem { tracing } ) ;
288+ }
289+
290+ this. expose_provenance ( prov) ?;
291+ interp_ok ( ( ) )
292+ } ;
293+
294+ // Compute the byte-level representation of the argument. If there's a pointer in there, we
295+ // expose it inside the AM. Later in `visit_reachable_allocs`, the "meta"-level provenance
296+ // for accessing the pointee gets exposed; this is crucial to justify the C code effectively
297+ // casting the integer in `byte` to a pointer and using that.
283298 let bytes = match v. as_mplace_or_imm ( ) {
284299 either:: Either :: Left ( mplace) => {
285300 // Get the alloc id corresponding to this mplace, alongside
286301 // a pointer that's offset to point to this particular
287302 // mplace (not one at the base addr of the allocation).
288- let mplace_ptr = mplace. ptr ( ) ;
289303 let sz = mplace. layout . size . bytes_usize ( ) ;
290304 if sz == 0 {
291305 throw_unsup_format ! ( "attempting to pass a ZST over FFI" ) ;
292306 }
293- let ( id, ofs, _) = this. ptr_get_alloc_id ( mplace_ptr , sz. try_into ( ) . unwrap ( ) ) ?;
307+ let ( id, ofs, _) = this. ptr_get_alloc_id ( mplace . ptr ( ) , sz. try_into ( ) . unwrap ( ) ) ?;
294308 let ofs = ofs. bytes_usize ( ) ;
295- // Expose all provenances in the allocation within the byte
296- // range of the struct, if any.
309+ let range = ofs..ofs. strict_add ( sz) ;
310+ // Expose all provenances in the allocation within the byte range of the struct, if
311+ // any. These pointers are being directly passed to native code by-value.
297312 let alloc = this. get_alloc_raw ( id) ?;
298- let alloc_ptr = this. get_alloc_bytes_unchecked_raw ( id) ?;
299- for prov in alloc. provenance ( ) . get_range ( this, ( ofs..ofs. strict_add ( sz) ) . into ( ) ) {
300- this. expose_provenance ( prov) ?;
301- }
302- // SAFETY: We know for sure that at alloc_ptr + ofs the next layout.size
303- // bytes are part of this allocation and initialised. They might be marked
304- // as uninit in Miri, but all bytes returned by `MiriAllocBytes` are
305- // initialised.
306- unsafe {
307- Box :: from ( std:: slice:: from_raw_parts (
308- alloc_ptr. add ( ofs) ,
309- mplace. layout . size . bytes_usize ( ) ,
310- ) )
313+ for prov in alloc. provenance ( ) . get_range ( this, range. clone ( ) . into ( ) ) {
314+ expose ( prov) ?;
311315 }
316+ // Read the bytes that make up this argument. We cannot use the normal getter as
317+ // those would fail if any part of the argument is uninitialized. Native code
318+ // is kind of outside the interpreter, after all...
319+ Box :: from ( alloc. inspect_with_uninit_and_ptr_outside_interpreter ( range) )
312320 }
313321 either:: Either :: Right ( imm) => {
322+ let mut bytes: Box < [ u8 ] > = vec ! [ 0 ; imm. layout. size. bytes_usize( ) ] . into ( ) ;
323+
314324 // A little helper to write scalars to our byte array.
315- let write_scalar = |this : & MiriInterpCx < ' tcx > , sc : Scalar , bytes : & mut [ u8 ] | {
325+ let mut write_scalar = |this : & MiriInterpCx < ' tcx > , sc : Scalar , pos : usize | {
316326 // If a scalar is a pointer, then expose its provenance.
317327 if let interpret:: Scalar :: Ptr ( p, _) = sc {
318- // This relies on the `expose_provenance` in the `visit_reachable_allocs` callback
319- // below to expose the actual interpreter-level allocation.
320- this. expose_and_warn ( Some ( p. provenance ) , tracing) ?;
328+ expose ( p. provenance ) ?;
321329 }
322- // `bytes[0]` should be the first byte we want to write to.
323330 write_target_uint (
324331 this. data_layout ( ) . endian ,
325- & mut bytes[ ..sc. size ( ) . bytes_usize ( ) ] ,
332+ & mut bytes[ pos.. ] [ ..sc. size ( ) . bytes_usize ( ) ] ,
326333 sc. to_scalar_int ( ) ?. to_bits_unchecked ( ) ,
327334 )
328335 . unwrap ( ) ;
329336 interp_ok ( ( ) )
330337 } ;
331338
332- let mut bytes: Box < [ u8 ] > =
333- ( 0 ..imm. layout . size . bytes_usize ( ) ) . map ( |_| 0u8 ) . collect ( ) ;
334-
339+ // Write the scalar into the `bytes` buffer.
335340 match * imm {
336- Immediate :: Scalar ( sc) => write_scalar ( this, sc, & mut bytes ) ?,
341+ Immediate :: Scalar ( sc) => write_scalar ( this, sc, 0 ) ?,
337342 Immediate :: ScalarPair ( sc_first, sc_second) => {
338- // The first scalar has an offset of zero.
343+ // The first scalar has an offset of zero; compute the offset of the 2nd .
339344 let ofs_second = {
340345 let rustc_abi:: BackendRepr :: ScalarPair ( a, b) = imm. layout . backend_repr
341346 else {
@@ -348,11 +353,12 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
348353 a. size ( this) . align_to ( b. align ( this) . abi ) . bytes_usize ( )
349354 } ;
350355
351- write_scalar ( this, sc_first, & mut bytes) ?;
352- write_scalar ( this, sc_second, & mut bytes[ ofs_second..] ) ?;
356+ write_scalar ( this, sc_first, 0 ) ?;
357+ write_scalar ( this, sc_second, ofs_second) ?;
358+ }
359+ Immediate :: Uninit => {
360+ // Nothing to write.
353361 }
354- Immediate :: Uninit =>
355- span_bug ! ( this. cur_span( ) , "op_to_ffi_arg: argument is uninit: {:#?}" , imm) ,
356362 }
357363
358364 bytes
@@ -381,7 +387,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
381387
382388 let this = self . eval_context_ref ( ) ;
383389 let mut fields = vec ! [ ] ;
384- for field in adt_def. all_fields ( ) {
390+ for field in & adt_def. non_enum_variant ( ) . fields {
385391 fields. push ( this. ty_to_ffitype ( field. ty ( * this. tcx , args) ) ?) ;
386392 }
387393
@@ -407,20 +413,6 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
407413 _ => throw_unsup_format ! ( "unsupported argument type for native call: {}" , ty) ,
408414 } )
409415 }
410-
411- fn expose_and_warn ( & self , prov : Option < Provenance > , tracing : bool ) -> InterpResult < ' tcx > {
412- let this = self . eval_context_ref ( ) ;
413- if let Some ( prov) = prov {
414- // The first time this happens, print a warning.
415- if !this. machine . native_call_mem_warned . replace ( true ) {
416- // Newly set, so first time we get here.
417- this. emit_diagnostic ( NonHaltingDiagnostic :: NativeCallSharedMem { tracing } ) ;
418- }
419-
420- this. expose_provenance ( prov) ?;
421- } ;
422- interp_ok ( ( ) )
423- }
424416}
425417
426418impl < ' tcx > EvalContextExt < ' tcx > for crate :: MiriInterpCx < ' tcx > { }
@@ -472,8 +464,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
472464 std:: hint:: black_box ( alloc. get_bytes_unchecked_raw ( ) . expose_provenance ( ) ) ;
473465
474466 if !tracing {
475- // Expose all provenances in this allocation, since the native code can do $whatever.
476- // Can be skipped when tracing; in that case we'll expose just the actually-read parts later.
467+ // Expose all provenances in this allocation, since the native code can do
468+ // $whatever. Can be skipped when tracing; in that case we'll expose just the
469+ // actually-read parts later.
477470 for prov in alloc. provenance ( ) . provenances ( ) {
478471 this. expose_provenance ( prov) ?;
479472 }
@@ -483,7 +476,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
483476 if info. mutbl . is_mut ( ) {
484477 let ( alloc, cx) = this. get_alloc_raw_mut ( alloc_id) ?;
485478 // These writes could initialize everything and wreck havoc with the pointers.
486- // We can skip that when tracing; in that case we'll later do that only for the memory that got actually written.
479+ // We can skip that when tracing; in that case we'll later do that only for the
480+ // memory that got actually written.
487481 if !tracing {
488482 alloc. process_native_write ( & cx. tcx , None ) ;
489483 }
0 commit comments