SmtModel

Struct SmtModel 

Source
pub(crate) struct SmtModel<'a, 'ctx, 'tcx> {
    tcx: TyCtxt<'tcx>,
    checkpoint: &'a Checkpoint<'tcx>,
    forward: &'a ForwardVisitResult<'tcx>,
    ctx: &'ctx Context,
    place_terms: HashMap<PlaceKey, Int<'ctx>>,
    local_terms: HashMap<usize, Int<'ctx>>,
    symbolic_align_terms: HashMap<String, Int<'ctx>>,
    symbolic_len_terms: HashMap<String, Int<'ctx>>,
    const_terms: HashMap<String, Int<'ctx>>,
    assumptions: Vec<SmtPredicate>,
    has_index_access_assumptions: bool,
}
Expand description

Per-query SMT term builder over a forward visit result.

Fields§

§tcx: TyCtxt<'tcx>§checkpoint: &'a Checkpoint<'tcx>§forward: &'a ForwardVisitResult<'tcx>§ctx: &'ctx Context§place_terms: HashMap<PlaceKey, Int<'ctx>>§local_terms: HashMap<usize, Int<'ctx>>

Shared Z3 constants per MIR local — ensures every reference to the same local produces the exact same SMT term (e.g. mid used in both ptr.add and unchecked_sub).

§symbolic_align_terms: HashMap<String, Int<'ctx>>§symbolic_len_terms: HashMap<String, Int<'ctx>>§const_terms: HashMap<String, Int<'ctx>>§assumptions: Vec<SmtPredicate>§has_index_access_assumptions: bool

Set to true when IndexAccess InBound assumptions were added from caller contract

Implementations§

Source§

impl<'a, 'ctx, 'tcx> SmtModel<'a, 'ctx, 'tcx>

Source

pub(crate) fn new( tcx: TyCtxt<'tcx>, checkpoint: &'a Checkpoint<'tcx>, forward: &'a ForwardVisitResult<'tcx>, ctx: &'ctx Context, ) -> Self

Create a fresh SMT model builder.

Source

pub(crate) fn symbolic_align_term(&mut self, ty_name: &str) -> Int<'ctx>

Create or return a cached symbolic alignment constant for a type name.

Source

fn symbolic_len_term(&mut self, len_key: &str) -> Int<'ctx>

Source

fn has_equivalent_contract_fact( &mut self, place: &PlaceKey, _kind: PropertyKind, ) -> bool

Check whether a ContractFact in the forward facts targets the same (or Cast-equivalent) place with the given property kind.

Used by struct-invariant checkpoint checks to short-circuit when a caller #[rapx::requires] already establishes the property.

Source

