|
1 | 1 | use std::collections::hash_map::Entry; |
2 | 2 | use std::io::Write; |
| 3 | +use std::iter; |
3 | 4 | use std::path::Path; |
4 | 5 |
|
5 | 6 | use rustc_abi::{Align, AlignFromBytesError, Size}; |
@@ -502,34 +503,127 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> { |
502 | 503 | } |
503 | 504 |
|
504 | 505 | // Rust allocation |
505 | | - "miri_alloc" => { |
506 | | - let [size, align] = this.check_shim(abi, Conv::Rust, link_name, args)?; |
507 | | - let size = this.read_target_usize(size)?; |
508 | | - let align = this.read_target_usize(align)?; |
| 506 | + "__rust_alloc" | "miri_alloc" => { |
| 507 | + let default = |ecx: &mut MiriInterpCx<'tcx>| { |
| 508 | + // Only call `check_shim` when `#[global_allocator]` isn't used. When that |
| 509 | + // macro is used, we act like no shim exists, so that the exported function can run. |
| 510 | + let [size, align] = ecx.check_shim(abi, Conv::Rust, link_name, args)?; |
| 511 | + let size = ecx.read_target_usize(size)?; |
| 512 | + let align = ecx.read_target_usize(align)?; |
| 513 | + |
| 514 | + ecx.check_rustc_alloc_request(size, align)?; |
| 515 | + |
| 516 | + let memory_kind = match link_name.as_str() { |
| 517 | + "__rust_alloc" => MiriMemoryKind::Rust, |
| 518 | + "miri_alloc" => MiriMemoryKind::Miri, |
| 519 | + _ => unreachable!(), |
| 520 | + }; |
509 | 521 |
|
510 | | - this.check_rustc_alloc_request(size, align)?; |
| 522 | + let ptr = ecx.allocate_ptr( |
| 523 | + Size::from_bytes(size), |
| 524 | + Align::from_bytes(align).unwrap(), |
| 525 | + memory_kind.into(), |
| 526 | + AllocInit::Uninit, |
| 527 | + )?; |
511 | 528 |
|
512 | | - let ptr = this.allocate_ptr( |
513 | | - Size::from_bytes(size), |
514 | | - Align::from_bytes(align).unwrap(), |
515 | | - MiriMemoryKind::Miri.into(), |
516 | | - AllocInit::Uninit, |
517 | | - )?; |
| 529 | + ecx.write_pointer(ptr, dest) |
| 530 | + }; |
518 | 531 |
|
519 | | - this.write_pointer(ptr, dest)?; |
| 532 | + match link_name.as_str() { |
| 533 | + "__rust_alloc" => return this.emulate_allocator(default), |
| 534 | + "miri_alloc" => { |
| 535 | + default(this)?; |
| 536 | + return interp_ok(EmulateItemResult::NeedsReturn); |
| 537 | + } |
| 538 | + _ => unreachable!(), |
| 539 | + } |
520 | 540 | } |
521 | | - "miri_dealloc" => { |
522 | | - let [ptr, old_size, align] = this.check_shim(abi, Conv::Rust, link_name, args)?; |
523 | | - let ptr = this.read_pointer(ptr)?; |
524 | | - let old_size = this.read_target_usize(old_size)?; |
525 | | - let align = this.read_target_usize(align)?; |
| 541 | + "__rust_alloc_zeroed" => { |
| 542 | + return this.emulate_allocator(|this| { |
| 543 | + // See the comment for `__rust_alloc` why `check_shim` is only called in the |
| 544 | + // default case. |
| 545 | + let [size, align] = this.check_shim(abi, Conv::Rust, link_name, args)?; |
| 546 | + let size = this.read_target_usize(size)?; |
| 547 | + let align = this.read_target_usize(align)?; |
| 548 | + |
| 549 | + this.check_rustc_alloc_request(size, align)?; |
| 550 | + |
| 551 | + let ptr = this.allocate_ptr( |
| 552 | + Size::from_bytes(size), |
| 553 | + Align::from_bytes(align).unwrap(), |
| 554 | + MiriMemoryKind::Rust.into(), |
| 555 | + AllocInit::Zero, |
| 556 | + )?; |
526 | 557 |
|
527 | | - // No need to check old_size/align; we anyway check that they match the allocation. |
528 | | - this.deallocate_ptr( |
529 | | - ptr, |
530 | | - Some((Size::from_bytes(old_size), Align::from_bytes(align).unwrap())), |
531 | | - MiriMemoryKind::Miri.into(), |
532 | | - )?; |
| 558 | + // We just allocated this, the access is definitely in-bounds. |
| 559 | + this.write_bytes_ptr( |
| 560 | + ptr.into(), |
| 561 | + iter::repeat(0u8).take(usize::try_from(size).unwrap()), |
| 562 | + ) |
| 563 | + .unwrap(); |
| 564 | + this.write_pointer(ptr, dest) |
| 565 | + }); |
| 566 | + } |
| 567 | + "__rust_dealloc" | "miri_dealloc" => { |
| 568 | + let default = |ecx: &mut MiriInterpCx<'tcx>| { |
| 569 | + // See the comment for `__rust_alloc` why `check_shim` is only called in the |
| 570 | + // default case. |
| 571 | + let [ptr, old_size, align] = |
| 572 | + ecx.check_shim(abi, Conv::Rust, link_name, args)?; |
| 573 | + let ptr = ecx.read_pointer(ptr)?; |
| 574 | + let old_size = ecx.read_target_usize(old_size)?; |
| 575 | + let align = ecx.read_target_usize(align)?; |
| 576 | + |
| 577 | + let memory_kind = match link_name.as_str() { |
| 578 | + "__rust_dealloc" => MiriMemoryKind::Rust, |
| 579 | + "miri_dealloc" => MiriMemoryKind::Miri, |
| 580 | + _ => unreachable!(), |
| 581 | + }; |
| 582 | + |
| 583 | + // No need to check old_size/align; we anyway check that they match the allocation. |
| 584 | + ecx.deallocate_ptr( |
| 585 | + ptr, |
| 586 | + Some((Size::from_bytes(old_size), Align::from_bytes(align).unwrap())), |
| 587 | + memory_kind.into(), |
| 588 | + ) |
| 589 | + }; |
| 590 | + |
| 591 | + match link_name.as_str() { |
| 592 | + "__rust_dealloc" => { |
| 593 | + return this.emulate_allocator(default); |
| 594 | + } |
| 595 | + "miri_dealloc" => { |
| 596 | + default(this)?; |
| 597 | + return interp_ok(EmulateItemResult::NeedsReturn); |
| 598 | + } |
| 599 | + _ => unreachable!(), |
| 600 | + } |
| 601 | + } |
| 602 | + "__rust_realloc" => { |
| 603 | + return this.emulate_allocator(|this| { |
| 604 | + // See the comment for `__rust_alloc` why `check_shim` is only called in the |
| 605 | + // default case. |
| 606 | + let [ptr, old_size, align, new_size] = |
| 607 | + this.check_shim(abi, Conv::Rust, link_name, args)?; |
| 608 | + let ptr = this.read_pointer(ptr)?; |
| 609 | + let old_size = this.read_target_usize(old_size)?; |
| 610 | + let align = this.read_target_usize(align)?; |
| 611 | + let new_size = this.read_target_usize(new_size)?; |
| 612 | + // No need to check old_size; we anyway check that they match the allocation. |
| 613 | + |
| 614 | + this.check_rustc_alloc_request(new_size, align)?; |
| 615 | + |
| 616 | + let align = Align::from_bytes(align).unwrap(); |
| 617 | + let new_ptr = this.reallocate_ptr( |
| 618 | + ptr, |
| 619 | + Some((Size::from_bytes(old_size), align)), |
| 620 | + Size::from_bytes(new_size), |
| 621 | + align, |
| 622 | + MiriMemoryKind::Rust.into(), |
| 623 | + AllocInit::Uninit, |
| 624 | + )?; |
| 625 | + this.write_pointer(new_ptr, dest) |
| 626 | + }); |
533 | 627 | } |
534 | 628 |
|
535 | 629 | // C memory handling functions |
|
0 commit comments