@@ -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,68 @@ 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
+ // 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.
283
298
let bytes = match v. as_mplace_or_imm ( ) {
284
299
either:: Either :: Left ( mplace) => {
285
300
// Get the alloc id corresponding to this mplace, alongside
286
301
// a pointer that's offset to point to this particular
287
302
// mplace (not one at the base addr of the allocation).
288
- let mplace_ptr = mplace. ptr ( ) ;
289
303
let sz = mplace. layout . size . bytes_usize ( ) ;
290
304
if sz == 0 {
291
305
throw_unsup_format ! ( "attempting to pass a ZST over FFI" ) ;
292
306
}
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 ( ) ) ?;
294
308
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.
297
312
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) ?;
311
315
}
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) )
312
320
}
313
321
either:: Either :: Right ( imm) => {
322
+ let mut bytes: Box < [ u8 ] > = vec ! [ 0 ; imm. layout. size. bytes_usize( ) ] . into ( ) ;
323
+
314
324
// 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 | {
316
326
// If a scalar is a pointer, then expose its provenance.
317
327
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 ) ?;
321
329
}
322
- // `bytes[0]` should be the first byte we want to write to.
323
330
write_target_uint (
324
331
this. data_layout ( ) . endian ,
325
- & mut bytes[ ..sc. size ( ) . bytes_usize ( ) ] ,
332
+ & mut bytes[ pos.. ] [ ..sc. size ( ) . bytes_usize ( ) ] ,
326
333
sc. to_scalar_int ( ) ?. to_bits_unchecked ( ) ,
327
334
)
328
335
. unwrap ( ) ;
329
336
interp_ok ( ( ) )
330
337
} ;
331
338
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.
335
340
match * imm {
336
- Immediate :: Scalar ( sc) => write_scalar ( this, sc, & mut bytes ) ?,
341
+ Immediate :: Scalar ( sc) => write_scalar ( this, sc, 0 ) ?,
337
342
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 .
339
344
let ofs_second = {
340
345
let rustc_abi:: BackendRepr :: ScalarPair ( a, b) = imm. layout . backend_repr
341
346
else {
@@ -348,11 +353,12 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
348
353
a. size ( this) . align_to ( b. align ( this) . abi ) . bytes_usize ( )
349
354
} ;
350
355
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.
353
361
}
354
- Immediate :: Uninit =>
355
- span_bug ! ( this. cur_span( ) , "op_to_ffi_arg: argument is uninit: {:#?}" , imm) ,
356
362
}
357
363
358
364
bytes
@@ -381,7 +387,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
381
387
382
388
let this = self . eval_context_ref ( ) ;
383
389
let mut fields = vec ! [ ] ;
384
- for field in adt_def. all_fields ( ) {
390
+ for field in & adt_def. non_enum_variant ( ) . fields {
385
391
fields. push ( this. ty_to_ffitype ( field. ty ( * this. tcx , args) ) ?) ;
386
392
}
387
393
@@ -407,20 +413,6 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
407
413
_ => throw_unsup_format ! ( "unsupported argument type for native call: {}" , ty) ,
408
414
} )
409
415
}
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
416
}
425
417
426
418
impl < ' tcx > EvalContextExt < ' tcx > for crate :: MiriInterpCx < ' tcx > { }
@@ -472,8 +464,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
472
464
std:: hint:: black_box ( alloc. get_bytes_unchecked_raw ( ) . expose_provenance ( ) ) ;
473
465
474
466
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.
477
470
for prov in alloc. provenance ( ) . provenances ( ) {
478
471
this. expose_provenance ( prov) ?;
479
472
}
@@ -483,7 +476,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
483
476
if info. mutbl . is_mut ( ) {
484
477
let ( alloc, cx) = this. get_alloc_raw_mut ( alloc_id) ?;
485
478
// 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.
487
481
if !tracing {
488
482
alloc. process_native_write ( & cx. tcx , None ) ;
489
483
}
0 commit comments