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