make return type of get_alloc_info a struct, and reduce some code dup… · rust-lang/rust@4a54ec8 (original) (raw)

`@@ -14,10 +14,9 @@ use std::{fmt, mem, ptr};

`

14

14

`use rustc_abi::{Align, HasDataLayout, Size};

`

15

15

`use rustc_ast::Mutability;

`

16

16

`use rustc_data_structures::fx::{FxHashSet, FxIndexMap};

`

17

``

`-

use rustc_hir::def::DefKind;

`

18

17

`use rustc_middle::bug;

`

19

18

`use rustc_middle::mir::display_allocation;

`

20

``

`-

use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TyCtxt};

`

``

19

`+

use rustc_middle::ty::{self, Instance, Ty, TyCtxt};

`

21

20

`use tracing::{debug, instrument, trace};

`

22

21

``

23

22

`use super::{

`

`@@ -72,6 +71,21 @@ pub enum AllocKind {

`

72

71

`Dead,

`

73

72

`}

`

74

73

``

``

74

`` +

/// Metadata about an AllocId.

``

``

75

`+

#[derive(Copy, Clone, PartialEq, Debug)]

`

``

76

`+

pub struct AllocInfo {

`

``

77

`+

pub size: Size,

`

``

78

`+

pub align: Align,

`

``

79

`+

pub kind: AllocKind,

`

``

80

`+

pub mutbl: Mutability,

`

``

81

`+

}

`

``

82

+

``

83

`+

impl AllocInfo {

`

``

84

`+

fn new(size: Size, align: Align, kind: AllocKind, mutbl: Mutability) -> Self {

`

``

85

`+

Self { size, align, kind, mutbl }

`

``

86

`+

}

`

``

87

`+

}

`

``

88

+

75

89

`/// The value of a function pointer.

`

76

90

`#[derive(Debug, Copy, Clone)]

`

77

91

`pub enum FnVal<'tcx, Other> {

`

`@@ -524,17 +538,22 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {

`

524

538

`match self.ptr_try_get_alloc_id(ptr, 0) {

`

525

539

`Err(addr) => is_offset_misaligned(addr, align),

`

526

540

`Ok((alloc_id, offset, _prov)) => {

`

527

``

`-

let (_size, alloc_align, kind, _mutbl) = self.get_alloc_info(alloc_id);

`

528

``

`-

if let Some(misalign) =

`

529

``

`-

M::alignment_check(self, alloc_id, alloc_align, kind, offset, align)

`

530

``

`-

{

`

``

541

`+

let alloc_info = self.get_alloc_info(alloc_id);

`

``

542

`+

if let Some(misalign) = M::alignment_check(

`

``

543

`+

self,

`

``

544

`+

alloc_id,

`

``

545

`+

alloc_info.align,

`

``

546

`+

alloc_info.kind,

`

``

547

`+

offset,

`

``

548

`+

align,

`

``

549

`+

) {

`

531

550

`Some(misalign)

`

532

551

`} else if M::Provenance::OFFSET_IS_ADDR {

`

533

552

`is_offset_misaligned(ptr.addr().bytes(), align)

`

534

553

`} else {

`

535

554

`// Check allocation alignment and offset alignment.

`

536

``

`-

if alloc_align.bytes() < align.bytes() {

`

537

``

`-

Some(Misalignment { has: alloc_align, required: align })

`

``

555

`+

if alloc_info.align.bytes() < align.bytes() {

`

``

556

`+

Some(Misalignment { has: alloc_info.align, required: align })

`

538

557

`} else {

`

539

558

`is_offset_misaligned(offset.bytes(), align)

`

540

559

`}

`

`@@ -818,93 +837,45 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {

`

818

837

``

819

838

`/// Obtain the size and alignment of an allocation, even if that allocation has

`

820

839

`/// been deallocated.

`

821

``

`-

pub fn get_alloc_info(&self, id: AllocId) -> (Size, Align, AllocKind, Mutability) {

`

``

840

`+

pub fn get_alloc_info(&self, id: AllocId) -> AllocInfo {

`

822

841

`// # Regular allocations

`

823

842

`` // Don't use self.get_raw here as that will

