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