fn contract_predicate_to_smt( &mut self, predicate: &NumericPredicate<'tcx>, ) -> Option<SmtPredicate>

Source

fn smt_term_from_contract_expr( &mut self, expr: &ContractExpr<'tcx>, ) -> Option<SmtTerm>

Source

fn value_to_int(&mut self, value: &AbstractValue<'tcx>) -> Option<Int<'ctx>>

Source

pub(crate) fn assert_forward_facts(&mut self, solver: &Solver<'ctx>)

Assert facts collected by the forward visitor.

Source

pub(crate) fn assumptions(&self) -> &[SmtPredicate]

Return the path assumptions asserted by this model.

Source

fn latest_cursor(&self) -> usize

Source

fn call_definition_cursor(&self, call: &CallSummary<'tcx>) -> usize

Source

pub(crate) fn pointer_bounds_for_place( &mut self, place: &PlaceKey, ) -> Option<PointerBounds<'ctx>>

Try to recover the slice index/length terms behind a pointer result.

Supported forms:

  • slice.as_ptr().add(index) and wrappers summarized as ReturnPointerAdd
  • plain slice.as_ptr() / slice.as_mut_ptr(), treated as index 0
Source

fn field_projection_index( &mut self, place: &PlaceKey, origin_key: &str, len_term: &SmtTerm, ) -> (SmtTerm, Int<'ctx>)

Walk the value chain for place to determine if it is a field projection from an as_ptr_range/as_mut_ptr_range result (or an inlined equivalent). Returns (index_term, index_val). Field [0] (start) → offset 0; field [1] (end) → offset len.

Source

fn compute_pointer_arith_index( &mut self, base: &AbstractValue<'tcx>, base_origin: &str, len_term: &SmtTerm, call: &CallSummary<'tcx>, call_cursor: usize, ) -> (SmtTerm, Int<'ctx>)

Compute the offset index for a pointer-arithmetic call result. result_offset = base_offset (+ or -) count

Source

fn pointer_object_offset_for_place( &self, place: &PlaceKey, ) -> Option<(PlaceKey, SmtTerm)>

Recover the allocation object and element offset for a pointer-like place. This is intentionally small: it handles base pointers returned by as_ptr/as_mut_ptr and offsets produced by pointer arithmetic summaries.

Source

fn pointer_object_offset_for_place_before( &self, place: &PlaceKey, cursor: usize, seen: &mut HashSet<(PlaceKey, usize)>, ) -> Option<(PlaceKey, SmtTerm)>

Source

fn pointer_object_offset_for_value( &self, value: &AbstractValue<'tcx>, cursor: usize, seen: &mut HashSet<(PlaceKey, usize)>, ) -> Option<(PlaceKey, SmtTerm)>

Source

fn allocated_object_for_place(&self, place: &PlaceKey) -> Option<PlaceKey>

Source

pub(crate) fn assert_place_non_zero( &mut self, solver: &Solver<'ctx>, place: &PlaceKey, reason: &str, )

Assert that a place is known to denote a non-zero address.

Source

fn assert_place_alignment(&mut self, solver: &Solver<'ctx>, place: &PlaceKey)

Assert known alignment for a place when its MIR type provides one.

Source

fn assert_known_alignment( &mut self, solver: &Solver<'ctx>, place: &PlaceKey, align: u64, ty_name: &str, reason: &str, )

Assert an explicitly summarized alignment fact.

Source

fn assert_known_const( &mut self, solver: &Solver<'ctx>, place: &PlaceKey, value: u64, reason: &str, )

Assert that a place is equal to a concrete layout/numeric constant.

Source

fn assert_length_alias( &mut self, solver: &Solver<'ctx>, left: &PlaceKey, right: &PlaceKey, )

Assert equal slice lengths for two slice-like places that alias.

Source

fn is_len_carrying_place(&self, place: &PlaceKey) -> bool

Source

fn record_call_effect_assumptions(&mut self, call: &CallSummary<'tcx>)

Record call-effect definitions that the term builder understands.

Source

pub(crate) fn term_for_place(&mut self, place: &PlaceKey) -> Option<Int<'ctx>>

Build an SMT term for a place.

Source

fn term_for_place_before( &mut self, place: &PlaceKey, cursor: usize, seen: &mut HashSet<(PlaceKey, usize)>, ) -> Option<Int<'ctx>>

Build an SMT term for a place using only definitions before cursor.

Source

fn projected_term_for_place( &mut self, place: &PlaceKey, cursor: usize, seen: &mut HashSet<(PlaceKey, usize)>, ) -> Option<Int<'ctx>>

Build terms for well-known aggregate projections.

Checked integer arithmetic is represented as (value, overflow) in MIR. For numeric reasoning we can use field 0 as the mathematical result. Field 1 remains a fresh value, so overflow assertions do not become accidental constraints on the result itself.

Source

fn term_for_value( &mut self, value: &AbstractValue<'tcx>, seen: &mut HashSet<(PlaceKey, usize)>, ) -> Option<Int<'ctx>>

Build an SMT term for an abstract value.

Source

fn term_for_pointer_arith_call( &mut self, call: &CallSummary<'tcx>, cursor: usize, seen: &mut HashSet<(PlaceKey, usize)>, ) -> Option<Int<'ctx>>

Build an address expression for a call summarized as pointer arithmetic.

Source

fn term_for_length_call( &mut self, call: &CallSummary<'tcx>, cursor: usize, seen: &mut HashSet<(PlaceKey, usize)>, ) -> Option<Int<'ctx>>

Build a stable len(origin) term for calls summarized as length reads.

Source

fn const_param_symbol(&mut self, name_or_debug: &str) -> Int<'ctx>

Return a cached Z3 integer symbol for a const generic parameter, keyed by its plain name (e.g. N). Accepts either a plain name or a rustc debug string such as Ty(usize, N/#1) / Param(N), so that a const parameter referenced from a MIR operand, a contract, and an array length all resolve to the same const_<name> symbol.

Source

fn term_for_value_at( &mut self, value: &AbstractValue<'tcx>, cursor: usize, seen: &mut HashSet<(PlaceKey, usize)>, ) -> Option<Int<'ctx>>

Build an SMT term for an abstract value at a program point.

Source

fn term_for_smt_term(&mut self, term: &SmtTerm) -> Option<Int<'ctx>>

Build an SMT integer term from a property-independent diagnostic term.

Source

fn bool_for_predicates( &mut self, predicates: &[SmtPredicate], ) -> Option<Bool<'ctx>>

Build a boolean term for a conjunction of shared predicates.

Source

fn bool_for_predicate(&mut self, predicate: &SmtPredicate) -> Option<Bool<'ctx>>

Build a boolean term from a shared diagnostic/query predicate.

Source

fn assert_unsigned_bounds_for_predicates( &mut self, solver: &Solver<'ctx>, predicates: &[SmtPredicate], )

Assert Rust unsigned integer lower bounds for terms that appear in a numeric obligation.

Source

fn assert_unsigned_bounds_for_predicate( &mut self, solver: &Solver<'ctx>, predicate: &SmtPredicate, seen: &mut HashSet<PlaceKey>, )

Source

fn assert_unsigned_bounds_for_term( &mut self, solver: &Solver<'ctx>, term: &SmtTerm, seen: &mut HashSet<PlaceKey>, )

Source

fn term_for_binary( &self, op: BinOp, lhs: &Int<'ctx>, rhs: &Int<'ctx>, ) -> Option<Int<'ctx>>

Lower a binary MIR operation to an integer term.

Source

fn call_destination_stride(&self, call: &CallSummary<'tcx>) -> Option<u64>

Return the byte stride for a typed pointer-add call destination.

Source

fn place_ty(&self, place: &PlaceKey) -> Option<Ty<'tcx>>

Return the MIR type for a simple place key.

Source

fn type_layout(&self, ty: Ty<'tcx>) -> Option<(u64, u64)>

Source

fn guaranteed_alignment(&self, ty: Ty<'tcx>) -> Option<u64>

Return the alignment guaranteed by a concrete or generic type.

Source

fn generic_candidate_alignments(&self, ty: Ty<'tcx>) -> Option<Vec<u64>>

Source

fn pointer_add_call_for_place( &self, place: &PlaceKey, ) -> Option<CallSummary<'tcx>>

Return the pointer-add call/effect that produced a place after copies/casts.

Source

fn resolved_value_for_place( &self, place: &PlaceKey, seen: &mut HashSet<(PlaceKey, usize)>, ) -> Option<AbstractValue<'tcx>>

Resolve copy/cast chains for a MIR place into the value at their source.

Source

fn resolved_value_for_place_before( &self, place: &PlaceKey, cursor: usize, seen: &mut HashSet<(PlaceKey, usize)>, ) -> Option<AbstractValue<'tcx>>

Source

fn resolved_value( &self, value: &AbstractValue<'tcx>, seen: &mut HashSet<(PlaceKey, usize)>, ) -> Option<AbstractValue<'tcx>>

Resolve copy/cast chains for an abstract value.

Source

fn resolved_value_before( &self, value: &AbstractValue<'tcx>, cursor: usize, seen: &mut HashSet<(PlaceKey, usize)>, ) -> Option<AbstractValue<'tcx>>

Source

fn path_value_definition_before( &self, place: &PlaceKey, cursor: usize, ) -> Option<AbstractValue<'tcx>>

Recover a local definition directly from the expanded MIR path.

Backward relevance keeps the proof slice intentionally small. When a pure call-argument temporary is not retained in the forward visit, SMT term construction can still recover its value by replaying assignments along the already-enumerated path up to the current cursor.

Source

fn path_cursor_cutoff(&self, cursor: usize) -> PathCursorCutoff

Source

fn origin_key_for_value( &self, value: &AbstractValue<'tcx>, seen: &mut HashSet<(PlaceKey, usize)>, ) -> Option<String>

Return a stable origin key for matching as_ptr(source) and len(source).

Source

fn origin_key_for_value_before( &self, value: &AbstractValue<'tcx>, cursor: usize, seen: &mut HashSet<(PlaceKey, usize)>, ) -> Option<String>

Source

fn guarded_len_for_index( &self, base_origin: &str, index: &AbstractValue<'tcx>, ) -> Option<AbstractValue<'tcx>>

Recover a length value from a path guard that mentions index.

Source

fn value_mentions( &self, haystack: &AbstractValue<'tcx>, needle: &AbstractValue<'tcx>, ) -> bool

Return true when haystack contains the same resolved value as needle.

Source

fn value_mentions_inner( &self, haystack: &AbstractValue<'tcx>, needle: &AbstractValue<'tcx>, seen: &mut HashSet<(String, String)>, ) -> bool

Source

fn len_matches_origin( &self, len: &AbstractValue<'tcx>, base_origin: &str, ) -> bool

Return true when a length-like value is the metadata/len of base_origin.

Source

fn len_matches_origin_inner( &self, len: &AbstractValue<'tcx>, base_origin: &str, seen: &mut HashSet<String>, ) -> bool

Source

fn source_from_points_to(&self, pointer: &PlaceKey) -> Option<PlaceKey>

Return the source place recorded by a PointsTo(pointer, source) fact.

Source

fn init_target_terms(&mut self, place: &PlaceKey) -> Vec<Int<'ctx>>

Candidate address/value terms for an Init target.

Pointer targets use their value term. By-value MaybeUninit<T> targets may be moved into a temporary before assume_init; in that case the relevant initialized storage is the address of the original place.

Source

fn init_source_terms(&mut self, place: &PlaceKey) -> Vec<Int<'ctx>>

Candidate address/value terms for a known initialized write.

Source

fn storage_addr_for_place( &mut self, place: &PlaceKey, seen: &mut HashSet<PlaceKey>, ) -> Option<Int<'ctx>>

Return the address of the storage represented by place.

Source

fn bounds_len_for_origin( &mut self, origin_key: &str, index: Option<&AbstractValue<'tcx>>, ) -> Option<(Int<'ctx>, SmtTerm)>

Find a retained len(source) call whose source matches origin_key.

Source

fn is_slice_pointer_origin(&self, origin_key: &str) -> bool

Return true if origin_key is the source of an as_ptr-like call (suggesting it is a slice / reference whose internal pointer was extracted). For these origins a symbolic length term is safe because the length is naturally bounded by the reference type.

Source

fn is_maybe_uninit_origin(&self, origin_key: &str) -> bool

Return true if the allocation for origin_key is a MaybeUninit wrapper (dynamic-length array). These have elements == 0 in KnownAllocated and should use a symbolic/sentinel length.

Source

fn len_place_for_origin(&self, origin_key: &str) -> Option<PlaceKey>

Source

fn allocated_len_for_origin(&self, origin_key: &str) -> Option<u64>

Source

fn origin_is_initialized_for_ty( &self, origin_key: &str, required_ty_name: &str, ) -> bool

Source

fn initialized_element_ty_for_place(&self, place: &PlaceKey) -> Option<String>

Auto Trait Implementations§

§

impl<'a, 'ctx, 'tcx> Freeze for SmtModel<'a, 'ctx, 'tcx>

§

impl<'a, 'ctx, 'tcx> !RefUnwindSafe for SmtModel<'a, 'ctx, 'tcx>

§

impl<'a, 'ctx, 'tcx> !Send for SmtModel<'a, 'ctx, 'tcx>

§

impl<'a, 'ctx, 'tcx> !Sync for SmtModel<'a, 'ctx, 'tcx>

§

impl<'a, 'ctx, 'tcx> Unpin for SmtModel<'a, 'ctx, 'tcx>

§

impl<'a, 'ctx, 'tcx> !UnwindSafe for SmtModel<'a, 'ctx, 'tcx>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,