@@ -347,7 +347,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
347
347
/// Emulates calling the internal __rust_* allocator functions
348
348
fn emulate_allocator (
349
349
& mut self ,
350
- symbol : Symbol ,
351
350
default : impl FnOnce ( & mut MiriInterpCx < ' mir , ' tcx > ) -> InterpResult < ' tcx > ,
352
351
) -> InterpResult < ' tcx , EmulateByNameResult < ' mir , ' tcx > > {
353
352
let this = self . eval_context_mut ( ) ;
@@ -359,11 +358,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
359
358
360
359
match allocator_kind {
361
360
AllocatorKind :: Global => {
362
- let ( body, instance) = this
363
- . lookup_exported_symbol ( symbol) ?
364
- . expect ( "symbol should be present if there is a global allocator" ) ;
365
-
366
- Ok ( EmulateByNameResult :: MirBody ( body, instance) )
361
+ // When `#[global_allocator]` is used, `__rust_*` is defined by the macro expansion
362
+ // of this attribute. As such we have to call an exported Rust function,
363
+ // and not execute any Miri shim. Somewhat unintuitively doing so is done
364
+ // by returning `NotSupported`, which triggers the `lookup_exported_symbol`
365
+ // fallback case in `emulate_foreign_item`.
366
+ return Ok ( EmulateByNameResult :: NotSupported ) ;
367
367
}
368
368
AllocatorKind :: Default => {
369
369
default ( this) ?;
@@ -558,11 +558,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
558
558
559
559
// Rust allocation
560
560
"__rust_alloc" | "miri_alloc" => {
561
- let [ size, align] = this. check_shim ( abi, Abi :: Rust , link_name, args) ?;
562
- let size = this. read_target_usize ( size) ?;
563
- let align = this. read_target_usize ( align) ?;
564
-
565
561
let default = |this : & mut MiriInterpCx < ' mir , ' tcx > | {
562
+ // Only call `check_shim` when `#[global_allocator]` isn't used. When that
563
+ // macro is used, we act like no shim exists, so that the exported function can run.
564
+ let [ size, align] = this. check_shim ( abi, Abi :: Rust , link_name, args) ?;
565
+ let size = this. read_target_usize ( size) ?;
566
+ let align = this. read_target_usize ( align) ?;
567
+
566
568
Self :: check_alloc_request ( size, align) ?;
567
569
568
570
let memory_kind = match link_name. as_str ( ) {
@@ -581,8 +583,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
581
583
} ;
582
584
583
585
match link_name. as_str ( ) {
584
- "__rust_alloc" =>
585
- return this. emulate_allocator ( Symbol :: intern ( "__rg_alloc" ) , default) ,
586
+ "__rust_alloc" => return this. emulate_allocator ( default) ,
586
587
"miri_alloc" => {
587
588
default ( this) ?;
588
589
return Ok ( EmulateByNameResult :: NeedsJumping ) ;
@@ -591,11 +592,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
591
592
}
592
593
}
593
594
"__rust_alloc_zeroed" => {
594
- let [ size, align] = this. check_shim ( abi, Abi :: Rust , link_name, args) ?;
595
- let size = this. read_target_usize ( size) ?;
596
- let align = this. read_target_usize ( align) ?;
595
+ return this. emulate_allocator ( |this| {
596
+ // See the comment for `__rust_alloc` why `check_shim` is only called in the
597
+ // default case.
598
+ let [ size, align] = this. check_shim ( abi, Abi :: Rust , link_name, args) ?;
599
+ let size = this. read_target_usize ( size) ?;
600
+ let align = this. read_target_usize ( align) ?;
597
601
598
- return this. emulate_allocator ( Symbol :: intern ( "__rg_alloc_zeroed" ) , |this| {
599
602
Self :: check_alloc_request ( size, align) ?;
600
603
601
604
let ptr = this. allocate_ptr (
@@ -614,12 +617,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
614
617
} ) ;
615
618
}
616
619
"__rust_dealloc" | "miri_dealloc" => {
617
- let [ ptr, old_size, align] = this. check_shim ( abi, Abi :: Rust , link_name, args) ?;
618
- let ptr = this. read_pointer ( ptr) ?;
619
- let old_size = this. read_target_usize ( old_size) ?;
620
- let align = this. read_target_usize ( align) ?;
621
-
622
620
let default = |this : & mut MiriInterpCx < ' mir , ' tcx > | {
621
+ // See the comment for `__rust_alloc` why `check_shim` is only called in the
622
+ // default case.
623
+ let [ ptr, old_size, align] =
624
+ this. check_shim ( abi, Abi :: Rust , link_name, args) ?;
625
+ let ptr = this. read_pointer ( ptr) ?;
626
+ let old_size = this. read_target_usize ( old_size) ?;
627
+ let align = this. read_target_usize ( align) ?;
628
+
623
629
let memory_kind = match link_name. as_str ( ) {
624
630
"__rust_dealloc" => MiriMemoryKind :: Rust ,
625
631
"miri_dealloc" => MiriMemoryKind :: Miri ,
@@ -635,8 +641,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
635
641
} ;
636
642
637
643
match link_name. as_str ( ) {
638
- "__rust_dealloc" =>
639
- return this. emulate_allocator ( Symbol :: intern ( "__rg_dealloc" ) , default) ,
644
+ "__rust_dealloc" => {
645
+ return this. emulate_allocator ( default) ;
646
+ }
640
647
"miri_dealloc" => {
641
648
default ( this) ?;
642
649
return Ok ( EmulateByNameResult :: NeedsJumping ) ;
@@ -645,15 +652,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
645
652
}
646
653
}
647
654
"__rust_realloc" => {
648
- let [ ptr, old_size, align, new_size] =
649
- this. check_shim ( abi, Abi :: Rust , link_name, args) ?;
650
- let ptr = this. read_pointer ( ptr) ?;
651
- let old_size = this. read_target_usize ( old_size) ?;
652
- let align = this. read_target_usize ( align) ?;
653
- let new_size = this. read_target_usize ( new_size) ?;
654
- // No need to check old_size; we anyway check that they match the allocation.
655
+ return this. emulate_allocator ( |this| {
656
+ // See the comment for `__rust_alloc` why `check_shim` is only called in the
657
+ // default case.
658
+ let [ ptr, old_size, align, new_size] =
659
+ this. check_shim ( abi, Abi :: Rust , link_name, args) ?;
660
+ let ptr = this. read_pointer ( ptr) ?;
661
+ let old_size = this. read_target_usize ( old_size) ?;
662
+ let align = this. read_target_usize ( align) ?;
663
+ let new_size = this. read_target_usize ( new_size) ?;
664
+ // No need to check old_size; we anyway check that they match the allocation.
655
665
656
- return this. emulate_allocator ( Symbol :: intern ( "__rg_realloc" ) , |this| {
657
666
Self :: check_alloc_request ( new_size, align) ?;
658
667
659
668
let align = Align :: from_bytes ( align) . unwrap ( ) ;
0 commit comments