cargo : clap_builder @ 4.6.0
PE Patrick Elsen signed 2026-05-28 published 2026-05-28

Claims

algorithm-impl-boundsalgorithm-impl-correctalgorithm-impl-safealgorithm-impl-testeddatastructure-impl-boundsdatastructure-impl-correctdatastructure-impl-safedatastructure-impl-testedenvironment-safehas-binarieshas-build-exechas-fuzz-testshas-install-exechas-integration-testshas-property-testshas-unit-testsimpl-algorithmimpl-concurrencyimpl-cryptoimpl-datastructureimpl-interpreterimpl-jitimpl-parserimpl-protocolis-benignparser-impl-correctparser-impl-safeparser-impl-testeduses-concurrencyuses-cryptouses-environmentuses-execuses-filesystemuses-interpreteruses-jituses-networkuses-unsafe

Summary

clap_builder 4.6.0 is the runtime engine behind clap. The entire 29 K-line codebase is safe Rust (#![forbid(unsafe_code)]), with no build scripts, no binary artefacts, and no network or filesystem access. One low-severity correctness finding: display_width misidentifies non-ESC ASCII control characters as ANSI sequences, producing incorrect help-text line widths. All other areas — the argument parser, FlatMap data structure, and did-you-mean algorithm — are sound and well-tested.

Report

Subject

clap_builder is the runtime engine of the clap command-line argument-parsing library. The clap crate is a thin re-export facade; all parsing logic, the Arg/Command/ArgMatches builder API, value validation, help and error formatting, and the derive-trait shims live here. The package is 29 K lines of safe Rust across 57 source files.

Methodology

The published .crate was compared against the upstream VCS checkout (at the commit recorded in .cargo_vcs_info.json) using diff. Differences were limited to Cargo's standard manifest normalisation and an added Cargo.lock; all source files match byte-for-byte.

No binary artefacts were present in the package. The Cargo.toml declares build = false and there is no build.rs, so no build-time code executes.

The source was surveyed with grep for unsafe blocks, environment variable reads, network/filesystem calls, process spawning, and concurrency primitives. The five largest files (command.rs, arg.rs, value_parser.rs, arg_matches.rs, parser.rs) were read in full, as were the utility modules (flat_map.rs, any_value.rs, flat_set.rs, graph.rs, suggestions.rs) and the output subsystem (fmt.rs, help_template.rs, textwrap/core.rs, textwrap/wrap_algorithms.rs, textwrap/word_separators.rs). All expect/unwrap call-sites outside test code were reviewed. The VCS repository was checked for integration tests and fuzz infrastructure.

Tools used: diff (macOS 15), grep/find (BSD), wc.

Results

The crate declares #![forbid(unsafe_code)] at the root (justifying uses-unsafe = false). No network, filesystem, or process-execution calls were found anywhere in the source (justifying uses-network, uses-filesystem, uses-exec, uses-jit, uses-interpreter, all false). No cryptographic operations are performed (uses-crypto = false) and no cryptographic algorithms are implemented (impl-crypto = false). No concurrency primitives are used or implemented (uses-concurrency = false, impl-concurrency = false). No protocol is implemented (impl-protocol = false). No interpreter is implemented (impl-interpreter = false) and no JIT (impl-jit = false). The crate ships no binary artefacts (has-binaries = false) and no build.rs (has-build-exec = false, has-install-exec = false). The code performs only the functions documented in its public API (is-benign = true).

Environment variable access (justifying uses-environment = true) is limited to two call sites: Arg::env reads a single user-specified variable via env::var_os when the env feature is enabled (builder/arg.rs:2207), and the wrap_help feature reads COLUMNS/LINES as a terminal-size fallback (output/help_template.rs:1118). Both accesses are narrowly scoped to documented functionality, justifying environment-safe = true.

The package implements a command-line argument parser (impl-parser = true), a FlatMap/FlatSet data-structure pair (impl-datastructure = true), and string-similarity "did you mean" fuzzy matching (impl-algorithm = true). All are implemented in safe Rust; correctness is covered by 21 files of inline unit tests (has-unit-tests = true) and a comprehensive integration test suite of 134 files in the upstream repository (has-integration-tests = true). No fuzz or property-based tests were found (has-fuzz-tests = false, has-property-tests = false). These observations justify parser-impl-safe, parser-impl-tested, parser-impl-correct, datastructure-impl-safe, datastructure-impl-correct, datastructure-impl-tested, datastructure-impl-bounds, algorithm-impl-safe, algorithm-impl-correct, algorithm-impl-tested, and algorithm-impl-bounds.

One low-severity correctness finding was raised (FINDING-1): display_width in textwrap/core.rs triggers its ANSI-escape-suppression logic on any ASCII control character rather than only on ESC. This causes incorrect display-width calculations when help text contains tab or other control characters, producing wrong line-wrap positions. The issue is aesthetic and cannot be reached by untrusted input in a way that affects memory safety.

Conclusion

clap_builder 4.6.0 is a well-structured, entirely safe-Rust codebase. The single finding is a minor cosmetic correctness defect in help-text formatting. The parser, data structures, and algorithm implementations are thoroughly tested. No safety, security, or legal concerns were identified.

Findings(1)

FINDING-1 correctness low

display_width misidentifies arbitrary ASCII control characters as ANSI escape sequences

In src/output/textwrap/core.rs, display_width sets control_sequence = true whenever ch.is_ascii_control() is true, then waits for 'm' to clear it. ANSI CSI sequences always start with ESC (\x1b) followed by [; other ASCII control characters (BEL \x07, TAB \x09, etc.) must not trigger the CSI state. A help string containing, say, a tab character followed by non-m printable text will have those printable characters excluded from the width count, producing incorrect line-wrapping in formatted help output. The bug is aesthetic — it cannot be triggered by untrusted input to cause memory unsafety — and only affects help text rendering in the wrap_help feature.

Annotations(6)

src/builder/arg.rs

src/builder/arg.rs, line 2202-2213

    #[cfg(feature = "env")]
    #[inline]
    #[must_use]
    pub fn env(mut self, name: impl IntoResettable<OsStr>) -> Self {
        if let Some(name) = name.into_resettable().into_option() {
            let value = env::var_os(&name);
            self.env = Some((name, value));
        } else {
            self.env = None;
        }
        self
    }

The env feature reads a single caller-specified environment variable via env::var_os at argument-construction time. This is the full extent of environment variable usage, justifying uses-environment = true and environment-safe = true.

src/lib.rs

src/lib.rs, line 9-9

#![forbid(unsafe_code)]

The crate declares #![forbid(unsafe_code)] at the crate root, ruling out any unsafe Rust, justifying uses-unsafe = false.

src/output/textwrap/core.rs

src/output/textwrap/core.rs, line 55-74

pub(crate) fn display_width(text: &str) -> usize {
    let mut width = 0;

    let mut control_sequence = false;
    let control_terminate: char = 'm';

    for ch in text.chars() {
        if ch.is_ascii_control() {
            control_sequence = true;
        } else if control_sequence && ch == control_terminate {
            control_sequence = false;
            continue;
        }

        if !control_sequence {
            width += ch_width(ch);
        }
    }
    width
}

The ANSI-strip heuristic in display_width sets control_sequence=true on any ASCII control character, not just ESC. Tab, BEL, and other control characters incorrectly enter the 'ANSI sequence' state, causing subsequent printable characters to be excluded from the width count until an 'm' is seen. See FINDING-1.

src/parser/features/suggestions.rs

Implements fuzzy flag/subcommand suggestion via strsim::jaro with a 0.7 threshold. Uses binary_search_by with .unwrap_or_else(|e| e) on the Err case (insertion point), which is always valid. Supports impl-algorithm = true and algorithm-impl-safe = true.

src/parser/parser.rs

Core argument parser implementing command-line tokenisation via clap_lex and dispatching to value parsers and validators. No unsafe code; error paths surface user-visible errors rather than panicking. Justifies impl-parser = true and parser-impl-safe = true.

src/util/flat_map.rs

FlatMap is a sorted parallel-vector map used to store parsed argument values. Its Iterator impls call .unwrap() after a .next() on the companion slice, safe because both slices are always kept in sync at insertion. Supports impl-datastructure = true and datastructure-impl-safe = true.