@@ -76,7 +76,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
76
76
& mut self ,
77
77
link_name : Symbol ,
78
78
dest : & MPlaceTy < ' tcx > ,
79
- ptr : CodePtr ,
79
+ fun : CodePtr ,
80
80
libffi_args : & mut [ OwnedArg ] ,
81
81
) -> InterpResult < ' tcx , ( crate :: ImmTy < ' tcx > , Option < MemEvents > ) > {
82
82
let this = self . eval_context_mut ( ) ;
@@ -95,54 +95,54 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
95
95
// Unsafe because of the call to native code.
96
96
// Because this is calling a C function it is not necessarily sound,
97
97
// 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) } ;
99
99
Scalar :: from_i8 ( x)
100
100
}
101
101
ty:: Int ( IntTy :: I16 ) => {
102
- let x = unsafe { ffi:: call :: < i16 > ( ptr , libffi_args) } ;
102
+ let x = unsafe { ffi:: call :: < i16 > ( fun , libffi_args) } ;
103
103
Scalar :: from_i16 ( x)
104
104
}
105
105
ty:: Int ( IntTy :: I32 ) => {
106
- let x = unsafe { ffi:: call :: < i32 > ( ptr , libffi_args) } ;
106
+ let x = unsafe { ffi:: call :: < i32 > ( fun , libffi_args) } ;
107
107
Scalar :: from_i32 ( x)
108
108
}
109
109
ty:: Int ( IntTy :: I64 ) => {
110
- let x = unsafe { ffi:: call :: < i64 > ( ptr , libffi_args) } ;
110
+ let x = unsafe { ffi:: call :: < i64 > ( fun , libffi_args) } ;
111
111
Scalar :: from_i64 ( x)
112
112
}
113
113
ty:: Int ( IntTy :: Isize ) => {
114
- let x = unsafe { ffi:: call :: < isize > ( ptr , libffi_args) } ;
114
+ let x = unsafe { ffi:: call :: < isize > ( fun , libffi_args) } ;
115
115
Scalar :: from_target_isize ( x. try_into ( ) . unwrap ( ) , this)
116
116
}
117
117
// uints
118
118
ty:: Uint ( UintTy :: U8 ) => {
119
- let x = unsafe { ffi:: call :: < u8 > ( ptr , libffi_args) } ;
119
+ let x = unsafe { ffi:: call :: < u8 > ( fun , libffi_args) } ;
120
120
Scalar :: from_u8 ( x)
121
121
}
122
122
ty:: Uint ( UintTy :: U16 ) => {
123
- let x = unsafe { ffi:: call :: < u16 > ( ptr , libffi_args) } ;
123
+ let x = unsafe { ffi:: call :: < u16 > ( fun , libffi_args) } ;
124
124
Scalar :: from_u16 ( x)
125
125
}
126
126
ty:: Uint ( UintTy :: U32 ) => {
127
- let x = unsafe { ffi:: call :: < u32 > ( ptr , libffi_args) } ;
127
+ let x = unsafe { ffi:: call :: < u32 > ( fun , libffi_args) } ;
128
128
Scalar :: from_u32 ( x)
129
129
}
130
130
ty:: Uint ( UintTy :: U64 ) => {
131
- let x = unsafe { ffi:: call :: < u64 > ( ptr , libffi_args) } ;
131
+ let x = unsafe { ffi:: call :: < u64 > ( fun , libffi_args) } ;
132
132
Scalar :: from_u64 ( x)
133
133
}
134
134
ty:: Uint ( UintTy :: Usize ) => {
135
- let x = unsafe { ffi:: call :: < usize > ( ptr , libffi_args) } ;
135
+ let x = unsafe { ffi:: call :: < usize > ( fun , libffi_args) } ;
136
136
Scalar :: from_target_usize ( x. try_into ( ) . unwrap ( ) , this)
137
137
}
138
138
// Functions with no declared return type (i.e., the default return)
139
139
// have the output_type `Tuple([])`.
140
140
ty:: Tuple ( t_list) if ( * t_list) . deref ( ) . is_empty ( ) => {
141
- unsafe { ffi:: call :: < ( ) > ( ptr , libffi_args) } ;
141
+ unsafe { ffi:: call :: < ( ) > ( fun , libffi_args) } ;
142
142
return interp_ok ( ImmTy :: uninit ( dest. layout ) ) ;
143
143
}
144
144
ty:: RawPtr ( ..) => {
145
- let x = unsafe { ffi:: call :: < * const ( ) > ( ptr , libffi_args) } ;
145
+ let x = unsafe { ffi:: call :: < * const ( ) > ( fun , libffi_args) } ;
146
146
let ptr = StrictPointer :: new ( Provenance :: Wildcard , Size :: from_bytes ( x. addr ( ) ) ) ;
147
147
Scalar :: from_pointer ( ptr, this)
148
148
}
@@ -279,63 +279,67 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
279
279
// of extra work for types that aren't supported yet.
280
280
let ty = this. ty_to_ffitype ( v. layout . ty ) ?;
281
281
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
+ // Now grab the byte-level representation of the argument. If there's a pointer in there, we
295
+ // rely on its interpreter-level provenance being exposed in the `visit_reachable_allocs`
296
+ // callback.
283
297
let bytes = match v. as_mplace_or_imm ( ) {
284
298
either:: Either :: Left ( mplace) => {
285
299
// Get the alloc id corresponding to this mplace, alongside
286
300
// a pointer that's offset to point to this particular
287
301
// mplace (not one at the base addr of the allocation).
288
- let mplace_ptr = mplace. ptr ( ) ;
289
302
let sz = mplace. layout . size . bytes_usize ( ) ;
290
303
if sz == 0 {
291
304
throw_unsup_format ! ( "attempting to pass a ZST over FFI" ) ;
292
305
}
293
- let ( id, ofs, _) = this. ptr_get_alloc_id ( mplace_ptr , sz. try_into ( ) . unwrap ( ) ) ?;
306
+ let ( id, ofs, _) = this. ptr_get_alloc_id ( mplace . ptr ( ) , sz. try_into ( ) . unwrap ( ) ) ?;
294
307
let ofs = ofs. bytes_usize ( ) ;
295
- // Expose all provenances in the allocation within the byte
296
- // range of the struct, if any.
308
+ let range = ofs..ofs. strict_add ( sz) ;
309
+ // Expose all provenances in the allocation within the byte range of the struct, if
310
+ // any. These pointers are being directly passed to native code by-value.
297
311
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
- ) )
312
+ for prov in alloc. provenance ( ) . get_range ( this, range. clone ( ) . into ( ) ) {
313
+ expose ( prov) ?;
311
314
}
315
+ // Read the bytes that make up this argument. We cannot use the normal getter as
316
+ // those would fail if any part of the argument is uninitialized. Native code
317
+ // is kind of outside the interpreter, after all...
318
+ Box :: from ( alloc. inspect_with_uninit_and_ptr_outside_interpreter ( range) )
312
319
}
313
320
either:: Either :: Right ( imm) => {
321
+ let mut bytes: Box < [ u8 ] > = vec ! [ 0 ; imm. layout. size. bytes_usize( ) ] . into ( ) ;
322
+
314
323
// A little helper to write scalars to our byte array.
315
- let write_scalar = |this : & MiriInterpCx < ' tcx > , sc : Scalar , bytes : & mut [ u8 ] | {
324
+ let mut write_scalar = |this : & MiriInterpCx < ' tcx > , sc : Scalar , pos : usize | {
316
325
// If a scalar is a pointer, then expose its provenance.
317
326
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) ?;
327
+ expose ( p. provenance ) ?;
321
328
}
322
- // `bytes[0]` should be the first byte we want to write to.
323
329
write_target_uint (
324
330
this. data_layout ( ) . endian ,
325
- & mut bytes[ ..sc. size ( ) . bytes_usize ( ) ] ,
331
+ & mut bytes[ pos.. ] [ ..sc. size ( ) . bytes_usize ( ) ] ,
326
332
sc. to_scalar_int ( ) ?. to_bits_unchecked ( ) ,
327
333
)
328
334
. unwrap ( ) ;
329
335
interp_ok ( ( ) )
330
336
} ;
331
337
332
- let mut bytes: Box < [ u8 ] > =
333
- ( 0 ..imm. layout . size . bytes_usize ( ) ) . map ( |_| 0u8 ) . collect ( ) ;
334
-
338
+ // Write the scalar into the `bytes` buffer.
335
339
match * imm {
336
- Immediate :: Scalar ( sc) => write_scalar ( this, sc, & mut bytes ) ?,
340
+ Immediate :: Scalar ( sc) => write_scalar ( this, sc, 0 ) ?,
337
341
Immediate :: ScalarPair ( sc_first, sc_second) => {
338
- // The first scalar has an offset of zero.
342
+ // The first scalar has an offset of zero; compute the offset of the 2nd .
339
343
let ofs_second = {
340
344
let rustc_abi:: BackendRepr :: ScalarPair ( a, b) = imm. layout . backend_repr
341
345
else {
@@ -348,11 +352,12 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
348
352
a. size ( this) . align_to ( b. align ( this) . abi ) . bytes_usize ( )
349
353
} ;
350
354
351
- write_scalar ( this, sc_first, & mut bytes) ?;
352
- write_scalar ( this, sc_second, & mut bytes[ ofs_second..] ) ?;
355
+ write_scalar ( this, sc_first, 0 ) ?;
356
+ write_scalar ( this, sc_second, ofs_second) ?;
357
+ }
358
+ Immediate :: Uninit => {
359
+ // Nothing to write.
353
360
}
354
- Immediate :: Uninit =>
355
- span_bug ! ( this. cur_span( ) , "op_to_ffi_arg: argument is uninit: {:#?}" , imm) ,
356
361
}
357
362
358
363
bytes
@@ -381,7 +386,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
381
386
382
387
let this = self . eval_context_ref ( ) ;
383
388
let mut fields = vec ! [ ] ;
384
- for field in adt_def. all_fields ( ) {
389
+ for field in & adt_def. non_enum_variant ( ) . fields {
385
390
fields. push ( this. ty_to_ffitype ( field. ty ( * this. tcx , args) ) ?) ;
386
391
}
387
392
@@ -407,20 +412,6 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
407
412
_ => throw_unsup_format ! ( "unsupported argument type for native call: {}" , ty) ,
408
413
} )
409
414
}
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
- }
424
415
}
425
416
426
417
impl < ' tcx > EvalContextExt < ' tcx > for crate :: MiriInterpCx < ' tcx > { }
@@ -472,8 +463,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
472
463
std:: hint:: black_box ( alloc. get_bytes_unchecked_raw ( ) . expose_provenance ( ) ) ;
473
464
474
465
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.
466
+ // Expose all provenances in this allocation, since the native code can do
467
+ // $whatever. Can be skipped when tracing; in that case we'll expose just the
468
+ // actually-read parts later.
477
469
for prov in alloc. provenance ( ) . provenances ( ) {
478
470
this. expose_provenance ( prov) ?;
479
471
}
@@ -483,7 +475,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
483
475
if info. mutbl . is_mut ( ) {
484
476
let ( alloc, cx) = this. get_alloc_raw_mut ( alloc_id) ?;
485
477
// 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.
478
+ // We can skip that when tracing; in that case we'll later do that only for the
479
+ // memory that got actually written.
487
480
if !tracing {
488
481
alloc. process_native_write ( & cx. tcx , None ) ;
489
482
}
0 commit comments