use crate::obligation::marking::{MarkingEvent, MarkingEventKind};
use crate::record::ObligationKind;
use crate::types::{ObligationId, RegionId, TaskId, Time};
use std::collections::BTreeMap;
use std::fmt;
#[derive(Debug, Clone)]
struct GhostPermitMap {
active: BTreeMap<ObligationId, GhostEntry>,
consumed: BTreeMap<ObligationId, ConsumedEntry>,
}
#[derive(Debug, Clone)]
struct GhostEntry {
holder: TaskId,
kind: ObligationKind,
region: RegionId,
}
#[derive(Debug, Clone)]
struct ConsumedEntry {
_resolution: ConsumedHow,
resolved_at: Time,
_last_holder: TaskId,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum ConsumedHow {
Committed,
Aborted,
Leaked,
}
impl GhostPermitMap {
fn new() -> Self {
Self {
active: BTreeMap::new(),
consumed: BTreeMap::new(),
}
}
fn active_count(&self) -> usize {
self.active.len()
}
fn holder_count(&self, id: ObligationId) -> usize {
usize::from(self.active.contains_key(&id))
}
#[cfg(test)]
fn holder_of(&self, id: ObligationId) -> Option<TaskId> {
self.active.get(&id).map(|e| e.holder)
}
fn is_consumed(&self, id: ObligationId) -> bool {
self.consumed.contains_key(&id)
}
}
#[derive(Debug, Clone)]
pub struct ProofStep {
pub lemma: Lemma,
pub obligation: ObligationId,
pub time: Time,
pub verified: bool,
pub description: String,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Lemma {
AllocationFreshness,
TransferExclusivity,
ReleaseConsumption,
ConcurrentIndependence,
DropSafety,
}
impl fmt::Display for Lemma {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::AllocationFreshness => write!(f, "Lemma 1 (Allocation Freshness)"),
Self::TransferExclusivity => write!(f, "Lemma 2 (Transfer Exclusivity)"),
Self::ReleaseConsumption => write!(f, "Lemma 3 (Release Consumption)"),
Self::ConcurrentIndependence => write!(f, "Lemma 4 (Concurrent Independence)"),
Self::DropSafety => write!(f, "Lemma 5 (Drop Safety)"),
}
}
}
#[derive(Debug, Clone)]
pub struct Counterexample {
pub violation: ViolationKind,
pub obligation: ObligationId,
pub time: Time,
pub description: String,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ViolationKind {
DoubleOwnership,
DuplicateAllocation,
UseAfterRelease,
TransferAliasing,
KindDisagreement,
RegionDisagreement,
WrongKind,
SelfTransfer,
}
impl fmt::Display for ViolationKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::DoubleOwnership => write!(f, "double-ownership"),
Self::DuplicateAllocation => write!(f, "duplicate-allocation"),
Self::UseAfterRelease => write!(f, "use-after-release"),
Self::TransferAliasing => write!(f, "transfer-aliasing"),
Self::KindDisagreement => write!(f, "kind-disagreement"),
Self::RegionDisagreement => write!(f, "region-disagreement"),
Self::WrongKind => write!(f, "wrong-kind"),
Self::SelfTransfer => write!(f, "self-transfer"),
}
}
}
impl fmt::Display for Counterexample {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"[{}] obligation {:?} at t={}: {}",
self.violation, self.obligation, self.time, self.description,
)
}
}
#[derive(Debug, Clone)]
pub struct ProofResult {
pub steps: Vec<ProofStep>,
pub counterexamples: Vec<Counterexample>,
pub events_processed: usize,
pub sendpermit_events: usize,
pub peak_active_permits: usize,
pub frame_checks: usize,
}
impl ProofResult {
#[must_use]
pub fn is_verified(&self) -> bool {
self.counterexamples.is_empty()
}
pub fn counterexamples_of_kind(
&self,
kind: ViolationKind,
) -> impl Iterator<Item = &Counterexample> {
self.counterexamples
.iter()
.filter(move |c| c.violation == kind)
}
#[must_use]
pub fn verified_step_count(&self) -> usize {
self.steps.iter().filter(|s| s.verified).count()
}
#[must_use]
pub fn steps_for_lemma(&self, lemma: Lemma) -> usize {
self.steps.iter().filter(|s| s.lemma == lemma).count()
}
}
impl fmt::Display for ProofResult {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "SendPermit No-Aliasing Proof")?;
writeln!(f, "============================")?;
writeln!(f, "Events processed: {}", self.events_processed)?;
writeln!(f, "SendPermit events: {}", self.sendpermit_events)?;
writeln!(f, "Proof steps: {}", self.steps.len())?;
writeln!(f, "Verified steps: {}", self.verified_step_count())?;
writeln!(f, "Frame checks: {}", self.frame_checks)?;
writeln!(f, "Peak active permits: {}", self.peak_active_permits)?;
writeln!(f, "Verified: {}", self.is_verified())?;
if !self.counterexamples.is_empty() {
writeln!(f)?;
writeln!(f, "Counterexamples ({}):", self.counterexamples.len())?;
for ce in &self.counterexamples {
writeln!(f, " {ce}")?;
}
}
Ok(())
}
}
#[derive(Debug)]
pub struct NoAliasingProver {
ghost: GhostPermitMap,
sendpermit_only: bool,
steps: Vec<ProofStep>,
counterexamples: Vec<Counterexample>,
sendpermit_events: usize,
peak_active: usize,
frame_checks: usize,
}
impl NoAliasingProver {
#[must_use]
pub fn new() -> Self {
Self {
ghost: GhostPermitMap::new(),
sendpermit_only: true,
steps: Vec::new(),
counterexamples: Vec::new(),
sendpermit_events: 0,
peak_active: 0,
frame_checks: 0,
}
}
#[must_use]
pub fn all_kinds() -> Self {
Self {
sendpermit_only: false,
..Self::new()
}
}
#[must_use]
pub fn check(&mut self, events: &[MarkingEvent]) -> ProofResult {
self.reset();
for event in events {
self.process_event(event);
}
self.check_final_invariant(events.last().map_or(Time::ZERO, |e| e.time));
ProofResult {
steps: self.steps.clone(),
counterexamples: self.counterexamples.clone(),
events_processed: events.len(),
sendpermit_events: self.sendpermit_events,
peak_active_permits: self.peak_active,
frame_checks: self.frame_checks,
}
}
fn reset(&mut self) {
self.ghost = GhostPermitMap::new();
self.steps.clear();
self.counterexamples.clear();
self.sendpermit_events = 0;
self.peak_active = 0;
self.frame_checks = 0;
}
fn should_check_kind(&self, kind: ObligationKind) -> bool {
if self.sendpermit_only {
kind == ObligationKind::SendPermit
} else {
true
}
}
fn should_check_resolution(&self, kind: ObligationKind, obligation: ObligationId) -> bool {
self.should_check_kind(kind) || self.ghost.active.contains_key(&obligation)
}
fn process_event(&mut self, event: &MarkingEvent) {
match &event.kind {
MarkingEventKind::Reserve {
obligation,
kind,
task,
region,
} => {
if self.should_check_kind(*kind) {
self.sendpermit_events += 1;
self.check_allocation(*obligation, *kind, *task, *region, event.time);
}
}
MarkingEventKind::Commit {
obligation,
kind,
region,
} => {
if self.should_check_resolution(*kind, *obligation) {
self.sendpermit_events += 1;
self.check_release(
*obligation,
*kind,
*region,
ConsumedHow::Committed,
event.time,
);
}
}
MarkingEventKind::Abort {
obligation,
kind,
region,
} => {
if self.should_check_resolution(*kind, *obligation) {
self.sendpermit_events += 1;
self.check_release(
*obligation,
*kind,
*region,
ConsumedHow::Aborted,
event.time,
);
}
}
MarkingEventKind::Leak {
obligation,
kind,
region,
} => {
if self.should_check_resolution(*kind, *obligation) {
self.sendpermit_events += 1;
self.check_drop(*obligation, *kind, *region, event.time);
}
}
MarkingEventKind::RegionClose { .. } => {
}
}
}
fn check_allocation(
&mut self,
obligation: ObligationId,
kind: ObligationKind,
holder: TaskId,
region: RegionId,
time: Time,
) {
if self.ghost.active.contains_key(&obligation) {
self.counterexamples.push(Counterexample {
violation: ViolationKind::DuplicateAllocation,
obligation,
time,
description: format!(
"reserve({obligation:?}) but permit already active \
(current holder: {:?}) — Excl(Reserved) · Excl(Reserved) = ⊥",
self.ghost.active[&obligation].holder,
),
});
self.steps.push(ProofStep {
lemma: Lemma::AllocationFreshness,
obligation,
time,
verified: false,
description: "duplicate allocation detected".to_string(),
});
return;
}
if self.ghost.is_consumed(obligation) {
self.counterexamples.push(Counterexample {
violation: ViolationKind::UseAfterRelease,
obligation,
time,
description: format!(
"reserve({obligation:?}) but permit was previously consumed — \
Excl::Consumed cannot be composed with Excl::Some",
),
});
self.steps.push(ProofStep {
lemma: Lemma::AllocationFreshness,
obligation,
time,
verified: false,
description: "use-after-release on reserve".to_string(),
});
return;
}
self.ghost.active.insert(
obligation,
GhostEntry {
holder,
kind,
region,
},
);
let count = self.ghost.holder_count(obligation);
if count != 1 {
self.counterexamples.push(Counterexample {
violation: ViolationKind::DoubleOwnership,
obligation,
time,
description: format!(
"after reserve, holder_count({obligation:?}) = {count}, expected 1",
),
});
self.steps.push(ProofStep {
lemma: Lemma::AllocationFreshness,
obligation,
time,
verified: false,
description: format!("holder count {count} != 1"),
});
return;
}
self.check_frame_preservation(obligation, time);
let active = self.ghost.active_count();
if active > self.peak_active {
self.peak_active = active;
}
self.steps.push(ProofStep {
lemma: Lemma::AllocationFreshness,
obligation,
time,
verified: true,
description: format!("fresh allocation: ghost_permits[{obligation:?}] = {holder:?}"),
});
}
fn check_release_preconditions(
&mut self,
obligation: ObligationId,
kind: ObligationKind,
region: RegionId,
how: ConsumedHow,
time: Time,
) -> Option<GhostEntry> {
if self.ghost.is_consumed(obligation) {
self.counterexamples.push(Counterexample {
violation: ViolationKind::UseAfterRelease,
obligation,
time,
description: format!(
"{how:?}({obligation:?}) but permit already consumed at {:?}",
self.ghost.consumed[&obligation].resolved_at,
),
});
self.steps.push(ProofStep {
lemma: Lemma::ReleaseConsumption,
obligation,
time,
verified: false,
description: "use-after-release on resolve".to_string(),
});
return None;
}
let Some(entry) = self.ghost.active.get(&obligation).cloned() else {
self.counterexamples.push(Counterexample {
violation: ViolationKind::UseAfterRelease,
obligation,
time,
description: format!(
"{how:?}({obligation:?}) but permit not in ghost map — \
never reserved",
),
});
self.steps.push(ProofStep {
lemma: Lemma::ReleaseConsumption,
obligation,
time,
verified: false,
description: "resolve without prior reserve".to_string(),
});
return None;
};
if entry.kind != kind {
self.counterexamples.push(Counterexample {
violation: ViolationKind::KindDisagreement,
obligation,
time,
description: format!(
"reserved as {}, resolving as {kind} — Agree({}) · Agree({kind}) = ⊥",
entry.kind, entry.kind,
),
});
self.steps.push(ProofStep {
lemma: Lemma::ReleaseConsumption,
obligation,
time,
verified: false,
description: "kind disagreement".to_string(),
});
return None;
}
if entry.region != region {
self.counterexamples.push(Counterexample {
violation: ViolationKind::RegionDisagreement,
obligation,
time,
description: format!(
"reserved in {:?}, resolving in {region:?} — \
Agree({:?}) · Agree({region:?}) = ⊥",
entry.region, entry.region,
),
});
self.steps.push(ProofStep {
lemma: Lemma::ReleaseConsumption,
obligation,
time,
verified: false,
description: "region disagreement".to_string(),
});
return None;
}
Some(entry)
}
fn check_release(
&mut self,
obligation: ObligationId,
kind: ObligationKind,
region: RegionId,
how: ConsumedHow,
time: Time,
) {
let Some(entry) = self.check_release_preconditions(obligation, kind, region, how, time)
else {
return;
};
self.ghost.active.remove(&obligation);
self.ghost.consumed.insert(
obligation,
ConsumedEntry {
_resolution: how,
resolved_at: time,
_last_holder: entry.holder,
},
);
let count = self.ghost.holder_count(obligation);
if count != 0 {
self.counterexamples.push(Counterexample {
violation: ViolationKind::DoubleOwnership,
obligation,
time,
description: format!(
"after {how:?}, holder_count({obligation:?}) = {count}, expected 0",
),
});
self.steps.push(ProofStep {
lemma: Lemma::ReleaseConsumption,
obligation,
time,
verified: false,
description: format!("post-release holder count {count} != 0"),
});
return;
}
self.check_frame_preservation(obligation, time);
self.steps.push(ProofStep {
lemma: Lemma::ReleaseConsumption,
obligation,
time,
verified: true,
description: format!("{how:?}: ghost_permits removes {obligation:?}, holders = 0"),
});
}
fn check_drop(
&mut self,
obligation: ObligationId,
kind: ObligationKind,
region: RegionId,
time: Time,
) {
if self.ghost.is_consumed(obligation) {
self.counterexamples.push(Counterexample {
violation: ViolationKind::UseAfterRelease,
obligation,
time,
description: format!("leak({obligation:?}) but permit already consumed"),
});
self.steps.push(ProofStep {
lemma: Lemma::DropSafety,
obligation,
time,
verified: false,
description: "use-after-release on leak".to_string(),
});
return;
}
let Some(entry) = self.ghost.active.get(&obligation).cloned() else {
self.counterexamples.push(Counterexample {
violation: ViolationKind::UseAfterRelease,
obligation,
time,
description: format!("leak({obligation:?}) but permit not in ghost map"),
});
self.steps.push(ProofStep {
lemma: Lemma::DropSafety,
obligation,
time,
verified: false,
description: "leak without prior reserve".to_string(),
});
return;
};
let mut mismatch_detected = false;
if entry.kind != kind {
mismatch_detected = true;
self.counterexamples.push(Counterexample {
violation: ViolationKind::KindDisagreement,
obligation,
time,
description: format!(
"leak kind mismatch: reserved as {}, leaked as {kind}",
entry.kind,
),
});
}
if entry.region != region {
mismatch_detected = true;
self.counterexamples.push(Counterexample {
violation: ViolationKind::RegionDisagreement,
obligation,
time,
description: format!(
"leak region mismatch: reserved in {:?}, leaked in {region:?}",
entry.region,
),
});
}
self.ghost.active.remove(&obligation);
self.ghost.consumed.insert(
obligation,
ConsumedEntry {
_resolution: ConsumedHow::Leaked,
resolved_at: time,
_last_holder: entry.holder,
},
);
self.check_frame_preservation(obligation, time);
self.steps.push(ProofStep {
lemma: Lemma::DropSafety,
obligation,
time,
verified: !mismatch_detected,
description: if mismatch_detected {
format!(
"drop consumed {obligation:?}, ErrorFlag signaled (leak), but kind/region agreement failed"
)
} else {
format!("drop consumed {obligation:?}, ErrorFlag signaled (leak)")
},
});
}
fn check_frame_preservation(&mut self, operated_on: ObligationId, time: Time) {
self.frame_checks += 1;
for (&id, entry) in &self.ghost.active {
if id == operated_on {
continue;
}
let count = 1; if count != 1 {
self.counterexamples.push(Counterexample {
violation: ViolationKind::DoubleOwnership,
obligation: id,
time,
description: format!(
"frame violation: operation on {operated_on:?} disturbed \
{id:?} (holder count = {count})",
),
});
}
self.steps.push(ProofStep {
lemma: Lemma::ConcurrentIndependence,
obligation: id,
time,
verified: true,
description: format!("frame preserved: {id:?} still held by {:?}", entry.holder),
});
}
}
fn check_final_invariant(&mut self, trace_end: Time) {
for (&id, entry) in &self.ghost.active {
let count = self.ghost.holder_count(id);
if count != 1 {
self.counterexamples.push(Counterexample {
violation: ViolationKind::DoubleOwnership,
obligation: id,
time: trace_end,
description: format!(
"final invariant: {id:?} has {count} holders, expected 1",
),
});
}
let _ = entry; }
}
}
impl Default for NoAliasingProver {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone)]
pub struct TransferEvent {
pub obligation: ObligationId,
pub from: TaskId,
pub to: TaskId,
pub time: Time,
}
impl NoAliasingProver {
pub fn apply_transfer(&mut self, transfer: &TransferEvent) {
let obligation = transfer.obligation;
let time = transfer.time;
let Some(entry) = self.ghost.active.get(&obligation).cloned() else {
self.counterexamples.push(Counterexample {
violation: ViolationKind::UseAfterRelease,
obligation,
time,
description: format!("transfer({obligation:?}) but permit not active"),
});
self.steps.push(ProofStep {
lemma: Lemma::TransferExclusivity,
obligation,
time,
verified: false,
description: "transfer of non-active permit".to_string(),
});
return;
};
if entry.holder != transfer.from {
self.counterexamples.push(Counterexample {
violation: ViolationKind::TransferAliasing,
obligation,
time,
description: format!(
"transfer from {:?} but current holder is {:?} — \
Excl violation: two tasks claim ownership",
transfer.from, entry.holder,
),
});
self.steps.push(ProofStep {
lemma: Lemma::TransferExclusivity,
obligation,
time,
verified: false,
description: "transfer from wrong holder".to_string(),
});
return;
}
if transfer.from == transfer.to {
self.counterexamples.push(Counterexample {
violation: ViolationKind::SelfTransfer,
obligation,
time,
description: format!(
"self-transfer on {obligation:?} from {:?} to {:?} is disallowed",
transfer.from, transfer.to,
),
});
self.steps.push(ProofStep {
lemma: Lemma::TransferExclusivity,
obligation,
time,
verified: false,
description: "self-transfer is disallowed".to_string(),
});
return;
}
self.ghost
.active
.get_mut(&obligation)
.expect("obligation must be active")
.holder = transfer.to;
let count = self.ghost.holder_count(obligation);
if count != 1 {
self.counterexamples.push(Counterexample {
violation: ViolationKind::DoubleOwnership,
obligation,
time,
description: format!(
"after transfer, holder_count({obligation:?}) = {count}, expected 1",
),
});
self.steps.push(ProofStep {
lemma: Lemma::TransferExclusivity,
obligation,
time,
verified: false,
description: format!("post-transfer holder count {count} != 1"),
});
return;
}
self.check_frame_preservation(obligation, time);
self.steps.push(ProofStep {
lemma: Lemma::TransferExclusivity,
obligation,
time,
verified: true,
description: format!(
"transfer: ghost_permits[{obligation:?}] = {:?} → {:?}",
transfer.from, transfer.to,
),
});
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::obligation::marking::{MarkingEvent, MarkingEventKind};
use crate::util::ArenaIndex;
fn init_test(name: &str) {
crate::test_utils::init_test_logging();
crate::test_phase!(name);
}
fn r(n: u32) -> RegionId {
RegionId::from_arena(ArenaIndex::new(n, 0))
}
fn t(n: u32) -> TaskId {
TaskId::from_arena(ArenaIndex::new(n, 0))
}
fn o(n: u32) -> ObligationId {
ObligationId::from_arena(ArenaIndex::new(n, 0))
}
fn reserve(
time_ns: u64,
obligation: ObligationId,
kind: ObligationKind,
task: TaskId,
region: RegionId,
) -> MarkingEvent {
MarkingEvent::new(
Time::from_nanos(time_ns),
MarkingEventKind::Reserve {
obligation,
kind,
task,
region,
},
)
}
fn commit(
time_ns: u64,
obligation: ObligationId,
region: RegionId,
kind: ObligationKind,
) -> MarkingEvent {
MarkingEvent::new(
Time::from_nanos(time_ns),
MarkingEventKind::Commit {
obligation,
region,
kind,
},
)
}
fn abort(
time_ns: u64,
obligation: ObligationId,
region: RegionId,
kind: ObligationKind,
) -> MarkingEvent {
MarkingEvent::new(
Time::from_nanos(time_ns),
MarkingEventKind::Abort {
obligation,
region,
kind,
},
)
}
fn leak(
time_ns: u64,
obligation: ObligationId,
region: RegionId,
kind: ObligationKind,
) -> MarkingEvent {
MarkingEvent::new(
Time::from_nanos(time_ns),
MarkingEventKind::Leak {
obligation,
region,
kind,
},
)
}
#[test]
fn lemma1_single_allocation() {
init_test("lemma1_single_allocation");
let events = vec![
reserve(0, o(0), ObligationKind::SendPermit, t(0), r(0)),
commit(10, o(0), r(0), ObligationKind::SendPermit),
];
let mut prover = NoAliasingProver::new();
let result = prover.check(&events);
let verified = result.is_verified();
crate::assert_with_log!(verified, "single allocation verified", true, verified);
let alloc_steps = result.steps_for_lemma(Lemma::AllocationFreshness);
crate::assert_with_log!(
alloc_steps >= 1,
"at least 1 allocation step",
true,
alloc_steps >= 1
);
crate::test_complete!("lemma1_single_allocation");
}
#[test]
fn lemma1_multiple_fresh_allocations() {
init_test("lemma1_multiple_fresh_allocations");
let events = vec![
reserve(0, o(0), ObligationKind::SendPermit, t(0), r(0)),
reserve(1, o(1), ObligationKind::SendPermit, t(1), r(0)),
reserve(2, o(2), ObligationKind::SendPermit, t(2), r(0)),
commit(10, o(0), r(0), ObligationKind::SendPermit),
commit(11, o(1), r(0), ObligationKind::SendPermit),
commit(12, o(2), r(0), ObligationKind::SendPermit),
];
let mut prover = NoAliasingProver::new();
let result = prover.check(&events);
let verified = result.is_verified();
crate::assert_with_log!(verified, "3 fresh allocations verified", true, verified);
let peak = result.peak_active_permits;
crate::assert_with_log!(peak == 3, "peak active = 3", 3, peak);
crate::test_complete!("lemma1_multiple_fresh_allocations");
}
#[test]
fn lemma1_rejects_duplicate_allocation() {
init_test("lemma1_rejects_duplicate_allocation");
let events = vec![
reserve(0, o(0), ObligationKind::SendPermit, t(0), r(0)),
reserve(5, o(0), ObligationKind::SendPermit, t(1), r(0)), ];
let mut prover = NoAliasingProver::new();
let result = prover.check(&events);
let verified = result.is_verified();
crate::assert_with_log!(!verified, "duplicate detected", false, verified);
let dup_count = result
.counterexamples_of_kind(ViolationKind::DuplicateAllocation)
.count();
crate::assert_with_log!(dup_count == 1, "1 duplicate violation", 1, dup_count);
crate::test_complete!("lemma1_rejects_duplicate_allocation");
}
#[test]
fn lemma1_rejects_reserve_after_consume() {
init_test("lemma1_rejects_reserve_after_consume");
let events = vec![
reserve(0, o(0), ObligationKind::SendPermit, t(0), r(0)),
commit(5, o(0), r(0), ObligationKind::SendPermit),
reserve(10, o(0), ObligationKind::SendPermit, t(1), r(0)), ];
let mut prover = NoAliasingProver::new();
let result = prover.check(&events);
let verified = result.is_verified();
crate::assert_with_log!(!verified, "reuse after consume detected", false, verified);
let uar_count = result
.counterexamples_of_kind(ViolationKind::UseAfterRelease)
.count();
crate::assert_with_log!(uar_count == 1, "1 use-after-release", 1, uar_count);
crate::test_complete!("lemma1_rejects_reserve_after_consume");
}
#[test]
fn lemma2_valid_transfer() {
init_test("lemma2_valid_transfer");
let events = vec![reserve(0, o(0), ObligationKind::SendPermit, t(0), r(0))];
let mut prover = NoAliasingProver::new();
for event in &events {
prover.process_event(event);
}
prover.apply_transfer(&TransferEvent {
obligation: o(0),
from: t(0),
to: t(1),
time: Time::from_nanos(5),
});
let holder = prover.ghost.holder_of(o(0));
crate::assert_with_log!(
holder == Some(t(1)),
"holder is now t(1)",
Some(t(1)),
holder
);
let violations = prover.counterexamples.len();
crate::assert_with_log!(violations == 0, "no violations", 0, violations);
let transfer_steps = prover
.steps
.iter()
.filter(|s| s.lemma == Lemma::TransferExclusivity)
.count();
crate::assert_with_log!(
transfer_steps >= 1,
"at least 1 transfer step",
true,
transfer_steps >= 1
);
crate::test_complete!("lemma2_valid_transfer");
}
#[test]
fn lemma2_chain_transfer() {
init_test("lemma2_chain_transfer");
let events = vec![reserve(0, o(0), ObligationKind::SendPermit, t(0), r(0))];
let mut prover = NoAliasingProver::new();
for event in &events {
prover.process_event(event);
}
prover.apply_transfer(&TransferEvent {
obligation: o(0),
from: t(0),
to: t(1),
time: Time::from_nanos(5),
});
prover.apply_transfer(&TransferEvent {
obligation: o(0),
from: t(1),
to: t(2),
time: Time::from_nanos(10),
});
let holder = prover.ghost.holder_of(o(0));
crate::assert_with_log!(
holder == Some(t(2)),
"holder is t(2) after chain",
Some(t(2)),
holder
);
let violations = prover.counterexamples.len();
crate::assert_with_log!(violations == 0, "no violations", 0, violations);
crate::test_complete!("lemma2_chain_transfer");
}
#[test]
fn lemma2_rejects_self_transfer() {
init_test("lemma2_rejects_self_transfer");
let events = vec![reserve(0, o(0), ObligationKind::SendPermit, t(0), r(0))];
let mut prover = NoAliasingProver::new();
for event in &events {
prover.process_event(event);
}
prover.apply_transfer(&TransferEvent {
obligation: o(0),
from: t(0),
to: t(0),
time: Time::from_nanos(5),
});
let self_transfer_count = prover
.counterexamples
.iter()
.filter(|c| c.violation == ViolationKind::SelfTransfer)
.count();
crate::assert_with_log!(
self_transfer_count == 1,
"1 self-transfer violation",
1,
self_transfer_count
);
crate::test_complete!("lemma2_rejects_self_transfer");
}
#[test]
fn lemma2_rejects_transfer_from_wrong_holder() {
init_test("lemma2_rejects_transfer_from_wrong_holder");
let events = vec![reserve(0, o(0), ObligationKind::SendPermit, t(0), r(0))];
let mut prover = NoAliasingProver::new();
for event in &events {
prover.process_event(event);
}
prover.apply_transfer(&TransferEvent {
obligation: o(0),
from: t(1), to: t(2),
time: Time::from_nanos(5),
});
let alias_count = prover
.counterexamples
.iter()
.filter(|c| c.violation == ViolationKind::TransferAliasing)
.count();
crate::assert_with_log!(alias_count == 1, "1 transfer aliasing", 1, alias_count);
crate::test_complete!("lemma2_rejects_transfer_from_wrong_holder");
}
#[test]
fn lemma2_rejects_transfer_of_consumed() {
init_test("lemma2_rejects_transfer_of_consumed");
let events = vec![
reserve(0, o(0), ObligationKind::SendPermit, t(0), r(0)),
commit(5, o(0), r(0), ObligationKind::SendPermit),
];
let mut prover = NoAliasingProver::new();
for event in &events {
prover.process_event(event);
}
prover.apply_transfer(&TransferEvent {
obligation: o(0),
from: t(0),
to: t(1),
time: Time::from_nanos(10),
});
let uar_count = prover
.counterexamples
.iter()
.filter(|c| c.violation == ViolationKind::UseAfterRelease)
.count();
crate::assert_with_log!(uar_count == 1, "1 use-after-release", 1, uar_count);
crate::test_complete!("lemma2_rejects_transfer_of_consumed");
}
#[test]
fn lemma3_commit_consumes() {
init_test("lemma3_commit_consumes");
let events = vec![
reserve(0, o(0), ObligationKind::SendPermit, t(0), r(0)),
commit(10, o(0), r(0), ObligationKind::SendPermit),
];
let mut prover = NoAliasingProver::new();
let result = prover.check(&events);
let verified = result.is_verified();
crate::assert_with_log!(verified, "commit consumption verified", true, verified);
let release_steps = result.steps_for_lemma(Lemma::ReleaseConsumption);
crate::assert_with_log!(
release_steps >= 1,
"at least 1 release step",
true,
release_steps >= 1
);
crate::test_complete!("lemma3_commit_consumes");
}
#[test]
fn lemma3_abort_consumes() {
init_test("lemma3_abort_consumes");
let events = vec![
reserve(0, o(0), ObligationKind::SendPermit, t(0), r(0)),
abort(10, o(0), r(0), ObligationKind::SendPermit),
];
let mut prover = NoAliasingProver::new();
let result = prover.check(&events);
let verified = result.is_verified();
crate::assert_with_log!(verified, "abort consumption verified", true, verified);
crate::test_complete!("lemma3_abort_consumes");
}
#[test]
fn lemma3_rejects_double_commit() {
init_test("lemma3_rejects_double_commit");
let events = vec![
reserve(0, o(0), ObligationKind::SendPermit, t(0), r(0)),
commit(5, o(0), r(0), ObligationKind::SendPermit),
commit(10, o(0), r(0), ObligationKind::SendPermit), ];
let mut prover = NoAliasingProver::new();
let result = prover.check(&events);
let verified = result.is_verified();
crate::assert_with_log!(!verified, "double commit rejected", false, verified);
let uar_count = result
.counterexamples_of_kind(ViolationKind::UseAfterRelease)
.count();
crate::assert_with_log!(uar_count == 1, "1 use-after-release", 1, uar_count);
crate::test_complete!("lemma3_rejects_double_commit");
}
#[test]
fn lemma3_rejects_commit_without_reserve() {
init_test("lemma3_rejects_commit_without_reserve");
let events = vec![commit(10, o(99), r(0), ObligationKind::SendPermit)];
let mut prover = NoAliasingProver::new();
let result = prover.check(&events);
let verified = result.is_verified();
crate::assert_with_log!(!verified, "orphan commit rejected", false, verified);
crate::test_complete!("lemma3_rejects_commit_without_reserve");
}
#[test]
fn lemma3_rejects_kind_mismatch() {
init_test("lemma3_rejects_kind_mismatch");
let events = vec![
reserve(0, o(0), ObligationKind::SendPermit, t(0), r(0)),
commit(10, o(0), r(0), ObligationKind::Lease), ];
let mut prover = NoAliasingProver::new();
let result = prover.check(&events);
let verified = result.is_verified();
crate::assert_with_log!(!verified, "kind mismatch rejected", false, verified);
let kd_count = result
.counterexamples_of_kind(ViolationKind::KindDisagreement)
.count();
crate::assert_with_log!(kd_count == 1, "1 kind disagreement", 1, kd_count);
crate::test_complete!("lemma3_rejects_kind_mismatch");
}
#[test]
fn lemma3_rejects_region_mismatch() {
init_test("lemma3_rejects_region_mismatch");
let events = vec![
reserve(0, o(0), ObligationKind::SendPermit, t(0), r(0)),
commit(10, o(0), r(1), ObligationKind::SendPermit), ];
let mut prover = NoAliasingProver::new();
let result = prover.check(&events);
let verified = result.is_verified();
crate::assert_with_log!(!verified, "region mismatch rejected", false, verified);
let rd_count = result
.counterexamples_of_kind(ViolationKind::RegionDisagreement)
.count();
crate::assert_with_log!(rd_count == 1, "1 region disagreement", 1, rd_count);
crate::test_complete!("lemma3_rejects_region_mismatch");
}
#[test]
fn lemma4_independent_permits() {
init_test("lemma4_independent_permits");
let events = vec![
reserve(0, o(0), ObligationKind::SendPermit, t(0), r(0)),
reserve(1, o(1), ObligationKind::SendPermit, t(1), r(0)),
commit(10, o(0), r(0), ObligationKind::SendPermit),
commit(15, o(1), r(0), ObligationKind::SendPermit),
];
let mut prover = NoAliasingProver::new();
let result = prover.check(&events);
let verified = result.is_verified();
crate::assert_with_log!(verified, "independent permits verified", true, verified);
let frame_checks = result.frame_checks;
crate::assert_with_log!(
frame_checks >= 2,
"at least 2 frame checks",
true,
frame_checks >= 2
);
crate::test_complete!("lemma4_independent_permits");
}
#[test]
fn lemma4_many_concurrent_permits() {
init_test("lemma4_many_concurrent_permits");
let mut events = Vec::new();
for i in 0..10 {
events.push(reserve(
u64::from(i),
o(i),
ObligationKind::SendPermit,
t(i),
r(0),
));
}
for i in (0..10).rev() {
events.push(commit(
u64::from(10 + i),
o(i),
r(0),
ObligationKind::SendPermit,
));
}
let mut prover = NoAliasingProver::new();
let result = prover.check(&events);
let verified = result.is_verified();
crate::assert_with_log!(verified, "10 concurrent permits verified", true, verified);
let peak = result.peak_active_permits;
crate::assert_with_log!(peak == 10, "peak = 10", 10, peak);
crate::test_complete!("lemma4_many_concurrent_permits");
}
#[test]
fn lemma5_leak_consumes() {
init_test("lemma5_leak_consumes");
let events = vec![
reserve(0, o(0), ObligationKind::SendPermit, t(0), r(0)),
leak(5, o(0), r(0), ObligationKind::SendPermit),
];
let mut prover = NoAliasingProver::new();
let result = prover.check(&events);
let verified = result.is_verified();
crate::assert_with_log!(verified, "leak consumed (proof verified)", true, verified);
let drop_steps = result.steps_for_lemma(Lemma::DropSafety);
crate::assert_with_log!(
drop_steps >= 1,
"at least 1 drop step",
true,
drop_steps >= 1
);
crate::test_complete!("lemma5_leak_consumes");
}
#[test]
fn lemma5_rejects_double_leak() {
init_test("lemma5_rejects_double_leak");
let events = vec![
reserve(0, o(0), ObligationKind::SendPermit, t(0), r(0)),
leak(5, o(0), r(0), ObligationKind::SendPermit),
leak(10, o(0), r(0), ObligationKind::SendPermit), ];
let mut prover = NoAliasingProver::new();
let result = prover.check(&events);
let verified = result.is_verified();
crate::assert_with_log!(!verified, "double leak rejected", false, verified);
crate::test_complete!("lemma5_rejects_double_leak");
}
#[test]
fn lemma5_kind_mismatch_marks_failed_drop_step() {
init_test("lemma5_kind_mismatch_marks_failed_drop_step");
let events = vec![
reserve(0, o(0), ObligationKind::SendPermit, t(0), r(0)),
leak(5, o(0), r(0), ObligationKind::Ack), ];
let mut prover = NoAliasingProver::new();
let result = prover.check(&events);
crate::assert_with_log!(
!result.is_verified(),
"kind mismatch on leak rejected",
false,
result.is_verified()
);
let has_failed_drop_step = result
.steps
.iter()
.any(|step| step.lemma == Lemma::DropSafety && !step.verified);
crate::assert_with_log!(
has_failed_drop_step,
"drop mismatch produces failed DropSafety step",
true,
has_failed_drop_step
);
crate::test_complete!("lemma5_kind_mismatch_marks_failed_drop_step");
}
#[test]
fn lemma5_region_mismatch_marks_failed_drop_step() {
init_test("lemma5_region_mismatch_marks_failed_drop_step");
let events = vec![
reserve(0, o(0), ObligationKind::SendPermit, t(0), r(0)),
leak(5, o(0), r(1), ObligationKind::SendPermit), ];
let mut prover = NoAliasingProver::new();
let result = prover.check(&events);
crate::assert_with_log!(
!result.is_verified(),
"region mismatch on leak rejected",
false,
result.is_verified()
);
let has_failed_drop_step = result
.steps
.iter()
.any(|step| step.lemma == Lemma::DropSafety && !step.verified);
crate::assert_with_log!(
has_failed_drop_step,
"region mismatch produces failed DropSafety step",
true,
has_failed_drop_step
);
crate::test_complete!("lemma5_region_mismatch_marks_failed_drop_step");
}
#[test]
fn all_kinds_mode_verifies_all() {
init_test("all_kinds_mode_verifies_all");
let events = vec![
reserve(0, o(0), ObligationKind::SendPermit, t(0), r(0)),
reserve(1, o(1), ObligationKind::Ack, t(1), r(0)),
reserve(2, o(2), ObligationKind::Lease, t(2), r(0)),
reserve(3, o(3), ObligationKind::IoOp, t(3), r(0)),
commit(10, o(0), r(0), ObligationKind::SendPermit),
commit(11, o(1), r(0), ObligationKind::Ack),
abort(12, o(2), r(0), ObligationKind::Lease),
leak(13, o(3), r(0), ObligationKind::IoOp),
];
let mut prover = NoAliasingProver::all_kinds();
let result = prover.check(&events);
let verified = result.is_verified();
crate::assert_with_log!(verified, "all 4 kinds verified", true, verified);
let sp_events = result.sendpermit_events;
crate::assert_with_log!(sp_events == 8, "8 events processed", 8, sp_events);
crate::test_complete!("all_kinds_mode_verifies_all");
}
#[test]
fn sendpermit_only_mode_skips_others() {
init_test("sendpermit_only_mode_skips_others");
let events = vec![
reserve(0, o(0), ObligationKind::SendPermit, t(0), r(0)),
reserve(1, o(1), ObligationKind::Ack, t(1), r(0)), reserve(2, o(2), ObligationKind::Lease, t(2), r(0)), commit(10, o(0), r(0), ObligationKind::SendPermit),
commit(11, o(1), r(0), ObligationKind::Ack), abort(12, o(2), r(0), ObligationKind::Lease), ];
let mut prover = NoAliasingProver::new();
let result = prover.check(&events);
let verified = result.is_verified();
crate::assert_with_log!(verified, "sendpermit-only verified", true, verified);
let sp_events = result.sendpermit_events;
crate::assert_with_log!(sp_events == 2, "only 2 SendPermit events", 2, sp_events);
crate::test_complete!("sendpermit_only_mode_skips_others");
}
#[test]
fn mutation_cloned_permit() {
init_test("mutation_cloned_permit");
let events = vec![
reserve(0, o(0), ObligationKind::SendPermit, t(0), r(0)),
reserve(5, o(0), ObligationKind::SendPermit, t(1), r(0)), ];
let mut prover = NoAliasingProver::new();
let result = prover.check(&events);
let verified = result.is_verified();
crate::assert_with_log!(!verified, "cloned permit rejected", false, verified);
crate::test_complete!("mutation_cloned_permit");
}
#[test]
fn mutation_commit_then_abort_same_permit() {
init_test("mutation_commit_then_abort_same_permit");
let events = vec![
reserve(0, o(0), ObligationKind::SendPermit, t(0), r(0)),
commit(5, o(0), r(0), ObligationKind::SendPermit),
abort(10, o(0), r(0), ObligationKind::SendPermit), ];
let mut prover = NoAliasingProver::new();
let result = prover.check(&events);
let verified = result.is_verified();
crate::assert_with_log!(!verified, "double resolution rejected", false, verified);
crate::test_complete!("mutation_commit_then_abort_same_permit");
}
#[test]
fn mutation_stale_transfer() {
init_test("mutation_stale_transfer");
let events = vec![
reserve(0, o(0), ObligationKind::SendPermit, t(0), r(0)),
commit(5, o(0), r(0), ObligationKind::SendPermit),
];
let mut prover = NoAliasingProver::new();
for event in &events {
prover.process_event(event);
}
prover.apply_transfer(&TransferEvent {
obligation: o(0),
from: t(0),
to: t(1),
time: Time::from_nanos(10),
});
let violations = prover.counterexamples.len();
crate::assert_with_log!(
violations >= 1,
"stale transfer rejected",
true,
violations >= 1
);
crate::test_complete!("mutation_stale_transfer");
}
#[test]
fn mutation_kind_confusion() {
init_test("mutation_kind_confusion");
let events = vec![
reserve(0, o(0), ObligationKind::SendPermit, t(0), r(0)),
commit(10, o(0), r(0), ObligationKind::Ack), ];
let mut prover = NoAliasingProver::new();
let result = prover.check(&events);
let verified = result.is_verified();
crate::assert_with_log!(!verified, "kind confusion rejected", false, verified);
crate::test_complete!("mutation_kind_confusion");
}
#[test]
fn realistic_two_phase_send_with_cancel() {
init_test("realistic_two_phase_send_with_cancel");
let events = vec![
reserve(0, o(0), ObligationKind::SendPermit, t(0), r(0)),
abort(10, o(0), r(0), ObligationKind::SendPermit),
];
let mut prover = NoAliasingProver::new();
let result = prover.check(&events);
let verified = result.is_verified();
crate::assert_with_log!(verified, "cancel path verified", true, verified);
crate::test_complete!("realistic_two_phase_send_with_cancel");
}
#[test]
fn realistic_work_stealing_delegation() {
init_test("realistic_work_stealing_delegation");
let events = vec![reserve(0, o(0), ObligationKind::SendPermit, t(0), r(0))];
let mut prover = NoAliasingProver::new();
for event in &events {
prover.process_event(event);
}
prover.apply_transfer(&TransferEvent {
obligation: o(0),
from: t(0),
to: t(1),
time: Time::from_nanos(5),
});
let commit_event = commit(10, o(0), r(0), ObligationKind::SendPermit);
prover.process_event(&commit_event);
let violations = prover.counterexamples.len();
crate::assert_with_log!(violations == 0, "delegation verified", 0, violations);
crate::test_complete!("realistic_work_stealing_delegation");
}
#[test]
fn realistic_multi_region_permits() {
init_test("realistic_multi_region_permits");
let events = vec![
reserve(0, o(0), ObligationKind::SendPermit, t(0), r(0)),
reserve(1, o(1), ObligationKind::SendPermit, t(0), r(1)),
commit(10, o(0), r(0), ObligationKind::SendPermit),
commit(11, o(1), r(1), ObligationKind::SendPermit),
];
let mut prover = NoAliasingProver::new();
let result = prover.check(&events);
let verified = result.is_verified();
crate::assert_with_log!(verified, "multi-region verified", true, verified);
crate::test_complete!("realistic_multi_region_permits");
}
#[test]
fn realistic_same_task_multiple_permits() {
init_test("realistic_same_task_multiple_permits");
let events = vec![
reserve(0, o(0), ObligationKind::SendPermit, t(0), r(0)),
reserve(1, o(1), ObligationKind::SendPermit, t(0), r(0)),
reserve(2, o(2), ObligationKind::SendPermit, t(0), r(0)),
commit(10, o(0), r(0), ObligationKind::SendPermit),
commit(11, o(1), r(0), ObligationKind::SendPermit),
commit(12, o(2), r(0), ObligationKind::SendPermit),
];
let mut prover = NoAliasingProver::new();
let result = prover.check(&events);
let verified = result.is_verified();
crate::assert_with_log!(verified, "same task multi-permit verified", true, verified);
crate::test_complete!("realistic_same_task_multiple_permits");
}
#[test]
fn proof_result_display() {
init_test("proof_result_display");
let events = vec![
reserve(0, o(0), ObligationKind::SendPermit, t(0), r(0)),
commit(10, o(0), r(0), ObligationKind::SendPermit),
];
let mut prover = NoAliasingProver::new();
let result = prover.check(&events);
let display = format!("{result}");
let has_title = display.contains("No-Aliasing");
crate::assert_with_log!(has_title, "display has title", true, has_title);
let has_verified = display.contains("Verified:");
crate::assert_with_log!(has_verified, "display has verified", true, has_verified);
crate::test_complete!("proof_result_display");
}
#[test]
fn counterexample_display() {
init_test("counterexample_display");
let ce = Counterexample {
violation: ViolationKind::DuplicateAllocation,
obligation: o(0),
time: Time::from_nanos(42),
description: "test counterexample".to_string(),
};
let s = format!("{ce}");
let has_violation = s.contains("duplicate-allocation");
crate::assert_with_log!(has_violation, "display has violation", true, has_violation);
crate::test_complete!("counterexample_display");
}
#[test]
fn lemma_display() {
init_test("lemma_display");
let lemmas = [
Lemma::AllocationFreshness,
Lemma::TransferExclusivity,
Lemma::ReleaseConsumption,
Lemma::ConcurrentIndependence,
Lemma::DropSafety,
];
for lemma in &lemmas {
let s = format!("{lemma}");
let non_empty = !s.is_empty();
crate::assert_with_log!(non_empty, format!("{lemma:?} has display"), true, non_empty);
}
crate::test_complete!("lemma_display");
}
#[test]
fn empty_trace() {
init_test("empty_trace");
let mut prover = NoAliasingProver::new();
let result = prover.check(&[]);
let verified = result.is_verified();
crate::assert_with_log!(verified, "empty trace verified", true, verified);
let events = result.events_processed;
crate::assert_with_log!(events == 0, "0 events", 0, events);
crate::test_complete!("empty_trace");
}
#[test]
fn prover_reuse_resets() {
init_test("prover_reuse_resets");
let mut prover = NoAliasingProver::new();
let events1 = vec![
reserve(0, o(0), ObligationKind::SendPermit, t(0), r(0)),
reserve(5, o(0), ObligationKind::SendPermit, t(1), r(0)),
];
let r1 = prover.check(&events1);
let r1_ok = r1.is_verified();
crate::assert_with_log!(!r1_ok, "first check not verified", false, r1_ok);
let events2 = vec![
reserve(0, o(0), ObligationKind::SendPermit, t(0), r(0)),
commit(10, o(0), r(0), ObligationKind::SendPermit),
];
let r2 = prover.check(&events2);
let r2_ok = r2.is_verified();
crate::assert_with_log!(r2_ok, "second check verified (reset)", true, r2_ok);
crate::test_complete!("prover_reuse_resets");
}
#[test]
fn lemma_debug_clone_copy_eq() {
let a = Lemma::AllocationFreshness;
let b = a; let c = a;
assert_eq!(a, b);
assert_eq!(a, c);
assert_ne!(a, Lemma::DropSafety);
let dbg = format!("{a:?}");
assert!(dbg.contains("AllocationFreshness"));
}
#[test]
fn violation_kind_debug_clone_copy_eq() {
let a = ViolationKind::DoubleOwnership;
let b = a; let c = a;
assert_eq!(a, b);
assert_eq!(a, c);
assert_ne!(a, ViolationKind::SelfTransfer);
let dbg = format!("{a:?}");
assert!(dbg.contains("DoubleOwnership"));
}
}