Commit graph

151 commits

Author SHA1 Message Date
trvon
95aac8209c
feat: expand rust security scanner coverage 2026-05-27 11:32:05 -04:00
trvon
ce1c353847
feat: harden security scanner routing 2026-05-27 10:36:57 -04:00
trvon
da7e072028
perf(symbolic): model memcpy/memmove via z3::lambda (Z4)
Replaces the per-byte `store(store(...))` chain in modelMemcpyLikeCall
with a single `z3::lambda(i, ite(in_range, src_byte, orig_byte))`.
Drops the `!arg_values[2].is_numeral()` bail so symbolic copy_bytes
now reaches the solver instead of being silently skipped.

Concrete cap (kMaxModeledCopyBytes=4096) is kept to prevent
pathological bit-blast explosion on giant memcpy()s. strcpy is
unchanged -- literal bytes are short + concrete and the lambda
form doesn't help there.

z3 simplifies the lambda away at concrete-index selects so QF_BV
stays viable; no logic-change cascade. Full unit suite stays
57/57 green.
2026-05-26 08:47:20 -04:00
trvon
a791230552
feat(report): C9 FixIts + unified-diff --fix-output
Adds the FixIt collector + per-file unified-diff patch writer
behind a new `fold scan --fix-output <path>` flag. Patch-only --
no in-place rewrites -- so a bad suggestion can't silently
overwrite source.

Consumers (only when the transform is provably sound):
- UninitLocalRead: scalar integer locals only.
  `int x;` -> `int x = 0;`. Non-scalar types deferred.
- DeprecatedApi: regex extracts `[Uu]se foo()` from the
  deprecation message; silent skip when unparseable rather
  than hallucinating a rewrite.

Patches include 3 lines of context above + below each fix so
`git apply --check` accepts them. End-to-end verified against a
synthetic fixture.
2026-05-25 16:40:43 -04:00
trvon
48dac13d53
feat(detect): uninit-local-read detector (C5 wiring)
Graduates C5's UninitVariablesAnalysis wrapper from
measurement-only into a real detector. Emits a finding per read of
an uninitialised local in the TU's main-file functions.

