Skip to content

Research: SPDS field-stack reachability for ownership aliasing (bounded spike) #438

Open

Description

@PhysShell

Classification

Motivation and distinct question

SPDS (Späth, Ali, Bodden, POPL 2019) uses a call PDS to track call/return matching and a field PDS to track field-store/load matching. Each is a separate pushdown reachability problem; their synchronization provides context-, field-, and flow-sensitive may-flow information, without fixing field-access paths to a constant depth k.

This is interesting specifically for aliases of resources stored in nested and/or recursive heap structures (including resources transferred through wrapper objects across method boundaries). Existing ownership rules need to know whether a release, use, borrow, or escape applies to the same resource. But SPDS does not provide C# lifetime semantics or prove that Dispose() has happened: it supplies underlying flow/alias information that a separate ownership/typestate model can consume.

Important precision boundary: satisfying call-stack and field-stack reachability independently does not necessarily imply that both can be satisfied on the same concrete data-flow path. Exact interleaved two-stack reachability is undecidable in general. SPDS deliberately computes a sound over-approximation, and corner cases may yield spurious may-flow. Do not report a reachable graph path as an executable ownership witness or an unreachability result as safe without complete assumptions/model.

Incremental question, distinct from #429: Does unbounded-depth field-path matching (or the SPDS field-stack idea) improve a confirmed Own.NET diagnostic over the cheapest existing field/alias abstraction after the source→OwnIR fidelity and summary/model checks? Is that benefit obtainable with a small on-demand field-path experiment rather than a full synchronized-PDS engine?

If no verified field-depth-related discrepancy survives preliminary triage, stop early; #429 remains the broad alias-precision owner.

Scope / bounded research plan

0. Pin sources and adjudicate an actual gap

1. Write down the two-stack abstraction and its limits (no code first)

  • Model call PDS transitions (push call-site / pop return-site) and field PDS transitions (push/pop on field store/load) as conceptual analysis operations, not runtime C# stacks.
  • Contrast: current Own.NET resource identity, k-limited access paths if applicable, access graphs / field summaries, and SPDS field-stack reachability.
  • Specify a narrow query, e.g. “can release at site B may-alias the allocation/resource used at site A through next.value and wrapper calls?” Distinguish may-alias, must-alias, definitely disjoint, unknown.
  • Explain the two-path false-positive case: call-valid path differs from field-valid path. Create an adversarial negative control to ensure independent reachability is not promoted to a single realizable witness.
  • Detail heap abstractions, allocation sites, unknown receiver types, dynamic/virtual dispatch, recursion, ref/out, field overwrites, arrays, delegates, exception edges and incomplete calls. Mark unsupported features explicitly; no fabricated exactness.

2. Conditional micro-experiment only if the gap is real

Build one small, test-only on-demand query experiment over existing OwnIR/ICFG facts, preferring the cheapest counterfactual first:

  1. Existing Own.NET baseline.
  2. A bounded field-path / selective field-sensitive alternative; quantify where k loses or merges relevant resource identities.
  3. Only if (2) demonstrably fails for the eligible case, prototype field-stack reachability inspired by SPDS, with existing call-context facts and explicit over-approximation. No Java/JVM runtime dependency.
  4. Optional: test whether SparseBoomerang's type-aware vs alias-aware sparsification idea lowers exploration cost; do not promise its published speedups for Own.NET.

Reuse ~8–12 reviewed positive, negative, and adversarial C# fixtures, including:

  • definite alias vs separate instances of the same disposable type;
  • holder.child.resource, field overwrite, branch join, and aliased receiver;
  • recursive Node.Next chains at increasing depth (especially beyond any proposed k);
  • direct wrapper method vs two callers / mismatched return context;
  • guarded Dispose, use-after-dispose, double-release and transfer/escape;
  • a crossed call/field path that is accepted by both projections separately but has no jointly valid execution path;
  • a deliberately missing edge/model and forced analysis budget exhaustion;
  • an exceptional/virtual call case, only where faithfully lowered.

Independently adjudicate actual C# behavior; a compiler success or the prototype's verdict alone is not an oracle.

3. Correctness, budgets, and comparison

  • Separate may-flow reachability, possible violation, validated witness, bounded complete negative, UNKNOWN, INCOMPLETE, and UNSUPPORTED. Do not silently change public diagnostic statuses.
  • Never turn may-alias into must-alias, a failed search into PROVEN_SAFE, or crossed projections into a concrete witness. Keep existing confirmed positives under adverse budget/summary settings.
  • Compare per case: source/oracle, current Own.NET output, experimental output, first divergence, changed FP/FN, explanatory value, visited states, maximum field/context depth, time and memory (if measured).
  • Measure costs only on pinned inputs; include at least one real-OSS slice if an eligible gap exists. No synthetic pooled “precision” percentages from tiny curated sets.

Acceptance / stop gates

  • Version-pinned primary-source note: SPDS vs current Boomerang vs SparseBoomerang, and precise sound over-approximation boundary.
  • Explicit difference / overlap with Research: WALA-inspired demand-driven alias precision for ownership diagnostics (bounded spike) #429 and Research: Heros-inspired IFDS/IDE feasibility for interprocedural ownership facts (bounded spike) #434, and a source→OwnIR feasibility audit before proposing a solver.
  • One independently confirmed field-depth / field-sensitive ownership discrepancy, or documented STOP-NO-ELIGIBLE-GAP.
  • Reviewed source-level positive/negative/crossed-path corpus and baseline with exact commands and artifacts if the gap exists.
  • Conditional smallest-possible comparative experiment with deliberate missing-edge and truncation controls; unknown is never “safe”.
  • Per-case correctness and cost comparison; clear GO / NO-GO / RESEARCH ONLY ruling.
  • On GO only, create a separate narrowly scoped implementation issue with proven marginal benefit; otherwise close research with evidence.

Non-goals

No adoption of unmaintained CodeShield SPDS as a dependency, no Java/Soot/JVM integration, no port of Boomerang/IDEal/SparseBoomerang, no generic dual-PDS solver, no wholesale OwnIR / Python / Rust core rewrite, no new call graph framework, no default CI gate, no diagnostic promotion on graph reachability alone, no duplication of #429's broad alias work or #434's IFDS formulation.

Primary references

Decision criterion: demonstrate a real ownership correctness gain from deeper field-flow tracking, not just a more elaborate reachability engine.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions