Feat/configurable sanitizers and js precision (#32)

* chore: Exclude CLAUDE.md from Cargo.toml

* feat: Add configurable analysis rules and CLI commands for custom sanitizers and terminators

* feat: Enhance resource management and analysis efficiency

- Implemented parallel summary merging in `scan_filesystem` using rayon for improved performance.
- Introduced `GlobalSummaries::merge()` for efficient merging of summaries.
- Optimized file reading and hashing to eliminate redundant I/O operations.
- Added `should_scan_with_hash()` and `upsert_file_with_hash()` methods to streamline file processing.
- Enhanced taint analysis with in-place mutations to reduce memory allocations.
- Updated resource acquisition patterns to exclude false positives for `freopen` and wrapper functions.

* feat: Implement severity downgrade for findings in non-production paths and add source kind inference

* feat: Update versioning information in SECURITY.md for new stable line

* feat: Update categories in Cargo.toml to include parser-implementations and text-processing

* feat: Update dependencies in Cargo.lock for improved compatibility and performance

* feat: Update dependencies in Cargo.lock and Cargo.toml for improved compatibility
This commit is contained in:
Eli Peter 2026-02-25 04:02:11 -05:00 committed by GitHub
parent f96a89e7c1
commit 19b578c5c4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
37 changed files with 3775 additions and 432 deletions

View file

@ -3,9 +3,40 @@ use super::{AnalysisContext, CfgAnalysis, CfgFinding, Confidence};
use crate::cfg::StmtKind;
use crate::labels::DataLabel;
use crate::patterns::Severity;
use std::collections::HashSet;
pub struct UnreachableCode;
/// Collect function names that appear as arguments to configured event handler calls.
fn event_handler_callbacks(ctx: &AnalysisContext) -> HashSet<String> {
let mut callbacks = HashSet::new();
let handlers = match ctx.analysis_rules {
Some(rules) if !rules.event_handlers.is_empty() => &rules.event_handlers,
_ => return callbacks,
};
for idx in ctx.cfg.node_indices() {
let info = &ctx.cfg[idx];
if info.kind != StmtKind::Call {
continue;
}
if let Some(callee) = &info.callee {
let callee_lower = callee.to_ascii_lowercase();
let is_handler = handlers
.iter()
.any(|h| callee_lower.ends_with(&h.to_ascii_lowercase()));
if is_handler {
// The callback function is typically used within the call — any function
// that appears as `uses` of this call node is a potential callback.
for u in &info.uses {
callbacks.insert(u.clone());
}
}
}
}
callbacks
}
impl CfgAnalysis for UnreachableCode {
fn name(&self) -> &'static str {
"unreachable-code"
@ -13,6 +44,7 @@ impl CfgAnalysis for UnreachableCode {
fn run(&self, ctx: &AnalysisContext) -> Vec<CfgFinding> {
let reachable = dominators::reachable_set(ctx.cfg, ctx.entry);
let handler_callbacks = event_handler_callbacks(ctx);
let mut findings = Vec::new();
for idx in ctx.cfg.node_indices() {
@ -27,6 +59,13 @@ impl CfgAnalysis for UnreachableCode {
continue;
}
// Suppress findings for nodes inside event handler callbacks
if let Some(func_name) = &info.enclosing_func
&& handler_callbacks.contains(func_name)
{
continue;
}
let (rule_id, title, severity) = match info.label {
Some(DataLabel::Sanitizer(_)) => (
"cfg-unreachable-sanitizer",
@ -43,7 +82,9 @@ impl CfgAnalysis for UnreachableCode {
),
_ => {
// Check if it's a guard/auth call
if super::is_guard_call(info, ctx.lang) || super::is_auth_call(info, ctx.lang) {
if super::is_guard_call(info, ctx.lang, ctx.analysis_rules)
|| super::is_auth_call(info, ctx.lang)
{
(
"cfg-unreachable-guard",
"Unreachable guard/auth check",