``

824

843

`` // a) cause cycles in case id refers to a static

``

825

844

`// b) duplicate a global's allocation in miri

`

826

845

`if let Some((_, alloc)) = self.memory.alloc_map.get(id) {

`

827

``

`-

return (alloc.size(), alloc.align, AllocKind::LiveData, alloc.mutability);

`

``

846

`+

return AllocInfo::new(

`

``

847

`+

alloc.size(),

`

``

848

`+

alloc.align,

`

``

849

`+

AllocKind::LiveData,

`

``

850

`+

alloc.mutability,

`

``

851

`+

);

`

828

852

`}

`

829

853

``

830

854

`// # Function pointers

`

831

855

`` // (both global from alloc_map and local from extra_fn_ptr_map)

``

832

856

`if self.get_fn_alloc(id).is_some() {

`

833

``

`-

return (Size::ZERO, Align::ONE, AllocKind::Function, Mutability::Not);

`

``

857

`+

return AllocInfo::new(Size::ZERO, Align::ONE, AllocKind::Function, Mutability::Not);

`

834

858

`}

`

835

859

``

836

``

`-

// # Statics

`

837

``

`-

// Can't do this in the match argument, we may get cycle errors since the lock would

`

838

``

`-

// be held throughout the match.

`

839

``

`-

match self.tcx.try_get_global_alloc(id) {

`

840

``

`-

Some(GlobalAlloc::Static(def_id)) => {

`

841

``

`-

// Thread-local statics do not have a constant address. They must be accessed via

`

842

``

`` -

// ThreadLocalRef; we can never have a pointer to them as a regular constant value.

``

843

``

`-

assert!(!self.tcx.is_thread_local_static(def_id));

`

844

``

-

845

``

`-

let DefKind::Static { nested, mutability, .. } = self.tcx.def_kind(def_id) else {

`

846

``

`-

bug!("GlobalAlloc::Static is not a static")

`

847

``

`-

};

`

848

``

-

849

``

`-

let (size, align, mutability) = if nested {

`

850

``

`-

// Nested anonymous statics are untyped, so let's get their

`

851

``

`-

// size and alignment from the allocation itself. This always

`

852

``

`-

// succeeds, as the query is fed at DefId creation time, so no

`

853

``

`-

// evaluation actually occurs.

`

854

``

`-

let alloc = self.tcx.eval_static_initializer(def_id).unwrap();

`

855

``

`-

(alloc.0.size(), alloc.0.align, alloc.0.mutability)

`

856

``

`-

} else {

`

857

``

`-

// Use size and align of the type for everything else. We need

`

858

``

`-

// to do that to

`

859

``

`-

// * avoid cycle errors in case of self-referential statics,

`

860

``

`-

// * be able to get information on extern statics.

`

861

``

`-

let ty = self

`

862

``

`-

.tcx

`

863

``

`-

.type_of(def_id)

`

864

``

`-

.no_bound_vars()

`

865

``

`-

.expect("statics should not have generic parameters");

`

866

``

`-

let layout = self.tcx.layout_of(ParamEnv::empty().and(ty)).unwrap();

`

867

``

`-

assert!(layout.is_sized());

`

868

``

`-

let mutability = match mutability {

`

869

``

`-

Mutability::Not if !ty.is_freeze(*self.tcx, ParamEnv::empty()) => {

`

870

``

`-

Mutability::Not

`

871

``

`-

}

`

872

``

`-

_ => Mutability::Mut,

`

873

``

`-

};

`

874

``

`-

(layout.size, layout.align.abi, mutability)

`

875

``

`-

};

`

876

``

`-

(size, align, AllocKind::LiveData, mutability)

`

877

``

`-

}

`

878

``

`-

Some(GlobalAlloc::Memory(alloc)) => {

`

879

``

`-

// Need to duplicate the logic here, because the global allocations have

`

880

``

`-

// different associated types than the interpreter-local ones.

`

881

``

`-

let alloc = alloc.inner();

`

882

``

`-

(alloc.size(), alloc.align, AllocKind::LiveData, alloc.mutability)

`

883

``

`-

}

`

884

``

`-

Some(GlobalAlloc::Function { .. }) => {

`

