@@ -6,6 +6,7 @@ use std::{
6
6
use log:: trace;
7
7
8
8
use rustc_apfloat:: Float ;
9
+ use rustc_ast:: expand:: allocator:: AllocatorKind ;
9
10
use rustc_hir:: {
10
11
def:: DefKind ,
11
12
def_id:: { CrateNum , DefId , LOCAL_CRATE } ,
@@ -27,11 +28,13 @@ use super::backtrace::EvalContextExt as _;
27
28
use crate :: * ;
28
29
29
30
/// Returned by `emulate_foreign_item_by_name`.
30
- pub enum EmulateByNameResult {
31
+ pub enum EmulateByNameResult < ' mir , ' tcx > {
31
32
/// The caller is expected to jump to the return block.
32
33
NeedsJumping ,
33
34
/// Jumping has already been taken care of.
34
35
AlreadyJumped ,
36
+ /// A MIR body has been found for the function
37
+ MirBody ( & ' mir mir:: Body < ' tcx > ) ,
35
38
/// The item is not supported.
36
39
NotSupported ,
37
40
}
@@ -281,6 +284,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
281
284
this. go_to_block ( ret) ;
282
285
}
283
286
EmulateByNameResult :: AlreadyJumped => ( ) ,
287
+ EmulateByNameResult :: MirBody ( mir) => return Ok ( Some ( mir) ) ,
284
288
EmulateByNameResult :: NotSupported => {
285
289
if let Some ( body) = this. lookup_exported_symbol ( link_name) ? {
286
290
return Ok ( Some ( body) ) ;
@@ -294,6 +298,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
294
298
Ok ( None )
295
299
}
296
300
301
+ /// Emulates calling the internal __rust_* allocator functions
302
+ fn emulate_allocator (
303
+ & mut self ,
304
+ symbol : Symbol ,
305
+ default : impl FnOnce ( & mut MiriEvalContext < ' mir , ' tcx > ) -> InterpResult < ' tcx > ,
306
+ ) -> InterpResult < ' tcx , EmulateByNameResult < ' mir , ' tcx > > {
307
+ let this = self . eval_context_mut ( ) ;
308
+
309
+ let allocator_kind = if let Some ( allocator_kind) = this. tcx . allocator_kind ( ( ) ) {
310
+ allocator_kind
311
+ } else {
312
+ // in real code, this symbol does not exist without an allocator
313
+ return Ok ( EmulateByNameResult :: NotSupported ) ;
314
+ } ;
315
+
316
+ match allocator_kind {
317
+ AllocatorKind :: Global => {
318
+ let body = this
319
+ . lookup_exported_symbol ( symbol) ?
320
+ . expect ( "symbol should be present if there is a global allocator" ) ;
321
+
322
+ Ok ( EmulateByNameResult :: MirBody ( body) )
323
+ }
324
+ AllocatorKind :: Default => {
325
+ default ( this) ?;
326
+ Ok ( EmulateByNameResult :: NeedsJumping )
327
+ }
328
+ }
329
+ }
330
+
297
331
/// Emulates calling a foreign item using its name.
298
332
fn emulate_foreign_item_by_name (
299
333
& mut self ,
@@ -302,7 +336,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
302
336
args : & [ OpTy < ' tcx , Tag > ] ,
303
337
dest : & PlaceTy < ' tcx , Tag > ,
304
338
ret : mir:: BasicBlock ,
305
- ) -> InterpResult < ' tcx , EmulateByNameResult > {
339
+ ) -> InterpResult < ' tcx , EmulateByNameResult < ' mir , ' tcx > > {
306
340
let this = self . eval_context_mut ( ) ;
307
341
308
342
// Here we dispatch all the shims for foreign functions. If you have a platform specific
@@ -362,63 +396,78 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
362
396
}
363
397
364
398
// Rust allocation
365
- // (Usually these would be forwarded to to `#[global_allocator]`; we instead implement a generic
366
- // allocation that also checks that all conditions are met, such as not permitting zero-sized allocations.)
367
399
"__rust_alloc" => {
368
400
let & [ ref size, ref align] = this. check_shim ( abi, Abi :: Rust , link_name, args) ?;
369
401
let size = this. read_scalar ( size) ?. to_machine_usize ( this) ?;
370
402
let align = this. read_scalar ( align) ?. to_machine_usize ( this) ?;
371
- Self :: check_alloc_request ( size, align) ?;
372
- let ptr = this. memory . allocate (
373
- Size :: from_bytes ( size) ,
374
- Align :: from_bytes ( align) . unwrap ( ) ,
375
- MiriMemoryKind :: Rust . into ( ) ,
376
- ) ?;
377
- this. write_pointer ( ptr, dest) ?;
403
+
404
+ return this. emulate_allocator ( Symbol :: intern ( "__rg_alloc" ) , |this| {
405
+ Self :: check_alloc_request ( size, align) ?;
406
+
407
+ let ptr = this. memory . allocate (
408
+ Size :: from_bytes ( size) ,
409
+ Align :: from_bytes ( align) . unwrap ( ) ,
410
+ MiriMemoryKind :: Rust . into ( ) ,
411
+ ) ?;
412
+
413
+ this. write_pointer ( ptr, dest)
414
+ } ) ;
378
415
}
379
416
"__rust_alloc_zeroed" => {
380
417
let & [ ref size, ref align] = this. check_shim ( abi, Abi :: Rust , link_name, args) ?;
381
418
let size = this. read_scalar ( size) ?. to_machine_usize ( this) ?;
382
419
let align = this. read_scalar ( align) ?. to_machine_usize ( this) ?;
383
- Self :: check_alloc_request ( size, align) ?;
384
- let ptr = this. memory . allocate (
385
- Size :: from_bytes ( size) ,
386
- Align :: from_bytes ( align) . unwrap ( ) ,
387
- MiriMemoryKind :: Rust . into ( ) ,
388
- ) ?;
389
- // We just allocated this, the access is definitely in-bounds.
390
- this. memory . write_bytes ( ptr. into ( ) , iter:: repeat ( 0u8 ) . take ( usize:: try_from ( size) . unwrap ( ) ) ) . unwrap ( ) ;
391
- this. write_pointer ( ptr, dest) ?;
420
+
421
+ return this. emulate_allocator ( Symbol :: intern ( "__rg_alloc_zeroed" ) , |this| {
422
+ Self :: check_alloc_request ( size, align) ?;
423
+
424
+ let ptr = this. memory . allocate (
425
+ Size :: from_bytes ( size) ,
426
+ Align :: from_bytes ( align) . unwrap ( ) ,
427
+ MiriMemoryKind :: Rust . into ( ) ,
428
+ ) ?;
429
+
430
+ // We just allocated this, the access is definitely in-bounds.
431
+ this. memory . write_bytes ( ptr. into ( ) , iter:: repeat ( 0u8 ) . take ( usize:: try_from ( size) . unwrap ( ) ) ) . unwrap ( ) ;
432
+ this. write_pointer ( ptr, dest)
433
+ } ) ;
392
434
}
393
435
"__rust_dealloc" => {
394
436
let & [ ref ptr, ref old_size, ref align] = this. check_shim ( abi, Abi :: Rust , link_name, args) ?;
395
437
let ptr = this. read_pointer ( ptr) ?;
396
438
let old_size = this. read_scalar ( old_size) ?. to_machine_usize ( this) ?;
397
439
let align = this. read_scalar ( align) ?. to_machine_usize ( this) ?;
398
- // No need to check old_size/align; we anyway check that they match the allocation.
399
- this. memory . deallocate (
400
- ptr,
401
- Some ( ( Size :: from_bytes ( old_size) , Align :: from_bytes ( align) . unwrap ( ) ) ) ,
402
- MiriMemoryKind :: Rust . into ( ) ,
403
- ) ?;
440
+
441
+ return this. emulate_allocator ( Symbol :: intern ( "__rg_dealloc" ) , |this| {
442
+ // No need to check old_size/align; we anyway check that they match the allocation.
443
+ this. memory . deallocate (
444
+ ptr,
445
+ Some ( ( Size :: from_bytes ( old_size) , Align :: from_bytes ( align) . unwrap ( ) ) ) ,
446
+ MiriMemoryKind :: Rust . into ( ) ,
447
+ )
448
+ } ) ;
404
449
}
405
450
"__rust_realloc" => {
406
451
let & [ ref ptr, ref old_size, ref align, ref new_size] = this. check_shim ( abi, Abi :: Rust , link_name, args) ?;
407
452
let ptr = this. read_pointer ( ptr) ?;
408
453
let old_size = this. read_scalar ( old_size) ?. to_machine_usize ( this) ?;
409
454
let align = this. read_scalar ( align) ?. to_machine_usize ( this) ?;
410
455
let new_size = this. read_scalar ( new_size) ?. to_machine_usize ( this) ?;
411
- Self :: check_alloc_request ( new_size, align) ?;
412
456
// No need to check old_size; we anyway check that they match the allocation.
413
- let align = Align :: from_bytes ( align) . unwrap ( ) ;
414
- let new_ptr = this. memory . reallocate (
415
- ptr,
416
- Some ( ( Size :: from_bytes ( old_size) , align) ) ,
417
- Size :: from_bytes ( new_size) ,
418
- align,
419
- MiriMemoryKind :: Rust . into ( ) ,
420
- ) ?;
421
- this. write_pointer ( new_ptr, dest) ?;
457
+
458
+ return this. emulate_allocator ( Symbol :: intern ( "__rg_realloc" ) , |this| {
459
+ Self :: check_alloc_request ( new_size, align) ?;
460
+
461
+ let align = Align :: from_bytes ( align) . unwrap ( ) ;
462
+ let new_ptr = this. memory . reallocate (
463
+ ptr,
464
+ Some ( ( Size :: from_bytes ( old_size) , align) ) ,
465
+ Size :: from_bytes ( new_size) ,
466
+ align,
467
+ MiriMemoryKind :: Rust . into ( ) ,
468
+ ) ?;
469
+ this. write_pointer ( new_ptr, dest)
470
+ } ) ;
422
471
}
423
472
424
473
// C memory handling functions
0 commit comments