@@ -6,6 +6,7 @@ use std::{
66use log:: trace;
77
88use rustc_apfloat:: Float ;
9+ use rustc_ast:: expand:: allocator:: AllocatorKind ;
910use rustc_hir:: {
1011 def:: DefKind ,
1112 def_id:: { CrateNum , DefId , LOCAL_CRATE } ,
@@ -27,11 +28,13 @@ use super::backtrace::EvalContextExt as _;
2728use crate :: * ;
2829
2930/// Returned by `emulate_foreign_item_by_name`.
30- pub enum EmulateByNameResult {
31+ pub enum EmulateByNameResult < ' mir , ' tcx > {
3132 /// The caller is expected to jump to the return block.
3233 NeedsJumping ,
3334 /// Jumping has already been taken care of.
3435 AlreadyJumped ,
36+ /// A MIR body has been found for the function
37+ MirBody ( & ' mir mir:: Body < ' tcx > ) ,
3538 /// The item is not supported.
3639 NotSupported ,
3740}
@@ -281,6 +284,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
281284 this. go_to_block ( ret) ;
282285 }
283286 EmulateByNameResult :: AlreadyJumped => ( ) ,
287+ EmulateByNameResult :: MirBody ( mir) => return Ok ( Some ( mir) ) ,
284288 EmulateByNameResult :: NotSupported => {
285289 if let Some ( body) = this. lookup_exported_symbol ( link_name) ? {
286290 return Ok ( Some ( body) ) ;
@@ -294,6 +298,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
294298 Ok ( None )
295299 }
296300
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+
297331 /// Emulates calling a foreign item using its name.
298332 fn emulate_foreign_item_by_name (
299333 & mut self ,
@@ -302,7 +336,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
302336 args : & [ OpTy < ' tcx , Tag > ] ,
303337 dest : & PlaceTy < ' tcx , Tag > ,
304338 ret : mir:: BasicBlock ,
305- ) -> InterpResult < ' tcx , EmulateByNameResult > {
339+ ) -> InterpResult < ' tcx , EmulateByNameResult < ' mir , ' tcx > > {
306340 let this = self . eval_context_mut ( ) ;
307341
308342 // 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
362396 }
363397
364398 // 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.)
367399 "__rust_alloc" => {
368400 let & [ ref size, ref align] = this. check_shim ( abi, Abi :: Rust , link_name, args) ?;
369401 let size = this. read_scalar ( size) ?. to_machine_usize ( this) ?;
370402 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+ } ) ;
378415 }
379416 "__rust_alloc_zeroed" => {
380417 let & [ ref size, ref align] = this. check_shim ( abi, Abi :: Rust , link_name, args) ?;
381418 let size = this. read_scalar ( size) ?. to_machine_usize ( this) ?;
382419 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+ } ) ;
392434 }
393435 "__rust_dealloc" => {
394436 let & [ ref ptr, ref old_size, ref align] = this. check_shim ( abi, Abi :: Rust , link_name, args) ?;
395437 let ptr = this. read_pointer ( ptr) ?;
396438 let old_size = this. read_scalar ( old_size) ?. to_machine_usize ( this) ?;
397439 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+ } ) ;
404449 }
405450 "__rust_realloc" => {
406451 let & [ ref ptr, ref old_size, ref align, ref new_size] = this. check_shim ( abi, Abi :: Rust , link_name, args) ?;
407452 let ptr = this. read_pointer ( ptr) ?;
408453 let old_size = this. read_scalar ( old_size) ?. to_machine_usize ( this) ?;
409454 let align = this. read_scalar ( align) ?. to_machine_usize ( this) ?;
410455 let new_size = this. read_scalar ( new_size) ?. to_machine_usize ( this) ?;
411- Self :: check_alloc_request ( new_size, align) ?;
412456 // 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+ } ) ;
422471 }
423472
424473 // C memory handling functions
0 commit comments