Commit graph

372 commits

Author SHA1 Message Date
trvon
a598e9dd96
docs: Facebook Infer gap matrix — ~30 checkers vs fold 10 detectors
- Concurrency: 7 Infer checkers, 0 in fold — biggest gap
- C++ lifetime: 4 Infer, 0 fold (dangling refs, ownership)
- Resource mgmt: file/socket leak missing from fold's memory-leak
- Performance: vector reallocation, loop invariants
2026-05-29 10:06:12 -04:00
trvon
5d81aa5b98
docs: CodeQL C/C++ gap matrix — ~200 queries vs fold 29 detectors
- Memory safety: 7/30 covered (7 new detectors added this session)
- Injection/taint: 1/25 covered — high-impact gap
- Phase 1: 8 syntactic detectors (deprecated APIs, format strings, weak crypto)
- Phase 2: 5 Z3-powered (path/command/SQL injection, tainted format, process)
- What fold does better: Z3-proved findings, semantic equivalence, binary scanning
2026-05-29 10:04:26 -04:00
trvon
27bb4d807f
docs: code quality detector opportunities — API misuse, exception safety, concurrency, deprecated APIs
- 12 detector ideas across 4 categories
- Phase 1 (S effort): deprecated APIs, throwing dtors, missing noexcept
- Phase 2 (M-L): use-after-move, iterator invalidation, lock inversion
- All phase 1 detectors are syntactic (RecursiveASTVisitor, no Z3 needed)
2026-05-29 10:03:25 -04:00
trvon
d2755e4d79
build: update nightly toolchain pin to 2026-05-28 (rustc 1.98.0)
- fold-rust builds with nightly rustc_private feature
- cargo-check now requires RUSTUP_TOOLCHAIN=nightly for target crates
- Ripgrep scan: 49 findings (42 path-traversal, 7 command-injection)
  with --suppress-local-paths taint filtering enabled
2026-05-29 09:48:22 -04:00
trvon
156dfa4642
build: add -march=native for ARM64 NEON / CPU-specific optimization
- Enables NEON SIMD on Apple Silicon, AVX on x86_64
- Speeds up Z3 queries, AST walking, and encoding
- ccache available: export CC='ccache clang' CXX='ccache clang++'
2026-05-28 21:12:41 -04:00
trvon
cb600dbac9
feat: IR language discriminator + Clang node kinds (Phase 3, multi-language IR)
- Language enum: Unknown, Rust, Cpp, Swift on RustExprNode
- 4 new Clang node kinds: ThrowExpr, CXXConstructExpr, LambdaExpr, StmtExpr
- Updated json_keys namespace with new constants
- 42 roundtrip test assertions pass
- All 3 frontends now share the same IR representation
2026-05-28 20:55:54 -04:00
trvon
5d8b288719
feat: Rust interprocedural symbolic summary caching (Phase 2, Rust-CLang parity)
- symbolic_summary.rs: MIR-based summary computation per function
- Produces SymbolicSummaryData with SMT-LIB BV-64 expressions
- Matches C++ fold::symbolic::SymbolicSummary wire format
- Cross-function Z3 proofs now possible
2026-05-28 20:41:29 -04:00
trvon
192387b406
feat: wire MIR control flow into Rust Z3 encoder (Phase 2, Rust-CLang parity)
- MIR-to-IR tree converter: 12 functions walk MIR basic blocks
- Each block becomes Call(mir_block) with statements + terminator
- SwitchInt terminators → path predicate forking per case
- Return/Rvalue encoding threaded through RustExprNode JSON
- Brings Rust CFG precision to parity with Clang security walker
2026-05-28 20:40:12 -04:00
trvon
2f3a8c037f
feat: path predicate tracking in Rust Z3 encoder (Phase 1, Rust-CLang parity)
- Fork path for &&/|| (LAnd/LOr) like Clang encoder H1 fix
- Fork path for Conditional nodes (true/false arms)
- Thread path through recursive encodeRustNode calls
- Eliminates false null-deref on guarded derefs in Rust code
2026-05-28 20:16:39 -04:00
trvon
10b9b81ef9
feat: known-safe path prefix recognition for Rust detectors
- KnownSafePaths set: codex_home, config_path, cargo_bin, cache dirs
- classify_origin returns LiteralValue for calls to known-safe functions
- Eliminates ~200 path-traversal FPs from config/cache file reading
2026-05-28 20:09:36 -04:00
trvon
04642c46af
docs: rustc internals research for HIR/MIR analysis in fold-rust
- rustc_driver Callbacks, TyCtxt, HIR ExprKind, MIR BasicBlock/Rvalue
- TyKind type system: bit-width queries via LayoutS
- Borrow checker: BorrowKind, loan scopes, BorrowTracker usage
2026-05-28 20:09:14 -04:00
trvon
585ae4e4ab
docs: clang API research, multi-language IR patterns, Rust-Clang parity gap analysis
- clang-analysis-api-research.md: AST nodes, CFG, type system, constant folding
- multi-language-ir-patterns.md: CodeQL shared engine, Infer SIL, Kani MIR→Goto-C
- rust-clang-scanning-parity.md: 9-component comparison table, 8 priority fixes
2026-05-28 20:08:38 -04:00
trvon
cabd242faa
fix: uninit-read — skip exception variables (isExceptionVariable check)
- catch (const X& e) initializes e at catch site
- Eliminates ~15 FP findings across the codebase
- Remaining FPs: value-init (= {}), struct arrays, branch patterns
2026-05-28 17:27:23 -04:00
trvon
4d85fbccff
fix: uninit-read — skip declarations with initializers (hasInit check)
- 32 FPs on own source: const auto* vd = dyn_cast<T>(expr) pattern
- vd->hasInit() returns true for declarations with initializers
- Reduces self-scan FPs from 32 to 0
2026-05-28 17:19:02 -04:00
trvon
f63fb06862
chore: fix clang warnings — missing switch cases + unused function
- ai_pre_pass.cpp: add OptionalBind/ProtocolWitness/ExistentialContainer/
  SwitchEnum/Conditional cases to both node->kind switches