885

``

`-

bug!("We already checked function pointers above")

`

886

``

`-

}

`

887

``

`-

Some(GlobalAlloc::VTable(..)) => {

`

888

``

`-

// No data to be accessed here. But vtables are pointer-aligned.

`

889

``

`-

return (

`

890

``

`-

Size::ZERO,

`

891

``

`-

self.tcx.data_layout.pointer_align.abi,

`

892

``

`-

AllocKind::VTable,

`

893

``

`-

Mutability::Not,

`

894

``

`-

);

`

895

``

`-

}

`

896

``

`-

// The rest must be dead.

`

897

``

`-

None => {

`

898

``

`-

// Deallocated pointers are allowed, we should be able to find

`

899

``

`-

// them in the map.

`

900

``

`-

let (size, align) = *self

`

901

``

`-

.memory

`

902

``

`-

.dead_alloc_map

`

903

``

`-

.get(&id)

`

904

``

`` -

.expect("deallocated pointers should all be recorded in dead_alloc_map");

``

905

``

`-

(size, align, AllocKind::Dead, Mutability::Not)

`

906

``

`-

}

`

``

860

`+

// # Global allocations

`

``

861

`+

if let Some(global_alloc) = self.tcx.try_get_global_alloc(id) {

`

``

862

`+

let (size, align) = global_alloc.size_and_align(*self.tcx, self.param_env);

`

``

863

`+

let mutbl = global_alloc.mutability(*self.tcx, self.param_env);

`

``

864

`+

let kind = match global_alloc {

`

``

865

`+

GlobalAlloc::Static { .. } | GlobalAlloc::Memory { .. } => AllocKind::LiveData,

`

``

866

`+

GlobalAlloc::Function { .. } => bug!("We already checked function pointers above"),

`

``

867

`+

GlobalAlloc::VTable { .. } => AllocKind::VTable,

`

``

868

`+

};

`

``

869

`+

return AllocInfo::new(size, align, kind, mutbl);

`

907

870

`}

`

``

871

+

``

872

`+

// # Dead pointers

`

``

873

`+

let (size, align) = *self

`

``

874

`+

.memory

`

``

875

`+

.dead_alloc_map

`

``

876

`+

.get(&id)

`

``

877

`` +

.expect("deallocated pointers should all be recorded in dead_alloc_map");

``

``

878

`+

AllocInfo::new(size, align, AllocKind::Dead, Mutability::Not)

`

908

879

`}

`

909

880

``

910

881

`/// Obtain the size and alignment of a live allocation.

`

`@@ -913,11 +884,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {

`

913

884

`id: AllocId,

`

914

885

`msg: CheckInAllocMsg,

`

915

886

`) -> InterpResult<'tcx, (Size, Align)> {

`

916

``

`-

let (size, align, kind, _mutbl) = self.get_alloc_info(id);

`

917

``

`-

if matches!(kind, AllocKind::Dead) {

`

``

887

`+

let info = self.get_alloc_info(id);

`

``

888

`+

if matches!(info.kind, AllocKind::Dead) {

`

918

889

`throw_ub!(PointerUseAfterFree(id, msg))

`

919

890

`}

`

920

``

`-

interp_ok((size, align))

`

``

891

`+

interp_ok((info.size, info.align))

`

921

892

`}

`

922

893

``

923

894

`fn get_fn_alloc(&self, id: AllocId) -> Option<FnVal<'tcx, M::ExtraFnVal>> {

`

`@@ -1469,7 +1440,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {

`

1469

1440

`let ptr = scalar.to_pointer(self)?;

`

1470

1441

`match self.ptr_try_get_alloc_id(ptr, 0) {

`

1471

1442

`Ok((alloc_id, offset, _)) => {

`

1472

``

`-

let (size, _align, _kind, _mutbl) = self.get_alloc_info(alloc_id);

`

``

1443

`+

let size = self.get_alloc_info(alloc_id).size;

`

1473

1444

`// If the pointer is out-of-bounds, it may be null.

`

1474

1445

`// Note that one-past-the-end (offset == size) is still inbounds, and never null.

`

1475

1446

` offset > size

`