Analysis Architecture
aurora-lint uses a multi-pass analysis architecture:
Source Files
|
v
[Tree-sitter Parser] --> AST (per-file)
|
v
[Pre-scan Pass] --> Cross-file context (function defs, summaries, macros,
| struct types, global states, call graph, call-site args)
v
[CFG Construction] --> Per-function control-flow graphs
|
v
[Dataflow Analysis] --> Null state, value range, reaching defs, init state
|
v
[Rule Evaluation] --> 307 CERT C rules applied to AST + CFG + context
|
v
[Suppression Filter] --> Hash-based + wildcard (glob/prefix) suppression
|
v
[Export] --> CSV, XLSX, JSON, SARIF
Analysis Modules
- Tree-sitter parsing (
src/analyze/mod.rs). Fast, incremental, error-tolerant C parsing. Each
.cfile is parsed into an AST; the orchestrator coordinates prescan, CFG construction, dataflow, and per-rule evaluation with optional Rayon parallelism.- Cross-file pre-scan (
src/analyze/prescan.rs,context.rs). Walks the
-ddirectories (or, with no-d, the scan target itself) collecting function definitions, header prototypes, function summaries, call graphs, macro constants/aliases, struct field types, global constants, and global pointer null states. Second pass aggregates call-site argument null states and propagates transitive frees through parameter pass-through chains (max 8 iterations). Results stored inProjectContext, optionally cached to binary (--save-prescan/--load-prescan). Consumed by 15+ rules.- Function summaries (
src/analyze/function_summary.rs). Lightweight inter-procedural summaries computed during prescan:
frees_params,can_return_null,returns_allocation,checks_null_params,modifies_params,dereferences_params,never_returns,callsite_param_null_states(aggregated from all call sites),callsite_param_field_null_states(struct field propagation),callsite_param_pointee_null_states(pointer-to-pointer propagation),return_range(VRA inter-procedural),param_passthroughs(transitive free tracking). Consumed by 7 rules.- Control-flow graphs (
src/analyze/cfg.rs). Per-function CFG with basic blocks, typed edges (Fallthrough, TrueBranch, FalseBranch, BackEdge, Return, Break, Continue, Goto), and
condition_rangemetadata for path-sensitive edge refinement. Optional macro-constant-aware construction for dead-branch elimination. Consumed by 8 rules (INT30/31/32/33/34-C, EXP33/34-C, MEM01-C).- Null state dataflow (
src/analyze/null_state.rs). Forward dataflow on CFG with NullState lattice (Unknown → DefinitelyNull / PossiblyNull / NotNull). Edge refinement on branch conditions supports compound
||/&&expressions. Seeded from global pointer states, call-site parameter states, and function summaries. Primary consumer: EXP34-C; also used by API00-C.- Value range analysis (
src/analyze/value_range.rs). CFG-based forward value-range dataflow for integer variables. Tracks
TypedRange(interval + signedness/bit-width) per variable. Handles sequential assignments, conditional narrowing, loop bounds, and early-return guards. Inter-procedural return ranges from function summaries. Consumed by INT30/31/32/33/34-C.- Constant evaluation (
src/analyze/const_eval.rs). Syntactic constant folding of
#definemacro constants and arithmetic expressions. Includes built-in C99<limits.h>/<stdint.h>macros (LP64 model).try_evaluate_range()computes value ranges from constants + variables + loop bounds via ancestor walks. Consumed by 11 rules (INT, ENV, ERR, FIO, FLP, STR families).- Reaching definitions (
src/analyze/dataflow.rs). Standard iterative worklist algorithm computing which definitions (Declaration, Assignment, Parameter, NullAssignment, FreeCall, NullableCall) reach each program point. Supports use-after-free and null dereference queries. Primary consumer: MEM01-C.
- Initialization state (
src/analyze/init_state.rs). Forward dataflow tracking initialization status with malloc-aware semantics (Uninitialized, MaybeUninitialized, Initialized, MallocUninitialized, MallocInitialized). Detects partial-init patterns in loops. Primary consumer: EXP33-C.
- Macro-expansion engine (
src/analyze/macro_expand.rs). Registry-based, name-independent modeling of function-like macro bodies — not a per-macro name allowlist.
collect_function_macros+FunctionMacroback a growing set of shape predicates regardless of the macro’s name (as of this writing: output-param writes, the “safe free” free+null idiom, generic writes, forwarding to another macro, plain frees, clears, and callee-released-parameter detection — see the file’s ownpub fnlist for the current, authoritative set rather than trusting a count here). Consumed by 18 rules: ARR30-C, DCL13-C, DCL31-C, DCL41-C, EXP10-C, EXP33-C, EXP34-C, EXP36-C, INT32-C, INT34-C, MEM03-C, MEM12-C, MEM30-C, MEM31-C, MSC13-C, MSC37-C, PRE31-C, and WIN05-C. Before adding a name-heuristic workaround for a macro-opacity false positive, check whether this engine already covers it — seedocs/design/macro-expansion.mdfor the full design rationale and a per-rule disposition table.- Standard function database (
src/utility/cert_c/std_functions.rs). ~370 C11, POSIX, and Windows API functions recognized to suppress false positives on standard library calls (DCL31-C, DCL07-C).
- Call-role classification (
src/utility/cert_c/call_roles.rs). Single-source-of-truth predicates layered on top of the standard function database for “what role does this call play” (
is_allocator_call,is_heap_allocator,is_printf_family,is_scanf_family,is_sizeof_text), replacing 7+ independently reinvented, disagreeing per-rule lists found by task 481’s duplication sweep (task 487).- Arithmetic-overflow-detection helpers (
src/utility/cert_c/overflow_helpers.rs). Shared type-map-building and identifier/operand-extraction primitives for
INT30-C/INT32-C(and one primitive each forINT10-C), replacing ~20 identically-named private helpers duplicated across those two ~2800-line files — the largest duplicated surface found by task 481’s sweep (task 490). The overflow-guard-detection logic itself (has_overflow_check_*) stays rule-local: it only looks duplicated:INT30-C’s is unsigned-wraparound-focused andINT32-C’s is signed-overflow-focused.- Floating-point type inference (
src/utility/cert_c/float_typing.rs). Word-boundary-aware float/integer classification (
is_float_type,expr_is_float,expr_is_definitely_integer,collect_variable_types) shared by the FLP rule family. Task 491 migrated 3 of the 9 flagged rules (FLP02-C, FLP34-C, FLP37-C); the other 6 turned out to check genuinely different concepts (format specifiers,long doublespecifically, a more comprehensive extended-float set) and correctly stay rule-local.- Internal capability catalog (
docs/design/internal-capability-catalog.md). A browsable-by-concept catalog of every reusable primitive in
src/utility/cert_c/*.rsandsrc/analyze/*.rs(macro detection, declarator resolution, lvalue/aliasing, constant folding/VRA, CFG, function summaries, suppression, cross-fileProjectContext). Skim it before writing any new AST/text heuristic in a rule file — filed as task 479 after a near-duplication of DCL40-C’s macro-detection helpers in MSC12-C task 475.- Suppression system (
src/analyze/suppression.rs). Inline
// AURORA-SUPPRESScomments andsuppress.tomlfiles (the pre-renameSQC-SUPPRESS/.sqc-suppress.tomlspellings still parse). SHA-256 hash-based point suppressions and glob/prefix wildcard suppressions.
Current Capabilities
Capability |
Implementation |
|---|---|
Local variable/type inference |
Per-function |
Preprocessor block traversal |
|
Standard function database |
~370 C11/POSIX/Windows functions |
Cross-file function scanning |
|
CFG construction |
Per-function with |
Reaching definitions |
Iterative worklist dataflow (MEM01-C) |
Inter-procedural summaries |
Null returns, freed params, no-return, return ranges, dereferences, pass-throughs |
CFG-based null state dataflow |
Forward dataflow with NullState lattice, compound condition support, global/call-site seeding |
Value range analysis |
CFG-based forward dataflow, inter-procedural return ranges, type-aware intervals |
Initialization state analysis |
Forward dataflow with malloc-aware semantics |
Constant evaluation |
Macro resolution, built-in limits, sizeof types |
Macro-expansion engine (registry) |
Name-independent free+null and output-param macro body modeling (MEM30/31-C, EXP33-C, DCL31-C) |
Call-site null propagation |
Aggregated argument states across all callers |
Transitive free propagation |
Parameter pass-through chains + field-sensitive custom-deallocator credit (MEM31-C) |
Global pointer null state |
Cross-file extern pointer tracking (EXP34-C) |
Struct field type resolution |
Prescan-collected struct definitions |
Taint tracking |
Intra-function (FIO30-C, STR02-C) |
Dead-branch elimination |
Macro-constant-aware CFG construction |
Known Limitations
Gap |
Impact |
|---|---|
No general macro expansion |
Arbitrary macro bodies are not expanded. A
registry-based engine ( |
No alias analysis |
Pointer aliasing unresolved; field-scoped alias collection causes cross-function issues |
No symbolic execution |
Complex path conditions not evaluated |
No SSA form |
No use-def chains beyond reaching definitions |
VRA intra-procedural only |
Inter-procedural argument ranges and field-sensitive VRA not implemented; return ranges available |
Limited taint tracking |
Intra-function only (STR02-C, FIO30-C); cross-function taint for injection CWEs planned |
Struct field tracking limited |
Prescan-visible structs only (INT32-C/INT30-C); no field-level free or null tracking |
No ownership model |
Same-function ownership transfer (allocate + custom deallocator) is credited, but parameter-owned vs. locally-owned struct lifetimes are not distinguished; dominant remaining MEM31-C real-world FP source |
Architectural Ceiling
Current TP rate: 83.8% (Juliet, v0.4.116, 74 CWEs; up from 67.5% at v0.3.119). CWE-190/191 (integer overflow) and CWE-476 (null dereference) have since moved substantially with VRA and null-state work; the remaining gaps are concentrated in a smaller set of CWEs still requiring deeper analysis:
CWE-190 (integer overflow): 100.0% — resolved via value-range analysis.
CWE-191 (integer underflow): 98.5% (was 55.3%) — same VRA work.
CWE-476 (null dereference): 67.9% (was 61.9%) vs clang-tidy 94.3%. Requires deeper inter-procedural null propagation and alias analysis.
CWE-121 (stack buffer overflow): 71.0% (was 57.5%) vs clang-tidy 86.6%. Requires symbolic buffer size tracking across assignments.
CWE-369 (divide by zero): 57.8% (was 56.0%) vs clang-tidy 94.7%. Requires stronger zero-value tracking through assignments; largely unmoved despite the VRA/alias investment that lifted 190/191/476/121.
Alias analysis and field-sensitive value tracking remain the two capabilities most likely to close the remaining gap, particularly for CWE-369 and the residual CWE-121/476 share tied to pointer aliasing.
Competitor Landscape
5-tool comparison on 15 overlapping Juliet CWEs (28,488 files):
Tool |
Detection Rate |
FP Rate |
Analysis Depth |
Price |
|---|---|---|---|---|
clang-tidy |
91.6% |
0.8% |
AST + path-sensitive |
Free |
aurora-lint |
67.5% |
32.5% |
AST + CFG + inter-procedural |
– |
Frama-C |
61.0% |
39.0% |
Abstract interpretation |
Free |
Infer |
43.6% |
56.4% |
Separation logic |
Free |
cppcheck |
36.4% |
63.6% |
Data-flow |
Free |
aurora-lint row is from the v0.3.119 Juliet benchmark, held fixed here because the other four tools were not re-run at v0.4.116 — this table is a frozen snapshot of a one-time comparative study, not a continuously re-measured figure. aurora-lint’s own overall TP rate has since risen to 83.8% (see above); it is not directly comparable to the 67.5% row without re-running the other four tools on the same 15-CWE, 28,488-file slice.
aurora-lint achieved 100% precision (zero FP) on 48 of 74 benchmarked CWEs as of v0.4.116 (a frozen figure from this study, not re-measured since; see README.md’s Benchmark Highlights for the current 100%-precision-CWE count), including CWE-690, CWE-761, CWE-78, and CWE-190. Broadest CWE coverage (74+ CWEs benchmarked vs clang-tidy’s 15 in the frozen study above).
Key context: Tools on average find ~20% of weaknesses in Juliet (ISSTA2022). Even commercial tools miss 27% (Goseva2015). Industry FP target for adoption is 10–20%. See Bibliography for full references.