-
Notifications
You must be signed in to change notification settings - Fork 407
initial implementation of wildcard provenence for tree borrows #4630
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -291,9 +291,10 @@ pub(super) struct TbError<'node> { | |||||||
| pub conflicting_info: &'node NodeDebugInfo, | ||||||||
| // What kind of access caused this error (read, write, reborrow, deallocation) | ||||||||
| pub access_cause: AccessCause, | ||||||||
| /// Which tag the access that caused this error was made through, i.e. | ||||||||
| /// Which tag, if any, the access that caused this error was made through, i.e. | ||||||||
| /// which tag was used to read/write/deallocate. | ||||||||
| pub accessed_info: &'node NodeDebugInfo, | ||||||||
| /// Not set on wildcard accesses. | ||||||||
| pub accessed_info: Option<&'node NodeDebugInfo>, | ||||||||
| } | ||||||||
|
|
||||||||
| impl TbError<'_> { | ||||||||
|
|
@@ -302,10 +303,20 @@ impl TbError<'_> { | |||||||
| use TransitionError::*; | ||||||||
| let cause = self.access_cause; | ||||||||
| let accessed = self.accessed_info; | ||||||||
| let accessed_str = | ||||||||
| self.accessed_info.map(|v| format!("{v}")).unwrap_or_else(|| "<wildcard>".into()); | ||||||||
| let conflicting = self.conflicting_info; | ||||||||
| let accessed_is_conflicting = accessed.tag == conflicting.tag; | ||||||||
| // An access is considered conflicting if it happened through a | ||||||||
| // different tag than the one who caused UB. | ||||||||
| // When doing a wildcard access (where `accessed` is `None`) we | ||||||||
| // do not know which precise tag the accessed happened from, | ||||||||
| // however we can be certain that it did not come from the | ||||||||
| // conflicting tag. | ||||||||
| // This is because the wildcard data structure already removes | ||||||||
| // all tags through which an access would cause UB. | ||||||||
| let accessed_is_conflicting = accessed.map(|a| a.tag) == Some(conflicting.tag); | ||||||||
| let title = format!( | ||||||||
| "{cause} through {accessed} at {alloc_id:?}[{offset:#x}] is forbidden", | ||||||||
| "{cause} through {accessed_str} at {alloc_id:?}[{offset:#x}] is forbidden", | ||||||||
| alloc_id = self.alloc_id, | ||||||||
| offset = self.error_offset | ||||||||
| ); | ||||||||
|
|
@@ -316,7 +327,7 @@ impl TbError<'_> { | |||||||
| let mut details = Vec::new(); | ||||||||
| if !accessed_is_conflicting { | ||||||||
| details.push(format!( | ||||||||
| "the accessed tag {accessed} is a child of the conflicting tag {conflicting}" | ||||||||
| "the accessed tag {accessed_str} is a child of the conflicting tag {conflicting}" | ||||||||
| )); | ||||||||
| } | ||||||||
| let access = cause.print_as_access(/* is_foreign */ false); | ||||||||
|
|
@@ -330,7 +341,7 @@ impl TbError<'_> { | |||||||
| let access = cause.print_as_access(/* is_foreign */ true); | ||||||||
| let details = vec![ | ||||||||
| format!( | ||||||||
| "the accessed tag {accessed} is foreign to the {conflicting_tag_name} tag {conflicting} (i.e., it is not a child)" | ||||||||
| "the accessed tag {accessed_str} is foreign to the {conflicting_tag_name} tag {conflicting} (i.e., it is not a child)" | ||||||||
| ), | ||||||||
| format!( | ||||||||
| "this {access} would cause the {conflicting_tag_name} tag {conflicting} (currently {before_disabled}) to become Disabled" | ||||||||
|
|
@@ -343,16 +354,18 @@ impl TbError<'_> { | |||||||
| let conflicting_tag_name = "strongly protected"; | ||||||||
| let details = vec![ | ||||||||
| format!( | ||||||||
| "the allocation of the accessed tag {accessed} also contains the {conflicting_tag_name} tag {conflicting}" | ||||||||
| "the allocation of the accessed tag {accessed_str} also contains the {conflicting_tag_name} tag {conflicting}" | ||||||||
| ), | ||||||||
| format!("the {conflicting_tag_name} tag {conflicting} disallows deallocations"), | ||||||||
| ]; | ||||||||
| (title, details, conflicting_tag_name) | ||||||||
| } | ||||||||
| }; | ||||||||
| let mut history = HistoryData::default(); | ||||||||
| if !accessed_is_conflicting { | ||||||||
| history.extend(self.accessed_info.history.forget(), "accessed", false); | ||||||||
| if let Some(accessed_info) = self.accessed_info | ||||||||
| && !accessed_is_conflicting | ||||||||
| { | ||||||||
| history.extend(accessed_info.history.forget(), "accessed", false); | ||||||||
| } | ||||||||
| history.extend( | ||||||||
| self.conflicting_info.history.extract_relevant(self.error_offset, self.error_kind), | ||||||||
|
|
@@ -363,6 +376,20 @@ impl TbError<'_> { | |||||||
| } | ||||||||
| } | ||||||||
|
|
||||||||
| /// Cannot access this allocation with wildcard provenance, as there are no | ||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
| /// valid exposed references for this access kind. | ||||||||
| pub fn no_valid_exposed_references_error<'tcx>( | ||||||||
| alloc_id: AllocId, | ||||||||
| offset: u64, | ||||||||
| access_cause: AccessCause, | ||||||||
| ) -> InterpErrorKind<'tcx> { | ||||||||
| let title = | ||||||||
| format!("{access_cause} through <wildcard> at {alloc_id:?}[{offset:#x}] is forbidden"); | ||||||||
| let details = vec![format!("there are no exposed tags which may perform this access here")]; | ||||||||
| let history = HistoryData::default(); | ||||||||
| err_machine_stop!(TerminationInfo::TreeBorrowsUb { title, details, history }) | ||||||||
| } | ||||||||
|
|
||||||||
| type S = &'static str; | ||||||||
| /// Pretty-printing details | ||||||||
| /// | ||||||||
|
|
@@ -623,10 +650,10 @@ impl DisplayRepr { | |||||||
| } else { | ||||||||
| // We take this node | ||||||||
| let rperm = tree | ||||||||
| .rperms | ||||||||
| .locations | ||||||||
| .iter_all() | ||||||||
| .map(move |(_offset, perms)| { | ||||||||
| let perm = perms.get(idx); | ||||||||
| .map(move |(_offset, loc)| { | ||||||||
| let perm = loc.perms.get(idx); | ||||||||
| perm.cloned() | ||||||||
| }) | ||||||||
| .collect::<Vec<_>>(); | ||||||||
|
|
@@ -788,7 +815,7 @@ impl<'tcx> Tree { | |||||||
| show_unnamed: bool, | ||||||||
| ) -> InterpResult<'tcx> { | ||||||||
| let mut indenter = DisplayIndent::new(); | ||||||||
| let ranges = self.rperms.iter_all().map(|(range, _perms)| range).collect::<Vec<_>>(); | ||||||||
| let ranges = self.locations.iter_all().map(|(range, _loc)| range).collect::<Vec<_>>(); | ||||||||
| if let Some(repr) = DisplayRepr::from(self, show_unnamed) { | ||||||||
| repr.print( | ||||||||
| &DEFAULT_FORMATTER, | ||||||||
|
|
||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,6 +14,7 @@ mod foreign_access_skipping; | |
| mod perms; | ||
| mod tree; | ||
| mod unimap; | ||
| mod wildcard; | ||
|
|
||
| #[cfg(test)] | ||
| mod exhaustive; | ||
|
|
@@ -54,16 +55,10 @@ impl<'tcx> Tree { | |
| interpret::Pointer::new(alloc_id, range.start), | ||
| range.size.bytes(), | ||
| ); | ||
| // TODO: for now we bail out on wildcard pointers. Eventually we should | ||
| // handle them as much as we can. | ||
| let tag = match prov { | ||
| ProvenanceExtra::Concrete(tag) => tag, | ||
| ProvenanceExtra::Wildcard => return interp_ok(()), | ||
| }; | ||
| let global = machine.borrow_tracker.as_ref().unwrap(); | ||
| let span = machine.current_user_relevant_span(); | ||
| self.perform_access( | ||
| tag, | ||
| prov, | ||
| Some((range, access_kind, diagnostics::AccessCause::Explicit(access_kind))), | ||
| global, | ||
| alloc_id, | ||
|
|
@@ -79,19 +74,9 @@ impl<'tcx> Tree { | |
| size: Size, | ||
| machine: &MiriMachine<'tcx>, | ||
| ) -> InterpResult<'tcx> { | ||
| // TODO: for now we bail out on wildcard pointers. Eventually we should | ||
| // handle them as much as we can. | ||
| let tag = match prov { | ||
| ProvenanceExtra::Concrete(tag) => tag, | ||
| ProvenanceExtra::Wildcard => return interp_ok(()), | ||
| }; | ||
| let global = machine.borrow_tracker.as_ref().unwrap(); | ||
| let span = machine.current_user_relevant_span(); | ||
| self.dealloc(tag, alloc_range(Size::ZERO, size), global, alloc_id, span) | ||
| } | ||
|
|
||
| pub fn expose_tag(&mut self, _tag: BorTag) { | ||
| // TODO | ||
| self.dealloc(prov, alloc_range(Size::ZERO, size), global, alloc_id, span) | ||
| } | ||
|
|
||
| /// A tag just lost its protector. | ||
|
|
@@ -109,7 +94,11 @@ impl<'tcx> Tree { | |
| ) -> InterpResult<'tcx> { | ||
| let span = machine.current_user_relevant_span(); | ||
| // `None` makes it the magic on-protector-end operation | ||
| self.perform_access(tag, None, global, alloc_id, span) | ||
| self.perform_access(ProvenanceExtra::Concrete(tag), None, global, alloc_id, span)?; | ||
|
|
||
| self.update_exposure_for_protector_release(tag); | ||
|
|
||
| interp_ok(()) | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -239,21 +228,22 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { | |
| assert_eq!(ptr_size, Size::ZERO); // we did the deref check above, size has to be 0 here | ||
| // This pointer doesn't come with an AllocId, so there's no | ||
| // memory to do retagging in. | ||
| let new_prov = place.ptr().provenance; | ||
| trace!( | ||
| "reborrow of size 0: reference {:?} derived from {:?} (pointee {})", | ||
| new_tag, | ||
| "reborrow of size 0: reusing {:?} (pointee {})", | ||
| place.ptr(), | ||
| place.layout.ty, | ||
| ); | ||
| log_creation(this, None)?; | ||
| // Keep original provenance. | ||
| return interp_ok(place.ptr().provenance); | ||
| return interp_ok(new_prov); | ||
| } | ||
| }; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is a If the size is 0 on a wildcard pointer I think we have to bail early, there's not much we can do. |
||
|
|
||
| log_creation(this, Some((alloc_id, base_offset, parent_prov)))?; | ||
|
|
||
| let orig_tag = match parent_prov { | ||
| ProvenanceExtra::Wildcard => return interp_ok(place.ptr().provenance), // TODO: handle wildcard pointers | ||
| ProvenanceExtra::Wildcard => return interp_ok(place.ptr().provenance), // TODO: handle retagging wildcard pointers | ||
| ProvenanceExtra::Concrete(tag) => tag, | ||
| }; | ||
|
|
||
|
|
@@ -356,7 +346,7 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { | |
| }; | ||
|
|
||
| tree_borrows.perform_access( | ||
| orig_tag, | ||
| parent_prov, | ||
| Some((range_in_alloc, AccessKind::Read, diagnostics::AccessCause::Reborrow)), | ||
| this.machine.borrow_tracker.as_ref().unwrap(), | ||
| alloc_id, | ||
|
|
@@ -606,7 +596,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { | |
| // uncovers a non-supported `extern static`. | ||
| let alloc_extra = this.get_alloc_extra(alloc_id)?; | ||
| trace!("Tree Borrows tag {tag:?} exposed in {alloc_id:?}"); | ||
| alloc_extra.borrow_tracker_tb().borrow_mut().expose_tag(tag); | ||
|
|
||
| let global = this.machine.borrow_tracker.as_ref().unwrap(); | ||
| let protected_tags = &global.borrow().protected_tags; | ||
| let protected = protected_tags.contains_key(&tag); | ||
| alloc_extra.borrow_tracker_tb().borrow_mut().expose_tag(tag, protected); | ||
| } | ||
| AllocKind::Function | AllocKind::VTable | AllocKind::TypeId | AllocKind::Dead => { | ||
| // No tree borrows on these allocations. | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.