Skip to content

Commit e8c4c9a

Browse files
committed
Auto merge of #2404 - RalfJung:mix, r=RalfJung
check for extern static size mismatches Also handle get_alloc_extra the same throughout Stacked Borrows. I don't think this `unwrap` can actually cause an ICE since another part of SB will raise an error before, but still, seems strange to do this inconsistently in retagging vs expose_ptr.
2 parents 167e5dc + 9f99d10 commit e8c4c9a

File tree

7 files changed

+93
-28
lines changed

7 files changed

+93
-28
lines changed

src/concurrency/data_race.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1061,7 +1061,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> {
10611061
if let Some(data_race) = &this.machine.data_race {
10621062
if data_race.race_detecting() {
10631063
let size = place.layout.size;
1064-
let (alloc_id, base_offset, _tag) = this.ptr_get_alloc_id(place.ptr)?;
1064+
let (alloc_id, base_offset, _prov) = this.ptr_get_alloc_id(place.ptr)?;
10651065
// Load and log the atomic operation.
10661066
// Note that atomic loads are possible even from read-only allocations, so `get_alloc_extra_mut` is not an option.
10671067
let alloc_meta = this.get_alloc_extra(alloc_id)?.data_race.as_ref().unwrap();

src/intptrcast.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,16 +94,21 @@ impl<'mir, 'tcx> GlobalStateInner {
9494
None
9595
}
9696

97-
pub fn expose_ptr(ecx: &mut MiriEvalContext<'mir, 'tcx>, alloc_id: AllocId, sb: SbTag) {
97+
pub fn expose_ptr(
98+
ecx: &mut MiriEvalContext<'mir, 'tcx>,
99+
alloc_id: AllocId,
100+
sb: SbTag,
101+
) -> InterpResult<'tcx> {
98102
let global_state = ecx.machine.intptrcast.get_mut();
99103
// In strict mode, we don't need this, so we can save some cycles by not tracking it.
100104
if global_state.provenance_mode != ProvenanceMode::Strict {
101105
trace!("Exposing allocation id {alloc_id:?}");
102106
global_state.exposed.insert(alloc_id);
103107
if ecx.machine.stacked_borrows.is_some() {
104-
ecx.expose_tag(alloc_id, sb);
108+
ecx.expose_tag(alloc_id, sb)?;
105109
}
106110
}
111+
Ok(())
107112
}
108113

109114
pub fn ptr_from_addr_transmute(

src/machine.rs

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -638,12 +638,35 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> {
638638
) -> InterpResult<'tcx, Pointer<Provenance>> {
639639
let link_name = ecx.item_link_name(def_id);
640640
if let Some(&ptr) = ecx.machine.extern_statics.get(&link_name) {
641+
// Various parts of the engine rely on `get_alloc_info` for size and alignment
642+
// information. That uses the type information of this static.
643+
// Make sure it matches the Miri allocation for this.
644+
let Provenance::Concrete { alloc_id, .. } = ptr.provenance else {
645+
panic!("extern_statics cannot contain wildcards")
646+
};
647+
let (shim_size, shim_align, _kind) = ecx.get_alloc_info(alloc_id);
648+
let extern_decl_layout =
649+
ecx.tcx.layout_of(ty::ParamEnv::empty().and(ecx.tcx.type_of(def_id))).unwrap();
650+
if extern_decl_layout.size != shim_size || extern_decl_layout.align.abi != shim_align {
651+
throw_unsup_format!(
652+
"`extern` static `{name}` from crate `{krate}` has been declared \
653+
with a size of {decl_size} bytes and alignment of {decl_align} bytes, \
654+
but Miri emulates it via an extern static shim \
655+
with a size of {shim_size} bytes and alignment of {shim_align} bytes",
656+
name = ecx.tcx.def_path_str(def_id),
657+
krate = ecx.tcx.crate_name(def_id.krate),
658+
decl_size = extern_decl_layout.size.bytes(),
659+
decl_align = extern_decl_layout.align.abi.bytes(),
660+
shim_size = shim_size.bytes(),
661+
shim_align = shim_align.bytes(),
662+
)
663+
}
641664
Ok(ptr)
642665
} else {
643666
throw_unsup_format!(
644-
"`extern` static `{}` from crate `{}` is not supported by Miri",
645-
ecx.tcx.def_path_str(def_id),
646-
ecx.tcx.crate_name(def_id.krate),
667+
"`extern` static `{name}` from crate `{krate}` is not supported by Miri",
668+
name = ecx.tcx.def_path_str(def_id),
669+
krate = ecx.tcx.crate_name(def_id.krate),
647670
)
648671
}
649672
}
@@ -754,15 +777,14 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> {
754777
ptr: Pointer<Self::Provenance>,
755778
) -> InterpResult<'tcx> {
756779
match ptr.provenance {
757-
Provenance::Concrete { alloc_id, sb } => {
758-
intptrcast::GlobalStateInner::expose_ptr(ecx, alloc_id, sb);
759-
}
780+
Provenance::Concrete { alloc_id, sb } =>
781+
intptrcast::GlobalStateInner::expose_ptr(ecx, alloc_id, sb),
760782
Provenance::Wildcard => {
761783
// No need to do anything for wildcard pointers as
762784
// their provenances have already been previously exposed.
785+
Ok(())
763786
}
764787
}
765-
Ok(())
766788
}
767789

768790
/// Convert a pointer with provenance into an allocation-offset pair,

src/shims/backtrace.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
123123

124124
let ptr = this.read_pointer(ptr)?;
125125
// Take apart the pointer, we need its pieces.
126-
let (alloc_id, offset, _tag) = this.ptr_get_alloc_id(ptr)?;
126+
let (alloc_id, offset, _prov) = this.ptr_get_alloc_id(ptr)?;
127127

128128
let fn_instance =
129129
if let Some(GlobalAlloc::Function(instance)) = this.tcx.get_global_alloc(alloc_id) {

src/stacked_borrows/mod.rs

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -777,20 +777,31 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
777777
return Ok(())
778778
};
779779

780-
let extra = this.get_alloc_extra(alloc_id)?;
781-
let mut stacked_borrows = extra
782-
.stacked_borrows
783-
.as_ref()
784-
.expect("we should have Stacked Borrows data")
785-
.borrow_mut();
786-
stacked_borrows.history.log_creation(
787-
Some(orig_tag),
788-
new_tag,
789-
alloc_range(base_offset, size),
790-
current_span,
791-
);
792-
if protect {
793-
stacked_borrows.history.log_protector(orig_tag, new_tag, current_span);
780+
let (_size, _align, kind) = this.get_alloc_info(alloc_id);
781+
match kind {
782+
AllocKind::LiveData => {
783+
// This should have alloc_extra data, but `get_alloc_extra` can still fail
784+
// if converting this alloc_id from a global to a local one
785+
// uncovers a non-supported `extern static`.
786+
let extra = this.get_alloc_extra(alloc_id)?;
787+
let mut stacked_borrows = extra
788+
.stacked_borrows
789+
.as_ref()
790+
.expect("we should have Stacked Borrows data")
791+
.borrow_mut();
792+
stacked_borrows.history.log_creation(
793+
Some(orig_tag),
794+
new_tag,
795+
alloc_range(base_offset, size),
796+
current_span,
797+
);
798+
if protect {
799+
stacked_borrows.history.log_protector(orig_tag, new_tag, current_span);
800+
}
801+
}
802+
AllocKind::Function | AllocKind::Dead => {
803+
// No stacked borrows on these allocations.
804+
}
794805
}
795806
Ok(())
796807
};
@@ -1116,7 +1127,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
11161127
}
11171128

11181129
/// Mark the given tag as exposed. It was found on a pointer with the given AllocId.
1119-
fn expose_tag(&mut self, alloc_id: AllocId, tag: SbTag) {
1130+
fn expose_tag(&mut self, alloc_id: AllocId, tag: SbTag) -> InterpResult<'tcx> {
11201131
let this = self.eval_context_mut();
11211132

11221133
// Function pointers and dead objects don't have an alloc_extra so we ignore them.
@@ -1125,14 +1136,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
11251136
let (_size, _align, kind) = this.get_alloc_info(alloc_id);
11261137
match kind {
11271138
AllocKind::LiveData => {
1128-
// This should have alloc_extra data.
1129-
let alloc_extra = this.get_alloc_extra(alloc_id).unwrap();
1139+
// This should have alloc_extra data, but `get_alloc_extra` can still fail
1140+
// if converting this alloc_id from a global to a local one
1141+
// uncovers a non-supported `extern static`.
1142+
let alloc_extra = this.get_alloc_extra(alloc_id)?;
11301143
trace!("Stacked Borrows tag {tag:?} exposed in {alloc_id:?}");
11311144
alloc_extra.stacked_borrows.as_ref().unwrap().borrow_mut().exposed_tags.insert(tag);
11321145
}
11331146
AllocKind::Function | AllocKind::Dead => {
11341147
// No stacked borrows on these allocations.
11351148
}
11361149
}
1150+
Ok(())
11371151
}
11381152
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
//@ only-target-linux: we need a specific extern supported on this target
2+
//@normalize-stderr-test: "[48] bytes" -> "N bytes"
3+
4+
extern "C" {
5+
static mut environ: i8;
6+
}
7+
8+
fn main() {
9+
let _val = unsafe { environ }; //~ ERROR: /has been declared with a size of 1 bytes and alignment of 1 bytes, but Miri emulates it via an extern static shim with a size of [48] bytes and alignment of [48] bytes/
10+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error: unsupported operation: `extern` static `environ` from crate `extern_static_wrong_size` has been declared with a size of 1 bytes and alignment of 1 bytes, but Miri emulates it via an extern static shim with a size of N bytes and alignment of N bytes
2+
--> $DIR/extern_static_wrong_size.rs:LL:CC
3+
|
4+
LL | let _val = unsafe { environ };
5+
| ^^^^^^^ `extern` static `environ` from crate `extern_static_wrong_size` has been declared with a size of 1 bytes and alignment of 1 bytes, but Miri emulates it via an extern static shim with a size of N bytes and alignment of N bytes
6+
|
7+
= help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support
8+
= note: backtrace:
9+
= note: inside `main` at $DIR/extern_static_wrong_size.rs:LL:CC
10+
11+
note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
12+
13+
error: aborting due to previous error
14+

0 commit comments

Comments
 (0)