- r2_backend.cpp: r2CmdQuote used at line 137, clang false positive
  — kept with static keyword
2026-05-28 17:09:22 -04:00
trvon
b1fe2bddec
feat: Phase 3 Z3 detector — memory-leak via HeapModel path tracking
- Z3 query: exists path from alloc to function exit where freed=false?
- Fork/merge walker per allocation site, tracks freed flag on all paths
- Reports leaked allocations with confidence=proved
- 7/7 Z3 detectors complete, 119 build targets
2026-05-28 17:02:59 -04:00
trvon
33134a189d
feat: Phase 2 Z3 detectors — use-after-free, double-free, redundant-store
- use_after_free: SafetyObserver hooks + HeapModel freed-flag queries
- double_free: HeapModel region tracking — freed=true on path to free-site
- redundant_store: variable write-before-read analysis
- All wired into ShardFrontend, FindingKind, CLI --detectors
- 118 build targets pass
2026-05-28 16:35:48 -04:00
trvon
5b88ed3344
feat: Phase 1 Z3 detectors — always-condition, uninit-read, unreachable-code
- always_condition: Z3 proves branch tautologies/contradictions
- uninit_read: Z3 detects variable reads before writes on any path
- unreachable: Z3 proves code after return/throw is unreachable
- All 3 wired into ShardFrontend, FindingKind, CLI --detectors
2026-05-28 16:05:34 -04:00
trvon
3beaef2958
build: fold-rust now build_by_default + install via custom_target
- Replaced run_target with custom_target (build_by_default: true)
- Single ninja builds all 3: fold + fold-rust + fold-swift
- meson install copies all 3 to prefix/bin automatically
- No more separate ninja fold-rust step needed
2026-05-28 13:03:02 -04:00
trvon
74b10224b1
fix: filter ts_rs codegen from path-traversal (eliminates 45% FPs)
- Skip path-traversal in ts_rs/__inline functions (compile-time codegen)
- TS::inline serializes types to .ts files — not runtime path handling
- Expected: ~500/1102 findings eliminated
2026-05-28 12:48:22 -04:00
trvon
ee49900f01
fix: filter augment_args from command-injection (eliminates 69% FPs)
- Add current_fn_name tracking in DerefHunter HIR visitor
- Skip command-injection when inside augment_args* functions
- clap derive macros are CLI registration, not command execution
- Expected: 150/217 findings eliminated
2026-05-28 12:47:19 -04:00
trvon
b79f964a59
feat: intra-procedural taint origin tracking for Rust detectors
- TaintOrigin enum: LiteralValue, EnvironmentSource, FileSource, UnknownProvenance
- classify_origin(): walks HIR to classify expression provenance
- Path-traversal: skip when path arg is LiteralValue (string literal, const)
- Command-injection: skip when .arg()/.args() arg is LiteralValue
- Expected: 80%+ FP reduction — most code uses fixed paths and commands
2026-05-28 12:20:07 -04:00
trvon
7f024fe607
refactor: expose CompositeSafetyObserver::observers() for testability 2026-05-28 10:50:36 -04:00
trvon
ffaa70573a
chore: add self-scan suppressions file + dogfood results
- 237 findings: 230 clones (97% macro-generated), 7 security (all FP)
- composite_observer.hpp: #1 clone source (intentional macro forwarding)
- Security findings all confirmed FP: guarded argv, conditional comp
- Suppressions file: .fold-suppressions for reproducible clean scans
2026-05-28 10:49:02 -04:00
trvon
20e74df72b
feat: C++ vtable fuzzing — discoverVtableTargets + vtable-dispatch harnesses
- Parse _ZTV symbols from isj, demangle class names
- VtableSlot/VtableInfo structs for structured vtable metadata
- emitVtableHarness: construct mock object, dispatch through slots
- --fuzz-vtables flag gates vtable discovery
2026-05-28 10:44:33 -04:00
trvon
f45bce34ac
fix: objc_msgSend — lang filter + _OBJC_CLASS_ verification + Swift IR kinds + vtable fuzzing
- discoverObjcClasses: filter icj to lang='objc', verify _OBJC_CLASS_ symbol exists
- Add 4 Swift IR node kinds: OptionalBind, ProtocolWitness, ExistentialContainer, SwitchEnum
- Vtable fuzzing: parse _ZTV symbols, emit vtable-dispatch harnesses
- Clone scoring: --clone-min-score gate with hash-distance metric
- BorrowTracker wired into Rust null-deref findings
2026-05-28 10:36:25 -04:00
trvon
18ce5a6050
docs: Swift/C++ ABI, fuzzing, IR, MIR research for multi-language pipeline
- Swift ABI: tagged pointers, garbage-input abort path, ObjC bridging
- C++ fuzz: libFuzzer dlopen coverage limits, AFL++ QEMU mode, vtable seeding
- Cross-language IR: CodeQL/Infer/Joern patterns, Swift SIL gaps in fold IR
- MIR verification: Kani/Prusti/Creusot approaches, BorrowTracker wiring
2026-05-28 10:28:41 -04:00
trvon
d2408405d3
feat: objc_msgSend harness wiring in fuzz-prep for Swift binaries
- R2Backend::discoverObjcClasses() queries icj for class+method list
- fuzz-prep generates objc_msgSend harnesses for each ObjC method
- Real instance pointer replaces fuzzer garbage as self/slot0
- 4 harnesses generated for FuzzMeClass: add, isEven, tokenize, init
2026-05-28 09:19:16 -04:00
trvon
3ca6e0c176
feat: ObjC msgSend harness generator + Swift test fixture
- emitObjcHarness: objc_getClass + sel_registerName + objc_msgSend
  routes fuzzer bytes through ObjC dispatch instead of raw dlopen