Scope is calibrated (C5's wrong-hypothesis pivot): clang's analyzer
flags LOCAL read-before-write, NOT parameter nullability. Tests
pin this explicitly (`int p; return p; -> no finding`).

End-to-end on synthetic fixture: 3 expected findings (read of
uninit local, self-init `int x = x`, subsequent use of the
self-init). Parameter reads correctly skipped.

scan_runner.cpp dispatch is unstaged in this commit -- parallel
session has unrelated in-flight edits to that file. The detector
is registered and tested; scan-runner wiring lands in a follow-up.
2026-05-25 11:52:20 -04:00
trvon
d410bb7ba7
feat(fuzz): refine SAT models for smaller integer witnesses (Z5)
When a witness recorder is active, run z3::optimize.minimize on the
SAT model before extracting bytes for fuzz seeds. Refines integer
params toward the smallest path-and-hazard-satisfying value, so
seeds emit `arg=1` instead of `arg=0xDEADBEEF`.

Measured on synthetic access_at_offset(p, offset) with the path
`0 < offset && offset < 100`: primary-witness median 33 -> 5
(85% smaller). divide_by_count(p, count) with `count > 0` was
already path-minimal so no change.

Only the primary witness is refined; recordAlternateWitnesses
still uses the original model so the corpus covers the
equivalence class.

Curl-scale validation deferred -- fuzz-prep on full curl crashes
pre-existing (verified Z5-OFF baseline exit 139).
2026-05-25 11:22:38 -04:00
trvon
72bc61f2c4
Document library expansion audit results 2026-05-25 09:55:55 -04:00
trvon
c29a290be2
Reduce Curl high-signal false positives 2026-05-25 09:49:07 -04:00
trvon
07a39e73a7
perf(symbolic): compact serialised summaries via z3 let-bindings
Drop pp.min-alias-size from 10 (default) to 2 so shared subterms
collapse under `let` in serialize(). Measured 39.9% byte reduction
on encoder-shaped n=100 corpus (94.9KB -> 57.0KB). Roundtrip
preserved -- deserialize() parses let-form via z3's SMT-LIB reader.
2026-05-25 09:19:13 -04:00
trvon
1a7b6c1302
feat(detect): deprecated-api detector via clang::Decl::isDeprecated
New AST-only detector that flags call sites whose target decl is
marked deprecated under any of the three idioms:

- `[[deprecated]]` / `[[deprecated("why")]]` (C++14 attribute)
- `__attribute__((deprecated))` (GCC/Clang extension)
- `__attribute__((availability(...,deprecated=N.M)))` (Apple)

Per-call rather than per-decl so a migration that updates call
sites one at a time shows monotone progress. Deprecation reason
(when present) carries through into finding.message. System-header
call sites are skipped so the report stays scoped to the user's
own code.

Curl baseline: 52 real findings, e.g.
  ldap.c:269  ldap_url_parse — first deprecated in macOS 10.11
  multi-formadd.c:50  curl_formadd — since 7.56.0. Use curl_mime_init()

Refs docs/library-expansion-matrix.md row C7.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-25 00:47:38 -04:00
trvon
3c02c123f6
feat(symbolic): /*@ requires p != null */ contract seeding
Adds fold::symbolic::parseFunctionContracts(fd, ctx) — reads
RawCommentList for a function decl and returns the param indices
proven non-null by `/*@ requires <param> != null */` clauses.
SecurityWalker calls applyInitialFunctionContracts before walkCFG,
so within-function derefs see the contract via the existing
isDefinitelyNonNull pre-filter.

Grammar v1: bare `<ident> != null|NULL|nullptr`. Multi-line and
multi-clause supported. Unrecognised shapes are silently rejected
so future grammar growth doesn't break existing files.

applyHostToolchain now passes -fparse-all-comments. Without it
clang's lexer drops ordinary block comments before they reach the
AST, so the contract syntax can't ride along on `/*` ... `*/`.

Scope: suppresses within-function derefs on contracted params.
Does NOT suppress call-site findings — that needs CrossTUCache
integration so callee CalleeProperties carry the precondition.
Filed as a follow-up on matrix row C8.

Refs docs/library-expansion-matrix.md row C8.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-24 23:31:32 -04:00
trvon
84a3126c35
feat(symbolic): wrap clang::UninitVariablesAnalysis
Adds fold::symbolic::runUninitAnalysisOnTU(ctx) returning aggregate
counts of functions with local read-before-write uses, derived from
clang's UninitVariablesAnalysis. Scope reminder pinned by the 4
unit tests: this flags LOCAL variable uninit reads, NOT parameter
nullability. The original matrix C5 framing ("null-deref FP triage
pre-pass") was wrong-hypothesis — the analyzer treats parameters as
always-initialised, so it cannot drive null-deref triage.

CFG build options need AddInitializers + setAllAlwaysAdd before the
per-fn AnalysisDeclContext sees decl initializers; without that the
analyzer silently reports zero uses.

Scan-pipeline integration deferred — needs a per-TU accumulator
threaded through the priming consumer.

Refs docs/library-expansion-matrix.md row C5.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-24 23:02:39 -04:00
trvon
783d83cc45
Deduplicate null callsites and honor loop aliases 2026-05-24 20:02:53 -04:00
trvon
6c38999e60
Honor validated divisors and bounded snprintf 2026-05-24 19:55:43 -04:00
trvon
2c8263fc1c
Recognize bounded divisor and index patterns 2026-05-24 19:41:27 -04:00
trvon
b3d7791aed
Skip pointer arithmetic overflow summaries 2026-05-24 19:17:07 -04:00
trvon
473dcb8a79
Avoid UI helper arithmetic summaries 2026-05-24 18:48:37 -04:00
trvon
e3cd897aa9
Suppress bounded local counter overflow FPs 2026-05-24 18:30:38 -04:00
trvon
d9477545a0
Use promoted arithmetic widths 2026-05-24 18:18:11 -04:00
trvon
0a92540b63
Prove positive derived divisors 2026-05-24 13:03:45 -04:00
trvon
976b667e45
Improve Clang guard handling 2026-05-23 21:47:53 -04:00
trvon
9707b35872
Propagate positive divisor initializers 2026-05-23 21:23:17 -04:00
trvon
03d93c0830
Refine divisor guards with Clang AST patterns 2026-05-23 21:06:37 -04:00
trvon
106fc07fe7
Use AST guards for divisor precision 2026-05-23 20:50:13 -04:00
trvon
331a68467c
Optimize security detectors and add quality gates 2026-05-23 20:42:05 -04:00
trvon
8895d50015
fix(dead-statement): filter range-for + structured-binding FPs
Fold-on-fold pass surfaced 152 dead-statement findings against
fold's own source. Spot-checks revealed every flagged statement
was inside a range-for body. Minimal isolation fixture:

  for (const auto& [k, v] : src)
      dst[k] = v;            // flagged FP: "unreachable from entry"

Plain `for (int x : v)` does NOT trip the bug. The trigger is the
structured binding inside the range-for. Clang's CFG for that
shape leaves the body block without an incoming edge from the
loop's condition check, so the reachability walk in
DeadStatementVisitor marks every body statement unreachable.

Filter: walk up the parent map from the candidate anchor (capped
at 16 hops); if any ancestor is a CXXForRangeStmt, suppress the
finding. Narrow, behaviour-preserving for real dead code,
contained to the same defensive-filter block that already handles
macro-expanded anchors.

Result on fold's own 134-TU compile DB:
  before: 152 dead-statement findings
  after:   16  (90% reduction)

The remaining 16 likely have other root causes; future audit work.

Added regression test exercising the exact failing fixture; 5/5
test_dead_statement cases pass. Full 44/44 suite still green.

Note: this is itself a fold-on-fold success — the perf-audit's
fold-on-fold pass surfaced a detector bug that had been silently
shipping FPs on every C++ codebase with structured-binding range
loops.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-23 14:48:38 -04:00
trvon
da4c848cbc
feat(rust): MVP Rust frontend — unsafe-deref detection + clone clustering
First non-clang frontend for fold. Scans Rust source for the
subset of issues that meaningfully exist there: raw-pointer
dereferences in `unsafe` blocks (Heuristic confidence) and
within-Rust Type-1/2/3 clones via the existing clone detector.
Reuses the M30 frontend-agnostic IR + AnalysisBackend
abstraction unchanged.

Architecture: a separate `tools/fold-rust` cargo binary that the
C++ `RustBackend` shells out to. Two subprocess invocation
modes:

- `extract --unit <file>`: standalone .rs file, no Cargo
  context (limited; external-crate imports won't resolve).
- `cargo-check --crate-dir <dir>`: invokes `cargo check` with
  RUSTC_WORKSPACE_WRAPPER set to ourselves so cargo supplies
  the full --extern/-L/--cfg per-TU. Mirrors the
  clippy/miri/kani pattern.

RustBackend::discoverUnits walks up from each `.rs` input to
find the nearest Cargo.toml and collapses sibling files to one
crate unit; orphan files fall back to single-file extract.
scan_router auto-detects --mode=rust when all paths are `.rs`;
mixed Rust + C/C++ warns and defaults to source mode.

Includes:

- tools/fold-rust/: cargo crate pinned to nightly-2026-05-22.
  HIR-driven DerefHunter (raw-pointer dereference detection
  via typeck `is_raw_ptr()`) and HashWalker (FNV-1a + mix64
  port of src/ir/normalize.cpp for FunctionSummary hashes).
- include/fold/ir/expr_json.{hpp,cpp}: RustExprNode +
  RustNodeArena + bidirectional JSON wire format for
  ir::Expr; round-trip tested across 8 Kinds.
- include/fold/frontend/rust_backend.{hpp,cpp}: AnalysisBackend
  impl. posix_spawnp + NDJSON parser. Caches summaries +
  findings across extractFunctions calls; polymorphic
  runDetectorsOnShard dispatch routes summaries to
  detectClones.
- src/cli/{main,scan_router,scan_runner}.cpp: --mode=rust
  branch + autoDetectRust(). Mode validation extended to
  accept rust.
- docs/rust-frontend.md: scope, wire format, rustc-private
  pin + bump procedure, verification snippets.

44/44 unit + integration tests still green. Verified
end-to-end on a 3-function rename-pair fixture: 1 clone
cluster + 1 raw-deref finding through both `extract` and
`cargo-check` paths.

Out of scope (tracked separately): equiv + class-dup
detectors (need encoder frontend-agnostification),
dead-statement (needs Rust CFG), cross-language clones
(needs unified kind-tag taxonomy), Proved/ConcreteWitness
promotion (needs encoder integration), `cargo fuzz`
harnesses.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 22:36:28 -04:00
trvon
1fa0612f6e
feat(encoder): M28 phi-merge non-null facts in summary encoder
When both arms of an if-statement prove the same variable non-null
(via M22 null-check inference or M23 address-of marking), the
summary encoder's `mergeBindings` now intersects the two branches'
nonNullVars sets and marks the survivors in the post-if env.
Mirrors the same logic already present in
security_walker.cpp::walkIf so summary mode and the main walker
stay in parity.

Added tests/unit/test_summary_encoder_phi_nonnull.cpp covering
the rename-pair address-of case. Pre-fix the test FAILs; post-fix
PASSes. 44/44 still green.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-22 22:35:00 -04:00
trvon
43c2e4d825
feat(fuzz): S3 — libFuzzer dictionary mining
For every Z3 model fold proved SAT, the concrete byte values it
picked for integer parameters often *are* the magic constants the
path guards on. Promoting them to a libFuzzer dictionary lets the
mutator splice those bytes into nearby inputs that would otherwise
fail the same guard.

Per libFuzzer's docs (https://llvm.org/docs/LibFuzzer.html#dictionaries),
dictionaries are the single largest mutation-quality lever for
formats with magic bytes, fixed headers, or length-prefixed records.

* dict_miner.{hpp,cpp} — mineDictionary(witnesses) -> dict-format
  string. One entry per unique non-trivial (Integer|Bool) byte
  sequence. Filters trivial values (0/1/all-FF) since S2 boundary
  derivatives + libFuzzer's mutator already cover those. Encodes
  printable ASCII verbatim, \xNN for non-printable.
* fuzz_prep_runner — emits one .dict per function under
  <prep>/dictionaries/<safe>.dict.
* FuzzRunOptions.dict_path + runner.cpp — when set, appends
  -dict=<path> to the libFuzzer argv at launch.
* fuzz_run_runner — auto-detects <prep>/dictionaries/<safe>.dict
  per function and sets ropts.dict_path. No new CLI flag.
* tests/unit/test_dict_miner.cpp — 10 cases / 12 assertions
  covering dedup, trivial filtering, ASCII passthrough, escape
  correctness for \" and \\, pointer skip, header counts.

Smoke: leaky(int*, int) with `flag == 0xAB` guard. dict contains
"\xab\x00\x00\x00"; libFuzzer crashes in 0.7s (vs 1s without
dict — gain is modest on a 1-byte guard but the architecture is
in place for the multi-byte magic-value formats where libFuzzer's
own docs cite 5-50x speedups).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 16:19:11 -04:00
trvon
7e33dd5276
feat(fuzz): S2 — integer boundary-derivative seeds (0/1/-1/MAX/MIN)
For each integer parameter in a PathWitness, derive boundary
perturbations: 0, 1, -1 (signed only), INT_MAX, INT_MIN (signed).
Classical fuzzing literature shows these catch off-by-one and
overflow bugs that random mutation needs many iterations to reach.

Derivatives share the primary witness's finding_id (so Phase 2's
crash-ingest still correlates by id equality) but are NOT added to
findings.predicted.json — adding them would bloat the prediction
map without changing the correlation key. They land in the same
corpus dir alongside the witness-derived and canonical seeds.

Content-hash filenames in corpus_writer naturally collapse
identical perturbations (e.g. when the primary already has flag=0).

* boundary_seeds.{hpp,cpp} — pure function over PathWitness POD
* fuzz_prep_runner.cpp — emit derivatives after each primary seed
* tests/unit/test_boundary_seeds.cpp — 7 cases / 39 assertions
  covering 32-bit signed (5), 32-bit unsigned (3), 8-bit signed,
  pointer skip, 2-param independence, bool (2), partial flag.

Smoke: leaky(int*, int) fixture grows from 4 seeds (1 witness +
3 canonical) to 9 seeds (1 witness + 5 boundaries + 3 canonical).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 16:03:10 -04:00
trvon
93eb1f09b2
feat(fuzz): M31 Phase 2 — closed-loop fuzz-run promotes to ConcreteWitness
End-to-end: fold scan → fuzz-prep emits Z3-derived seed → fuzz-run
compiles + libFuzzer + ASan → crash ingested → predicted Finding
promoted from Proved to ConcreteWitness in ~1s wall-clock.

P2.1 — Confidence::ConcreteWitness tier
* Strictly stronger than Proved: SMT-feasibility + observed runtime
  failure. confidenceRank() gives explicit numeric ordering so the
  enum integer values stay incidental.
* FindingKind::FuzzCrash for surprise crashes the SymEx side didn't
  predict.
* FuzzWitness evidence sub-struct (seed_path, asan_kind, asan_file,
  asan_line) + JSON round-trip.

P2.2 — ASan stderr parser
* include/fold/fuzz/asan_parser.{hpp,cpp} (~150 LOC)
* Parses the canonical SUMMARY tail line — stable across LLVM 15–22
  for both ASan (heap-buffer-overflow, SEGV, …) and UBSan
  (signed-integer-overflow, …)
* test_asan_parser.cpp: 6 cases / 27 assertions

P2.3 — FuzzRunner
* include/fold/fuzz/runner.{hpp,cpp}
* Synchronous: compile + posix_spawn + waitpid-with-deadline +
  artifact-scan. SIGTERM + 1s grace + SIGKILL on parent timeout.
* Per-source `-x c` / `-x c++` pinning so C targets keep their
  C linkage and the harness's extern "C" decl resolves.
* Drops -std= entirely — generated harnesses are pre-C++17.

P2.4 + P2.5 — fuzz-run CLI + crash ingestion
* src/cli/fuzz_run_runner.cpp: load findings.predicted.json, group
  by function, runFuzzCampaign per harness, replay each crash under
  ASan, parse SUMMARY, match (file, line) to predicted Finding.id.
* Matched crashes → augmented Finding with Confidence::ConcreteWitness
  + evidence.fuzz_witness. Unmatched → FindingKind::FuzzCrash.
* Subcommand: --prep-dir, --target-source (rep), --time-budget,
  --compiler, --report, --clang-flag.

P2.6 — integration test
* tests/integration/test_fuzz_run.cpp: probes for a clang++ that can
  link -fsanitize=fuzzer, builds the null-deref-behind-guard fixture,
  chains runFuzzPrep + runFuzzRun, asserts at least one
  concrete-witness Finding whose id matches a predicted Finding.id.
* WARN+SUCCEED when no libFuzzer-capable compiler is found so CI
  on stripped clang installs stays green.

Tests: 39 → 40 green.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 15:21:05 -04:00
trvon
075dd85669
feat(fuzz): R3-oob + P1.7 — full witness coverage + e2e test
R3-oob: oob_access now hoists z3::model out of both solver branches
and passes it to recordSinkWitnessWithModel. Predicted seeds for
`int buf[N]; return buf[idx];` now contain Z3's chosen boundary-
violating idx (e.g. `04 00 00 00` for buf[4]) instead of zeros.

P1.7: tests/integration/test_fuzz_prep.cpp materializes a
null-deref-behind-`flag==0xAB`-guard fixture, drives runFuzzPrep
in-process, and asserts the witness seed contains the exact magic
byte (0xAB at offset 0) plus a well-formed harness (extern "C",
size-gate at total_bytes, leaky(arg0, arg1) call).

Moves fuzz_prep_runner.cpp from the fold executable target into
fold_core_sources so the integration test can link runFuzzPrep
directly.

Tests: 37 → 38 green.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 14:39:17 -04:00
trvon
470ed6f8b4
feat(fuzz): M31 — fuzz-prep emits Z3-derived harnesses + corpora
Build the static-analysis-driven fuzzing pipeline alongside the radare2
+ z3 work. fold's symbolic engine already proves sink feasibility; this
adds the path that retains the Z3 model, lowers it to libFuzzer
harnesses + seed corpora, and writes a findings.predicted.json bridge
so a future fold fuzz-run can promote crashes to ConcreteWitness
confidence.

* fold::fuzz value types (PathWitness, ParamWitness) + WitnessRecorder
  collector — process-local, lock-free hot-path check
* model_to_bytes — z3::model → little-endian std::byte at source width;
  pointer null-vs-nullable disambiguation
* harness_emitter — generates .harness.cc + .schema.json; honors
  is_c_linkage via `extern "C"` wrapper for C targets; nested-namespace
  emission for C++
* corpus_writer — packs witness bytes per harness layout, FNV-1a hash
  for filename, 3 canonical seeds (zeros / 0xFF / single byte)
* param_schema — schemaForFunction + recordSinkWitness +
  recordSinkWitnessWithModel; latter looks up each parameter's z3::expr
  via env->tryGet() and mines the model for byte payloads
* SafetyObserver: const SymbolicEnv* env added to onPointerDeref,
  onDivision, onTruncation, onSignedUnsignedConversion,
  onArraySubscript; encoder.cpp passes &env at every call site;
  CompositeSafetyObserver in scan_runner fans through
* null_deref, div_by_zero, int_overflow, int_truncation,
  sign_conversion now record witnesses with full model bytes;
  oob_access records schema-only (sat sites don't capture a model yet)
* fold fuzz-prep subcommand — runs scan in-process (workers can't
  ship recorder state), drains the recorder, emits one
  {harness,schema,corpus/} bundle per function

Smoke validation: 4 detectors on a 5-line C fixture produce
non-partial witnesses whose bytes are the exact magic values that
trigger each sink (flag=0xAB for null-deref; x=0 for div-by-zero;
a+b that overflows INT_MIN for int-overflow).

Tests: 34 → 37 (add test_model_to_bytes, test_harness_emitter,
test_corpus_writer). All green.

Also folds in a small worker-toolchain optimization that had been
sitting in the working tree: preloadHostToolchainEnv() avoids
repeated popen calls during worker init.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-21 14:21:43 -04:00
trvon
a51cdf5748
M19–M30 + scout-rule encoder refactor
Multi-phase work merged into one commit:

* M19: flow-sensitive guard tracking (stmtAlwaysExits, walkIf early-exit)
* M20–M27: non-null marking across deref, addr-of, callsite preconds,
  if/while/switch guards, AddrOf-of-subexpr, CFG-block-scoped maps
* M30 Phase A: dialect-agnostic SourceLoc + LocationMapper + frontend/
  boundary marker; ClangLocationMapper wired through SafetyObserver
* M30 Phase B v2: QueryTracer + 13 SafetyObserver hooks migrated to
  ir::Expr / ir::Call / ir::MemberRef / ir::Symbol / ir::SourceLoc
* M30 Phase C/D/D2/D3: ir::Symbol, ir::Expr (with Kind), ir::Call,
  ir::MemberRef opaque types; ir_expr_clang.cpp houses the clang
  adapters; encodeExpr migrated to switch(kind) dispatch

Scout-rule extractions from encoder.cpp (2800 → 2371 lines):
* encoder_callee_predicates.{hpp,cpp} — isMallocLikeCall, isFreeCall,
  isAssertCall as pure std::string_view predicates
* encoder_type_queries.{hpp,cpp} — typeSizeBytes, sourceWidth,
  isUnsignedLike, byteWidthExpr
* encoder_callee_names.{hpp,cpp} — calleeName, qualifiedFunctionName,
  qualifiedCalleeName (with internal-linkage @-suffix)
* encoder_coerce.{hpp,cpp} — coerceToBv, coerceToExactBv, coerceToBool,
  coerceToType (BV-64 storage model documented at the boundary)
* encoder_reachability.{hpp,cpp} — ReachabilityCounter impl, markEncoded,
  recordEncoded, recordBailedNode, public profiling glue
* encoder_summary_instantiate.cpp — SMT-LIB summary substitution
  (instantiateSummaryExpr / Predicate / PredicateInContext +
  applySummaryParamPost; kills the redundant *Impl pass-through layer)
2026-05-21 11:17:50 -04:00
trvon
c4e42cec0a
Add scan router and MCP job queue
Split source and binary scan routing with merge-only hybrid support, binary provenance, and router-backed MCP scan contexts.

Add async MCP scan jobs for long-running scans, detector precision fixes, benchmark scripts, docs, and integration coverage.
2026-05-19 00:24:12 -04:00
trvon
43634705fc
Phase 6b: Transitive summary composition through call chains
24/24 tests, all CWEs stable
2026-05-16 14:35:08 -04:00
trvon
7adddcfec2
Phase 5d: Heap/Object Disambiguation + symbolic extents
CWE-121: 13.9% -> 44.8% (+1,623 TP)
Total TP: 4457 -> 6062 (+36%)
2026-05-16 09:45:12 -04:00
trvon
79fe06a316
Phase 5b: Sparse numeric AI sidecar — loop widening
CWE-190/369 stable, 23/24 tests pass
2026-05-16 09:19:17 -04:00
trvon
fba6861fd0
Remove broken abort() assume test (feature not implemented)
cross_tu_equiv hang is pre-existing (Phase 3 regression)
2026-05-15 23:09:21 -04:00
trvon
6edb31c3b8
Phase 4b+4d+4e: octagon domain, array memcpy/strcpy, heap arrays 2026-05-15 23:04:44 -04:00
trvon
6096972823
Phase 4a: Increase loop unroll k=3 -> k=5 2026-05-15 21:59:20 -04:00
trvon
564ed13e6c
Phase 3: Compositional Symbolic Summaries 2026-05-15 21:15:17 -04:00
trvon
a56d5dac2b
Phase 1: Clang CFG traversal layer + test coverage 2026-05-15 19:17:01 -04:00
trvon
0452353d2e
Implement walkSwitch: analyze case bodies in switch statements
Results: +86 TP across all CWEs (476:+3, 369:+18, 190:+51, 121:+14)
2026-05-15 18:32:45 -04:00
trvon
879f60f52d
Add alloca/_alloca as known allocation function 2026-05-15 17:34:37 -04:00
trvon
ddedb77a9f
Add strcpy/sprintf buffer overflow detection 2026-05-15 16:13:26 -04:00
trvon
66cda72701
Fix BufferSizeTracker: pointer-to-buffer alias tracking 2026-05-15 15:28:03 -04:00
trvon
7b28ebb31d
P0+P1: model ++/-- in encoder, symbolic array OOB 2026-05-15 15:00:54 -04:00
trvon
b73abea520
Optimize int-overflow: unsigned-skip, interval filter, range tracking
CWE-190 benchmark:
  Queries:   9045 -> 4385 (-52%)
  Z3 time:   164s -> 0.2s (-820x)
  Wall time: 457.8s -> 400.5s (-12.5%)
  TP:        1208 -> 1271 (+63)
2026-05-15 13:49:16 -04:00
trvon
f218af3d8b
Add githooks, clang-format all code, fix CI Z3 paths 2026-05-15 00:08:47 -04:00