Skip to content

Commit 2cef9e3

Browse files
committed
interpret: support for per-byte provenance
1 parent 452cf4f commit 2cef9e3

File tree

18 files changed

+506
-291
lines changed

18 files changed

+506
-291
lines changed

compiler/rustc_codegen_llvm/src/consts.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use std::ops::Range;
2626

2727
pub fn const_alloc_to_llvm<'ll>(cx: &CodegenCx<'ll, '_>, alloc: ConstAllocation<'_>) -> &'ll Value {
2828
let alloc = alloc.inner();
29-
let mut llvals = Vec::with_capacity(alloc.provenance().len() + 1);
29+
let mut llvals = Vec::with_capacity(alloc.provenance().ptrs().len() + 1);
3030
let dl = cx.data_layout();
3131
let pointer_size = dl.pointer_size.bytes() as usize;
3232

@@ -78,7 +78,7 @@ pub fn const_alloc_to_llvm<'ll>(cx: &CodegenCx<'ll, '_>, alloc: ConstAllocation<
7878
}
7979

8080
let mut next_offset = 0;
81-
for &(offset, alloc_id) in alloc.provenance().iter() {
81+
for &(offset, alloc_id) in alloc.provenance().ptrs().iter() {
8282
let offset = offset.bytes();
8383
assert_eq!(offset as usize as u64, offset);
8484
let offset = offset as usize;
@@ -489,7 +489,7 @@ impl<'ll> StaticMethods for CodegenCx<'ll, '_> {
489489
// happens to be zero. Instead, we should only check the value of defined bytes
490490
// and set all undefined bytes to zero if this allocation is headed for the
491491
// BSS.
492-
let all_bytes_are_zero = alloc.provenance().is_empty()
492+
let all_bytes_are_zero = alloc.provenance().ptrs().is_empty()
493493
&& alloc
494494
.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len())
495495
.iter()
@@ -513,7 +513,7 @@ impl<'ll> StaticMethods for CodegenCx<'ll, '_> {
513513
section.as_str().as_ptr().cast(),
514514
section.as_str().len() as c_uint,
515515
);
516-
assert!(alloc.provenance().is_empty());
516+
assert!(alloc.provenance().ptrs().is_empty());
517517

518518
// The `inspect` method is okay here because we checked for provenance, and
519519
// because we are doing this access to inspect the final interpreter state (not

compiler/rustc_const_eval/src/interpret/intern.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval:
134134
alloc.mutability = Mutability::Not;
135135
};
136136
// link the alloc id to the actual allocation
137-
leftover_allocations.extend(alloc.provenance().iter().map(|&(_, alloc_id)| alloc_id));
137+
leftover_allocations.extend(alloc.provenance().ptrs().iter().map(|&(_, alloc_id)| alloc_id));
138138
let alloc = tcx.intern_const_alloc(alloc);
139139
tcx.set_alloc_id_memory(alloc_id, alloc);
140140
None
@@ -439,7 +439,7 @@ pub fn intern_const_alloc_recursive<
439439
}
440440
let alloc = tcx.intern_const_alloc(alloc);
441441
tcx.set_alloc_id_memory(alloc_id, alloc);
442-
for &(_, alloc_id) in alloc.inner().provenance().iter() {
442+
for &(_, alloc_id) in alloc.inner().provenance().ptrs().iter() {
443443
if leftover_allocations.insert(alloc_id) {
444444
todo.push(alloc_id);
445445
}

compiler/rustc_const_eval/src/interpret/memory.rs

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -302,8 +302,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
302302
.into());
303303
};
304304