- Swift fixture (tests/fixtures/swift/): 4 C-ABI functions,
  1 ObjC-exposed class with 3 methods, Swift-mangled symbols
- isSwiftMangled filter skips symbols needing object references
- Budget floor 30→120s, ceiling 120→600s (AFL++/libFuzzer norms)
2026-05-28 09:14:15 -04:00
trvon
6f07fa25cc
fix: filter Swift symbols from binary fuzz + bump budget to 120-600s
- Swift-mangled symbols (//_T0) skipped: need valid objects, not raw uint64_t
- Cov:2 dead end explained: garbage args cause Swift runtime abort before real code
- Fuzz budget floor raised 30→120s, ceiling 120→600s (match AFL++/libFuzzer norms)
- Base per-CPU allocation doubled 45→90s
2026-05-28 09:08:32 -04:00
trvon
d22dff4aa2
feat: return value checking with ASan shadow sentinel
- --check-returns flag for emitBinaryHarness
- Pointer-returning functions get ASan shadow check via
  __asan_region_is_poisoned after call
- Volatile guard prevents compiler from eliding the call
2026-05-27 23:18:48 -04:00
trvon
e61821e5b7
feat: return-checking harnesses + Rust unsafe-audit command
- --check-returns flag adds ASan sentinel for pointer-returning functions
- unsafe-audit subcommand: detects SAFETY comment gaps in unsafe blocks
- fold-rust: null-deref adt-safety filter for Option/Result/Vec paths
2026-05-27 23:12:43 -04:00
trvon
ee3392931c
feat: param type inference + internal fuzz targets for binary harnesses
- --binary-param-types: uint64 (default) or infer (map r2 types)
- mapR2Type: converts afij type strings → C types with sized memcpy
- discoverInternalFuzzTargets: ObjC methods + Swift witnesses + vtable
- --fuzz-internal flag gates internal function fuzzing
2026-05-27 22:59:13 -04:00
trvon
93439bff4c
fix: Rust IR encoder — signedness threading + Member handling
- Wire node->int_signed through onBinaryArith/onDivision instead of hard-coded true
- Use signed comparisons (<, <=, >, >=) when int_signed is true, unsigned otherwise
- Add Member case: encode base, fire onPointerDerefIr
- Addresses H3 from encoder audit (Rust precision loss)
2026-05-27 22:38:12 -04:00
trvon
faeca6bf6d
fix: fork path predicate for &&/|| short-circuit (H1, FP-class-D)
- BO_LAnd/BO_LOr now fork path predicate like ConditionalOperator
- RHS encoded in forked env: path && LHS (LAnd) or path && !LHS (LOr)
- Eliminates false null-deref on guarded patterns:
  if (p && p->field) — 30-40% of null-deref FPs
- Removes TODO(fp-class-D) comment
2026-05-27 22:30:48 -04:00
trvon
811aab5254
docs: Z3 symbolic encoder robustness audit (31 files, 7 fixes ranked by ROI)
- H1: &&/|| short-circuit not forked → 30-40% null-deref FP reduction
- H3: Rust IR incomplete (Member, Conditional, signedness, path)
- 7 recommended fixes ordered by effort/impact
- Precision gaps mapped per detector family
2026-05-27 21:15:38 -04:00
trvon
b9381a6ab3
feat: adaptive fuzz budget + corpus seeding for binary harnesses
- HW detect: sysconf CPU/memory → compute per-harness budget (30-120s)
- --per-harness-timeout-seconds flag for override
- 3-5 seed files per harness: zeros, sentinels, ASCII patterns
- --corpus-seeds N flag to control seed count
2026-05-27 21:04:00 -04:00
trvon
1ee5fe06ed
feat: add --extra-arg flag for vendored-header workarounds
- ScanOptions::extra_args vector passed to ClangTool as
  ArgumentsAdjuster (END position)
- scan subcommand exposes --extra-arg (repeatable)
- Usage: fold scan --extra-arg -D_GLIBCXX_NO_INHERITED_CLANG ...
  to work around glaze/std::unexpected inherited-ctor incompatibility
2026-05-27 20:42:18 -04:00
trvon
642d2a012e
fix: ABI default params=3, SARIF kind field, size guard for zero-param
- inferParamCountARM64 returns 3 when disasm fails (was 0)
- Debug logs show symbol name, address, detected param count
- SARIF result.kind set to 'fail' per spec
- size < paramCount*8 only emitted when paramCount > 0
2026-05-27 20:09:20 -04:00
trvon
fb57ab0e2b
fix: ABI inference debug, binary --target-source skip, dlopen -ldl
- ABI inference now runs for isj-fallback exported functions
- Debug logging added to track param_count per function
- Binary fuzz-run skips --target-source requirement
- Runner adds -ldl for dlopen harnesses
2026-05-27 19:43:03 -04:00
trvon
a36801cf8e
perf: Z3 LRU cache, batch observers, fold-rust body cache, ripgrep benchmark
- Z3 query LRU cache (4096 entries, O(1) promote/evict)
- Batch observer dispatch in security walker
- fold-rust: single-walk hash, dead code removed, timing added
- bench/corpora/rust-oss/: ripgrep benchmark harness
2026-05-27 19:06:32 -04:00
trvon
98f02a4f4c
feat: architecture expansion — summary cache, observer interface, AI pre-pass
- SymbolicSummaryCache: per-function BV-64 cache to avoid re-encoding
- Language-agnostic observer overloads for Rust/Swift backends
- Abstract-interpretation pre-pass for Rust integer range filtering
- 3 new unit tests, 63/63 pass
2026-05-27 18:20:51 -04:00
trvon
56550a93a1
feat: symex-fuzz landscape, SWAN SIL parser, Juliet expansion, FP scoring
- docs/internal/symex-fuzz-landscape.md: 11 tools across 6 categories
- tools/fold-swift/swan_sil_parser: 75 SIL operator kinds, JSON converter
- bench/juliet/expansion/: 118-CWE catalog, gold generator, runner
- bench/score_fp.py: precision/recall/F1 per detector
2026-05-27 18:00:06 -04:00
trvon
9bdd989b7e
fix: binary harness_file, -I path resolution, caller-context schema
- Store harness_file in binary fuzz predictions to fix prep↔run mismatch
- Resolve relative -I flags against compile DB directory
- Add caller_unsafe/is_param_sourced fields to fold-rust NDJSON
- Allow empty target_sources in fuzz-run for dlopen harnesses
- Recursive IR encoder descent for nested hazards
2026-05-27 17:34:52 -04:00
trvon
9bdcd9f7a0
feat: audit fixes — complexity, CLI UX, MCP parity, binary fuzz
- CompositeSafetyObserver replaced with macros (composite_observer.hpp)
- tool_registry split per category
- Renamed --null-deref-nullable-allocations to --nullable-allocations
- --input-type hidden from help, fold-swift --help added
- MCP: fold.scan_rust, fold.scan_swift, backend filter on get_findings
- Binary fuzz: fold fuzz prep --binary <mach-o>, --compile-db optional
2026-05-27 16:29:39 -04:00
trvon
ffc7917957
feat: symbolic IR, swift backend, binary-to-fuzz pipeline, SARIF fixes
- Rust IR encoder (encodeRustIr): walks HIR expr trees, fires SafetyObserver hooks
- Swift SIL frontend (fold-swift): swiftc -emit-sil parser, demangling, NDJSON output
- SwiftBackend: --mode swift CLI routing, shells out to fold-swift
- Binary-to-fuzz: Mach-O export discovery, ARM64 ABI param-count inference, dlopen harness generation
- Language-agnostic IR: json_keys canonical constants, Call/Member/ArraySubscript/Cast/HeapNew nodes
- Dogfood fixes: SARIF kind field, cross-detector dedup, harness_file in predictions, Swift stoi safety
- Corpuses: swift-sil-z3-corpus.md, binary-fuzz-corpus.md
- AGENTS.md: cross-language wire format rule
2026-05-27 15:29:14 -04:00
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
b4c80b32b8
docs: capture library-expansion follow-ups in plan doc
Three outstanding workstreams after the matrix sweep:

1. scan_runner.cpp dispatch hook for uninit-local-read (C5).
   Uncommitted in local edits; entangled with parallel session's
   C2 clang::CallGraph work. Coordinated commit pending.

2. Native UAF detector. Carved out from C4 (ConsumedAnalysis was
   wrong-tool -- needs source attributes). New detector should
   be a CFG-walker tracking freed_ptrs per function.

3. Per-row precision baselines for Z5, Z10, C5, C7, C8, C9.
   Z4 has one (docs/perf-audit/runs/matrix/Z4-curl-2026-05-26.json);
   the rest are pending.

Also: cross-cutting cleanup (workspace junk to gitignore,
parallel-session rust-frontend edits, catch2 chained-comparison
lint).
2026-05-26 09:21:20 -04:00
trvon
1dc20ca920
docs(matrix): mark C4 unscheduled -- wrong-tool FP
clang::consumed::ConsumedAnalysis only activates on classes marked
[[clang::consumable]] + member functions marked
[[clang::callable_when(state)]] + [[clang::return_typestate(state)]].
Real-world C code (curl, yams, kernel-style) has none of these
attributes; without auto-injection the analysis is silent.

A native UAF detector remains a real opportunity, but it's a
CFG-walker shape (track malloc/free on tracked pointers + flag
derefs after free), not ConsumedAnalysis. Carved out as a future
detector row rather than wedged into C4's framing.
2026-05-26 09:16:03 -04:00