new capacity bits (#67)

This commit is contained in:
Eli Peter 2026-05-07 01:29:31 -04:00 committed by GitHub
parent afaffc0df6
commit 7d0e7320e2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
261 changed files with 10591 additions and 231 deletions

View file

@ -113,22 +113,22 @@ impl ConstValue {
// ── TypeSet ─────────────────────────────────────────────────────────────
/// Bitset over [`TypeKind`] variants (12 bits used of u16).
/// Bitset over [`TypeKind`] variants (19 bits used of u32).
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct TypeSet(u16);
pub struct TypeSet(u32);
impl TypeSet {
/// All 12 type bits set, no type constraint (Top).
pub const TOP: Self = Self(0x0FFF);
/// All 19 type bits set, no type constraint (Top).
pub const TOP: Self = Self(0x0007_FFFF);
/// No type bits, unsatisfiable (Bottom).
pub const BOTTOM: Self = Self(0);
pub fn singleton(kind: &TypeKind) -> Self {
Self(1u16 << type_kind_index(kind))
Self(1u32 << type_kind_index(kind))
}
pub fn contains(&self, kind: &TypeKind) -> bool {
self.0 & (1u16 << type_kind_index(kind)) != 0
self.0 & (1u32 << type_kind_index(kind)) != 0
}
/// Meet (intersection): refine type knowledge.
@ -156,7 +156,7 @@ impl TypeSet {
/// Check if this set contains exactly one type matching the given kind.
pub fn is_singleton_of(&self, kind: &TypeKind) -> bool {
self.0 != 0 && self.0 == (1u16 << type_kind_index(kind))
self.0 != 0 && self.0 == (1u32 << type_kind_index(kind))
}
/// Return the TypeKind if this is a singleton set (exactly one type).
@ -186,12 +186,21 @@ fn type_kind_index(kind: &TypeKind) -> u32 {
TypeKind::LocalCollection => 12,
TypeKind::RequestBuilder => 13,
TypeKind::JpaCriteriaQuery => 14,
TypeKind::LdapClient => 15,
TypeKind::XPathClient => 16,
TypeKind::XmlParser => 17,
TypeKind::Template => 18,
// the analysis DTO types carry per-field structural info that the
// bitset domain can't represent. Collapse to Unknown so callers
// still see "any type possible" rather than crashing on an
// unhandled variant. Same-file/cross-file Dto-aware paths read
// the structured TypeKind directly, not via this index.
TypeKind::Dto(_) => 6,
// NullPrototypeObject is a JS-only sub-kind of Object used for
// flow-sensitive prototype-pollution suppression. The bitset
// domain has no dedicated slot, share the Object index so
// singleton recovery still maps to a meaningful TypeKind.
TypeKind::NullPrototypeObject => 3,
}
}
@ -212,6 +221,10 @@ fn type_kind_from_index(idx: u32) -> Option<TypeKind> {
12 => Some(TypeKind::LocalCollection),
13 => Some(TypeKind::RequestBuilder),
14 => Some(TypeKind::JpaCriteriaQuery),
15 => Some(TypeKind::LdapClient),
16 => Some(TypeKind::XPathClient),
17 => Some(TypeKind::XmlParser),
18 => Some(TypeKind::Template),
_ => None,
}
}
@ -801,7 +814,7 @@ pub struct PathEnv {
/// Per-key meet count for widening decisions.
meet_counts: SmallVec<[(SsaValue, u8); 8]>,
/// Refinement counter (bounded per block).
refine_count: u16,
refine_count: u32,
}
impl PathEnv {
@ -837,7 +850,7 @@ impl PathEnv {
if self.unsat {
return;
}
if self.refine_count >= MAX_REFINE_PER_BLOCK as u16 {
if self.refine_count >= MAX_REFINE_PER_BLOCK as u32 {
return; // bounded
}
let canonical = self.uf.find_immutable(v);
@ -860,7 +873,7 @@ impl PathEnv {
// but `refine_single` is also invoked directly from `assume_eq`,
// `assume_neq`, and a few internal sites. Large generated inputs
// (thousands of short statements on one line) can drive millions
// of calls and overflow a plain u16 `refine_count`. Saturate to
// of calls and overflow a plain u32 `refine_count`. Saturate to
// stay within bounds, the refinement pipeline is already
// idempotent past the cap, so saturation is semantically a no-op.
self.refine_count = self.refine_count.saturating_add(1);

View file

@ -250,6 +250,31 @@ pub fn class_name_to_type_kind(name: &str) -> Option<TypeKind> {
// Java I/O supertypes (enables hierarchy fallback for subtypes)
| "InputStream" | "OutputStream" | "Reader" | "Writer" | "PrintWriter"
| "BufferedInputStream" | "BufferedOutputStream" => Some(TypeKind::FileHandle),
// JNDI / Spring LDAP directory-service types. Field- and method-typed
// declarations (`DirContext ctx = ...`, `LdapTemplate ldapTemplate;`)
// attach this fact to the receiver SSA value so type-qualified
// resolution rewrites `ctx.search(...)` → `LdapClient.search`.
"DirContext" | "LdapContext" | "InitialDirContext" | "InitialLdapContext"
| "LdapTemplate" => Some(TypeKind::LdapClient),
// JAXP XML parser instances. Field/local declarations like
// `DocumentBuilder builder = factory.newDocumentBuilder();` route
// through this map so the receiver SSA value carries
// `TypeKind::XmlParser` and the type-qualified
// `XmlParser.parse` rule fires on `builder.parse(...)`.
"DocumentBuilder" | "SAXParser" | "XMLReader" | "SAXBuilder" => {
Some(TypeKind::XmlParser)
}
// JAXP XPath instances. `XPath xpath = factory.newXPath();`
// routes through this map so the receiver carries
// `TypeKind::XPathClient`, enabling the type-qualified
// `XPathClient.evaluate` resolution and the resolver-binding
// suppression sidecar.
"XPath" | "XPathExpression" => Some(TypeKind::XPathClient),
// Apache FreeMarker `Template` declared receiver type. Routes
// `Template tpl = ...; tpl.process(model, out)` through
// type-qualified resolution to `Template.process`, the SSTI
// sink defined in `labels/java.rs`.
"Template" => Some(TypeKind::Template),
// Python qualified type names.
// Only covers raw lowered names from isinstance(). The lowering in lower.rs
// extracts the literal type text: isinstance(x, requests.Session) produces