305-
debug!(?alloc);
306-
307305
if alloc.mutability == Mutability::Not {
308306
throw_ub_format!("deallocating immutable allocation {alloc_id:?}");
309307
}
@@ -797,7 +795,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
797795
// This is a new allocation, add the allocation it points to `todo`.
798796
if let Some((_, alloc)) = self.memory.alloc_map.get(id) {
799797
todo.extend(
800-
alloc.provenance().values().filter_map(|prov| prov.get_alloc_id()),
798+
alloc.provenance().provenances().filter_map(|prov| prov.get_alloc_id()),
801799
);
802800
}
803801
}
@@ -833,7 +831,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> std::fmt::Debug for DumpAllocs<'a,
833831
allocs_to_print: &mut VecDeque<AllocId>,
834832
alloc: &Allocation<Prov, Extra>,
835833
) -> std::fmt::Result {
836-
for alloc_id in alloc.provenance().values().filter_map(|prov| prov.get_alloc_id()) {
834+
for alloc_id in alloc.provenance().provenances().filter_map(|prov| prov.get_alloc_id())
835+
{
837836
allocs_to_print.push_back(alloc_id);
838837
}
839838
write!(fmt, "{}", display_allocation(tcx, alloc))
@@ -962,7 +961,7 @@ impl<'tcx, 'a, Prov: Provenance, Extra> AllocRef<'a, 'tcx, Prov, Extra> {
962961

963962
/// Returns whether the allocation has provenance anywhere in the range of the `AllocRef`.
964963
pub(crate) fn has_provenance(&self) -> bool {
965-
self.alloc.range_has_provenance(&self.tcx, self.range)
964+
!self.alloc.provenance().range_empty(self.range, &self.tcx)
966965
}
967966
}
968967

@@ -1060,7 +1059,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
10601059

10611060
// Source alloc preparations and access hooks.
10621061
let Some((src_alloc_id, src_offset, src_prov)) = src_parts else {
1063-
// Zero-sized *source*, that means dst is also zero-sized and we have nothing to do.
1062+
// Zero-sized *source*, that means dest is also zero-sized and we have nothing to do.
10641063
return Ok(());
10651064
};
10661065
let src_alloc = self.get_alloc_raw(src_alloc_id)?;
@@ -1079,22 +1078,18 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
10791078
return Ok(());
10801079
};
10811080

1082-
// Checks provenance edges on the src, which needs to happen before
1083-
// `prepare_provenance_copy`.
1084-
if src_alloc.range_has_provenance(&tcx, alloc_range(src_range.start, Size::ZERO)) {
1085-
throw_unsup!(PartialPointerCopy(Pointer::new(src_alloc_id, src_range.start)));
1086-
}
1087-
if src_alloc.range_has_provenance(&tcx, alloc_range(src_range.end(), Size::ZERO)) {
1088-
throw_unsup!(PartialPointerCopy(Pointer::new(src_alloc_id, src_range.end())));
1089-
}
1081+
// Prepare getting source provenance.
10901082
let src_bytes = src_alloc.get_bytes_unchecked(src_range).as_ptr(); // raw ptr, so we can also get a ptr to the destination allocation
10911083
// first copy the provenance to a temporary buffer, because
10921084
// `get_bytes_mut` will clear the provenance, which is correct,
10931085
// since we don't want to keep any provenance at the target.
1094-
let provenance =
1095-
src_alloc.prepare_provenance_copy(self, src_range, dest_offset, num_copies);
1086+
// This will also error if copying partial provenance is not supported.
1087+
let provenance = src_alloc
1088+
.provenance()
1089+
.prepare_copy(src_range, dest_offset, num_copies, self)
1090+
.map_err(|e| e.to_interp_error(dest_alloc_id))?;
10961091
// Prepare a copy of the initialization mask.
1097-
let compressed = src_alloc.compress_uninit_range(src_range);
1092+
let init = src_alloc.compress_uninit_range(src_range);
10981093

10991094
// Destination alloc preparations and access hooks.
11001095
let (dest_alloc, extra) = self.get_alloc_raw_mut(dest_alloc_id)?;
@@ -1111,7 +1106,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
11111106
.map_err(|e| e.to_interp_error(dest_alloc_id))?
11121107
.as_mut_ptr();
11131108

1114-
if compressed.no_bytes_init() {
1109+
if init.no_bytes_init() {
11151110
// Fast path: If all bytes are `uninit` then there is nothing to copy. The target range
11161111
// is marked as uninitialized but we otherwise omit changing the byte representation which may
11171112
// be arbitrary for uninitialized bytes.
@@ -1161,12 +1156,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
11611156

11621157
// now fill in all the "init" data
11631158
dest_alloc.mark_compressed_init_range(
1164-
&compressed,
1159+
&init,
11651160
alloc_range(dest_offset, size), // just a single copy (i.e., not full `dest_range`)
11661161
num_copies,
11671162
);
11681163
// copy the provenance to the destination
1169-
dest_alloc.mark_provenance_range(provenance);
1164+
dest_alloc.provenance_apply_copy(provenance);
11701165

11711166
Ok(())
11721167
}

compiler/rustc_hir_analysis/src/check/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId) {
159159
// the consumer's responsibility to ensure all bytes that have been read
160160
// have defined values.
161161
if let Ok(alloc) = tcx.eval_static_initializer(id.to_def_id())
162-
&& alloc.inner().provenance().len() != 0
162+
&& alloc.inner().provenance().ptrs().len() != 0
163163
{
164164
let msg = "statics with a custom `#[link_section]` must be a \
165165
simple list of bytes on the wasm target with no \

0 commit comments

Comments
 (0)