@@ -21,7 +21,7 @@ mod ffi;
21
21
) ]
22
22
pub mod trace;
23
23
24
- use self :: ffi:: { CArg , CPrimitive , FfiArg } ;
24
+ use self :: ffi:: { OwnedArg , ScalarArg } ;
25
25
use crate :: * ;
26
26
27
27
/// The final results of an FFI trace, containing every relevant event detected
@@ -72,12 +72,12 @@ impl AccessRange {
72
72
impl < ' tcx > EvalContextExtPriv < ' tcx > for crate :: MiriInterpCx < ' tcx > { }
73
73
trait EvalContextExtPriv < ' tcx > : crate :: MiriInterpCxExt < ' tcx > {
74
74
/// Call native host function and return the output as an immediate.
75
- fn call_native_with_args < ' a > (
75
+ fn call_native_with_args (
76
76
& mut self ,
77
77
link_name : Symbol ,
78
78
dest : & MPlaceTy < ' tcx > ,
79
79
ptr : CodePtr ,
80
- libffi_args : Vec < FfiArg < ' a > > ,
80
+ libffi_args : & [ OwnedArg ] ,
81
81
) -> InterpResult < ' tcx , ( crate :: ImmTy < ' tcx > , Option < MemEvents > ) > {
82
82
let this = self . eval_context_mut ( ) ;
83
83
#[ cfg( target_os = "linux" ) ]
@@ -271,95 +271,90 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
271
271
}
272
272
273
273
/// Extract the value from the result of reading an operand from the machine
274
- /// and convert it to a `CArg `.
275
- fn op_to_ffi_arg ( & self , v : & OpTy < ' tcx > , tracing : bool ) -> InterpResult < ' tcx , CArg > {
274
+ /// and convert it to a `OwnedArg `.
275
+ fn op_to_ffi_arg ( & self , v : & OpTy < ' tcx > , tracing : bool ) -> InterpResult < ' tcx , OwnedArg > {
276
276
let this = self . eval_context_ref ( ) ;
277
277
let scalar = |v| interp_ok ( this. read_immediate ( v) ?. to_scalar ( ) ) ;
278
278
interp_ok ( match v. layout . ty . kind ( ) {
279
279
// If the primitive provided can be converted to a type matching the type pattern
280
- // then create a `CArg ` of this primitive value with the corresponding `CArg ` constructor.
280
+ // then create a `OwnedArg ` of this primitive value with the corresponding `OwnedArg ` constructor.
281
281
// the ints
282
- ty:: Int ( IntTy :: I8 ) => CPrimitive :: Int8 ( scalar ( v) ?. to_i8 ( ) ?) . into ( ) ,
283
- ty:: Int ( IntTy :: I16 ) => CPrimitive :: Int16 ( scalar ( v) ?. to_i16 ( ) ?) . into ( ) ,
284
- ty:: Int ( IntTy :: I32 ) => CPrimitive :: Int32 ( scalar ( v) ?. to_i32 ( ) ?) . into ( ) ,
285
- ty:: Int ( IntTy :: I64 ) => CPrimitive :: Int64 ( scalar ( v) ?. to_i64 ( ) ?) . into ( ) ,
282
+ ty:: Int ( IntTy :: I8 ) => ScalarArg :: Int8 ( scalar ( v) ?. to_i8 ( ) ?) . into ( ) ,
283
+ ty:: Int ( IntTy :: I16 ) => ScalarArg :: Int16 ( scalar ( v) ?. to_i16 ( ) ?) . into ( ) ,
284
+ ty:: Int ( IntTy :: I32 ) => ScalarArg :: Int32 ( scalar ( v) ?. to_i32 ( ) ?) . into ( ) ,
285
+ ty:: Int ( IntTy :: I64 ) => ScalarArg :: Int64 ( scalar ( v) ?. to_i64 ( ) ?) . into ( ) ,
286
286
ty:: Int ( IntTy :: Isize ) =>
287
- CPrimitive :: ISize ( scalar ( v) ?. to_target_isize ( this) ?. try_into ( ) . unwrap ( ) ) . into ( ) ,
287
+ ScalarArg :: ISize ( scalar ( v) ?. to_target_isize ( this) ?. try_into ( ) . unwrap ( ) ) . into ( ) ,
288
288
// the uints
289
- ty:: Uint ( UintTy :: U8 ) => CPrimitive :: UInt8 ( scalar ( v) ?. to_u8 ( ) ?) . into ( ) ,
290
- ty:: Uint ( UintTy :: U16 ) => CPrimitive :: UInt16 ( scalar ( v) ?. to_u16 ( ) ?) . into ( ) ,
291
- ty:: Uint ( UintTy :: U32 ) => CPrimitive :: UInt32 ( scalar ( v) ?. to_u32 ( ) ?) . into ( ) ,
292
- ty:: Uint ( UintTy :: U64 ) => CPrimitive :: UInt64 ( scalar ( v) ?. to_u64 ( ) ?) . into ( ) ,
289
+ ty:: Uint ( UintTy :: U8 ) => ScalarArg :: UInt8 ( scalar ( v) ?. to_u8 ( ) ?) . into ( ) ,
290
+ ty:: Uint ( UintTy :: U16 ) => ScalarArg :: UInt16 ( scalar ( v) ?. to_u16 ( ) ?) . into ( ) ,
291
+ ty:: Uint ( UintTy :: U32 ) => ScalarArg :: UInt32 ( scalar ( v) ?. to_u32 ( ) ?) . into ( ) ,
292
+ ty:: Uint ( UintTy :: U64 ) => ScalarArg :: UInt64 ( scalar ( v) ?. to_u64 ( ) ?) . into ( ) ,
293
293
ty:: Uint ( UintTy :: Usize ) =>
294
- CPrimitive :: USize ( scalar ( v) ?. to_target_usize ( this) ?. try_into ( ) . unwrap ( ) ) . into ( ) ,
294
+ ScalarArg :: USize ( scalar ( v) ?. to_target_usize ( this) ?. try_into ( ) . unwrap ( ) ) . into ( ) ,
295
295
ty:: RawPtr ( ..) => {
296
296
let ptr = scalar ( v) ?. to_pointer ( this) ?;
297
- // Pointer without provenance may not access any memory anyway, skip.
298
- if let Some ( prov) = ptr. provenance {
299
- // The first time this happens, print a warning.
300
- if !this. machine . native_call_mem_warned . replace ( true ) {
301
- // Newly set, so first time we get here.
302
- this. emit_diagnostic ( NonHaltingDiagnostic :: NativeCallSharedMem { tracing } ) ;
303
- }
304
-
305
- this. expose_provenance ( prov) ?;
306
- } ;
297
+ this. expose_and_warn ( ptr. provenance , tracing) ?;
307
298
308
299
// This relies on the `expose_provenance` in the `visit_reachable_allocs` callback
309
300
// below to expose the actual interpreter-level allocation.
310
- CPrimitive :: RawPtr ( std:: ptr:: with_exposed_provenance_mut ( ptr. addr ( ) . bytes_usize ( ) ) )
301
+ ScalarArg :: RawPtr ( std:: ptr:: with_exposed_provenance_mut ( ptr. addr ( ) . bytes_usize ( ) ) )
311
302
. into ( )
312
303
}
313
304
// For ADTs, create an FfiType from their fields.
314
305
ty:: Adt ( adt_def, args) => {
315
- let strukt = this. adt_to_ffitype ( v. layout . ty , * adt_def, args) ?;
306
+ let adt = this. adt_to_ffitype ( v. layout . ty , * adt_def, args) ?;
316
307
317
308
// Copy the raw bytes backing this arg.
318
309
let bytes = match v. as_mplace_or_imm ( ) {
319
310
either:: Either :: Left ( mplace) => {
320
- // We do all of this to grab the bytes without actually
321
- // stripping provenance from them, since it'll later be
322
- // exposed recursively.
323
- let ptr = mplace. ptr ( ) ;
324
- // Make sure the provenance of this allocation is exposed;
325
- // there must be one for this mplace to be valid at all.
326
- // The interpreter-level allocation itself is exposed in
327
- // visit_reachable_allocs.
328
- this. expose_provenance ( ptr. provenance . unwrap ( ) ) ?;
329
- // Then get the actual bytes.
311
+ // Get the alloc id corresponding to this mplace, alongside
312
+ // a pointer that's offset to point to this particular
313
+ // mplace (not one at the base addr of the allocation).
314
+ let mplace_ptr = mplace. ptr ( ) ;
315
+ let sz = mplace. layout . size . bytes_usize ( ) ;
330
316
let id = this
331
317
. alloc_id_from_addr (
332
- ptr . addr ( ) . bytes ( ) ,
333
- mplace . layout . size . bytes_usize ( ) . try_into ( ) . unwrap ( ) ,
334
- /* only_exposed_allocations */ true ,
318
+ mplace_ptr . addr ( ) . bytes ( ) ,
319
+ sz . try_into ( ) . unwrap ( ) ,
320
+ /* only_exposed_allocations */ false ,
335
321
)
336
322
. unwrap ( ) ;
337
- let ptr_raw = this. get_alloc_bytes_unchecked_raw ( id) ?;
338
- // SAFETY: We know for sure that at ptr_raw the next layout.size bytes
339
- // are part of this allocation and initialised. They might be marked as
340
- // uninit in Miri, but all bytes returned by `MiriAllocBytes` are
323
+ // Expose all provenances in the allocation within the byte
324
+ // range of the struct, if any.
325
+ let alloc = this. get_alloc_raw ( id) ?;
326
+ let alloc_ptr = this. get_alloc_bytes_unchecked_raw ( id) ?;
327
+ let start_addr =
328
+ mplace_ptr. addr ( ) . bytes_usize ( ) . strict_sub ( alloc_ptr. addr ( ) ) ;
329
+ for byte in start_addr..start_addr. strict_add ( sz) {
330
+ if let Some ( prov) = alloc. provenance ( ) . get ( Size :: from_bytes ( byte) , this)
331
+ {
332
+ this. expose_provenance ( prov) ?;
333
+ }
334
+ }
335
+ // SAFETY: We know for sure that at mplace_ptr.addr() the next layout.size
336
+ // bytes are part of this allocation and initialised. They might be marked
337
+ // as uninit in Miri, but all bytes returned by `MiriAllocBytes` are
341
338
// initialised.
342
339
unsafe {
343
- std:: slice:: from_raw_parts ( ptr_raw, mplace. layout . size . bytes_usize ( ) )
344
- . to_vec ( )
345
- . into_boxed_slice ( )
340
+ std:: slice:: from_raw_parts (
341
+ alloc_ptr. with_addr ( mplace_ptr. addr ( ) . bytes_usize ( ) ) ,
342
+ mplace. layout . size . bytes_usize ( ) ,
343
+ )
344
+ . to_vec ( )
345
+ . into_boxed_slice ( )
346
346
}
347
347
}
348
- either:: Either :: Right ( imm) => {
349
- // For immediates, we know the backing scalar is going to be 128 bits,
350
- // so we can just copy that.
351
- // TODO: is it possible for this to be a scalar pair?
352
- let scalar = imm. to_scalar ( ) ;
353
- if scalar. size ( ) . bytes ( ) > 0 {
354
- let bits = scalar. to_bits ( scalar. size ( ) ) ?;
355
- bits. to_ne_bytes ( ) . to_vec ( ) . into_boxed_slice ( )
356
- } else {
357
- throw_ub_format ! ( "attempting to pass a ZST over FFI: {}" , imm. layout. ty)
358
- }
348
+ either:: Either :: Right ( _) => {
349
+ // TODO: support this!
350
+ throw_unsup_format ! (
351
+ "Immediate structs can't be passed over FFI: {}" ,
352
+ v. layout. ty
353
+ )
359
354
}
360
355
} ;
361
356
362
- ffi:: CArg :: Struct ( strukt , bytes)
357
+ ffi:: OwnedArg :: Adt ( adt , bytes)
363
358
}
364
359
_ => throw_unsup_format ! ( "unsupported argument type for native call: {}" , v. layout. ty) ,
365
360
} )
@@ -372,14 +367,15 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
372
367
adt_def : ty:: AdtDef < ' tcx > ,
373
368
args : & ' tcx ty:: List < ty:: GenericArg < ' tcx > > ,
374
369
) -> InterpResult < ' tcx , FfiType > {
375
- // TODO: is this correct? Maybe `repr(transparent)` when the inner field
376
- // is itself `repr(c)` is ok?
370
+ // TODO: Certain non-C reprs should be okay also.
377
371
if !adt_def. repr ( ) . c ( ) {
378
- throw_ub_format ! ( "passing a non-#[repr(C)] struct over FFI: {orig_ty}" )
372
+ throw_unsup_format ! ( "passing a non-#[repr(C)] struct over FFI: {orig_ty}" )
379
373
}
380
374
// TODO: unions, etc.
381
375
if !adt_def. is_struct ( ) {
382
- throw_unsup_format ! ( "unsupported argument type for native call: {orig_ty} is an enum or union" ) ;
376
+ throw_unsup_format ! (
377
+ "unsupported argument type for native call: {orig_ty} is an enum or union"
378
+ ) ;
383
379
}
384
380
385
381
let this = self . eval_context_ref ( ) ;
@@ -410,6 +406,20 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
410
406
_ => throw_unsup_format ! ( "unsupported argument type for native call: {}" , ty) ,
411
407
} )
412
408
}
409
+
410
+ fn expose_and_warn ( & self , prov : Option < Provenance > , tracing : bool ) -> InterpResult < ' tcx > {
411
+ let this = self . eval_context_ref ( ) ;
412
+ if let Some ( prov) = prov {
413
+ // The first time this happens, print a warning.
414
+ if !this. machine . native_call_mem_warned . replace ( true ) {
415
+ // Newly set, so first time we get here.
416
+ this. emit_diagnostic ( NonHaltingDiagnostic :: NativeCallSharedMem { tracing } ) ;
417
+ }
418
+
419
+ this. expose_provenance ( prov) ?;
420
+ } ;
421
+ interp_ok ( ( ) )
422
+ }
413
423
}
414
424
415
425
impl < ' tcx > EvalContextExt < ' tcx > for crate :: MiriInterpCx < ' tcx > { }
@@ -439,12 +449,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
439
449
let tracing = trace:: Supervisor :: is_enabled ( ) ;
440
450
441
451
// Get the function arguments, copy them, and prepare the type descriptions.
442
- let mut libffi_args = Vec :: < CArg > :: with_capacity ( args. len ( ) ) ;
452
+ let mut libffi_args = Vec :: < OwnedArg > :: with_capacity ( args. len ( ) ) ;
443
453
for arg in args. iter ( ) {
444
- libffi_args. push ( this. op_to_carg ( arg, tracing) ?) ;
454
+ libffi_args. push ( this. op_to_ffi_arg ( arg, tracing) ?) ;
445
455
}
446
- // Convert arguments to a libffi-compatible type.
447
- let libffi_args = libffi_args. iter ( ) . map ( |arg| arg. arg_downcast ( ) ) . collect :: < Vec < _ > > ( ) ;
448
456
449
457
// Prepare all exposed memory (both previously exposed, and just newly exposed since a
450
458
// pointer was passed as argument). Uninitialised memory is left as-is, but any data
@@ -487,7 +495,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
487
495
488
496
// Call the function and store output, depending on return type in the function signature.
489
497
let ( ret, maybe_memevents) =
490
- this. call_native_with_args ( link_name, dest, code_ptr, libffi_args) ?;
498
+ this. call_native_with_args ( link_name, dest, code_ptr, & libffi_args) ?;
491
499
492
500
if tracing {
493
501
this. tracing_apply_accesses ( maybe_memevents. unwrap ( ) ) ?;
0 commit comments