use crate::labels::{Cap, SourceKind};
use crate::taint::path_state::PredicateKind;
use petgraph::graph::NodeIndex;
use smallvec::SmallVec;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct VarTaint {
pub caps: Cap,
pub origins: SmallVec<[TaintOrigin; 2]>,
pub uses_summary: bool,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct TaintOrigin {
pub node: NodeIndex,
pub source_kind: SourceKind,
pub source_span: Option<(usize, usize)>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct SmallBitSet(u64);
impl SmallBitSet {
pub fn empty() -> Self {
Self(0)
}
pub fn insert(&mut self, id: crate::state::symbol::SymbolId) {
let idx = id.0;
if idx < 64 {
self.0 |= 1u64 << idx;
} else {
tracing::debug!(
target: "nyx::predicate_bitset",
id = idx,
"SmallBitSet: dropped id >= 64; path-sensitivity degrades for this variable"
);
}
}
pub fn contains(&self, id: crate::state::symbol::SymbolId) -> bool {
let idx = id.0;
if idx < 64 {
self.0 & (1u64 << idx) != 0
} else {
false
}
}
pub fn union(self, other: Self) -> Self {
Self(self.0 | other.0)
}
pub fn intersection(self, other: Self) -> Self {
Self(self.0 & other.0)
}
pub fn is_empty(self) -> bool {
self.0 == 0
}
pub fn is_subset_of(self, other: Self) -> bool {
self.0 & other.0 == self.0
}
pub fn is_superset_of(self, other: Self) -> bool {
other.is_subset_of(self)
}
pub fn bits(self) -> u64 {
self.0
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct PredicateSummary {
pub known_true: u8,
pub known_false: u8,
}
impl PredicateSummary {
pub fn empty() -> Self {
Self {
known_true: 0,
known_false: 0,
}
}
pub fn join(self, other: Self) -> Self {
Self {
known_true: self.known_true & other.known_true,
known_false: self.known_false & other.known_false,
}
}
pub fn has_contradiction(self) -> bool {
self.known_true & self.known_false != 0
}
pub fn is_empty(self) -> bool {
self.known_true == 0 && self.known_false == 0
}
}
pub fn predicate_kind_bit(kind: PredicateKind) -> Option<u8> {
match kind {
PredicateKind::NullCheck => Some(0),
PredicateKind::EmptyCheck => Some(1),
PredicateKind::ErrorCheck => Some(2),
_ => None,
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::state::symbol::SymbolId;
#[test]
fn small_bitset_basic() {
let mut bs = SmallBitSet::empty();
assert!(bs.is_empty());
bs.insert(SymbolId(0));
assert!(bs.contains(SymbolId(0)));
assert!(!bs.contains(SymbolId(1)));
assert!(!bs.is_empty());
}
#[test]
fn small_bitset_union_intersection() {
let mut a = SmallBitSet::empty();
a.insert(SymbolId(0));
a.insert(SymbolId(2));
let mut b = SmallBitSet::empty();
b.insert(SymbolId(1));
b.insert(SymbolId(2));
let u = a.union(b);
assert!(u.contains(SymbolId(0)));
assert!(u.contains(SymbolId(1)));
assert!(u.contains(SymbolId(2)));
let i = a.intersection(b);
assert!(!i.contains(SymbolId(0)));
assert!(!i.contains(SymbolId(1)));
assert!(i.contains(SymbolId(2)));
}
#[test]
fn predicate_contradiction() {
let s = PredicateSummary {
known_true: 1, known_false: 1, };
assert!(s.has_contradiction());
}
#[test]
fn predicate_no_contradiction() {
let s = PredicateSummary {
known_true: 1, known_false: 2, };
assert!(!s.has_contradiction());
}
#[test]
fn predicate_join_intersection() {
let a = PredicateSummary {
known_true: 0b011, known_false: 0,
};
let b = PredicateSummary {
known_true: 0b010, known_false: 0,
};
let joined = a.join(b);
assert_eq!(joined.known_true, 0b010); }
}