fix(cli): make --model and --feature option strings escape-aware (ADR-1180) - #1310
fix(cli): make --model and --feature option strings escape-aware (ADR-1180)#1310lusoris wants to merge 5 commits into
Conversation
612aa7b to
732ee54
Compare
…c at its tidy baseline Extract the in-place `\=` compaction from parse_model_config() into unescape_equals_in_place() and make the drained `rest` token const. cli_parse() stays exactly as #1287 left it (no argv/settings null-guard: the analyzer misread that guard as evidence argv can be null, 16828c3). Split the ADR-1180 tests into six focused functions so each stays under the readability-function-size thresholds, and cite every `return NULL;` with NOLINTNEXTLINE(modernize-use-nullptr) per ADR-1138, matching the tidy pass #1287 applied to the rest of the file. clang-tidy measured against origin/feat/vmafx-cli-alias: core/tools/cli_parse.cpp 0 -> 0, core/test/test_cli_parse.c 24 -> 24 (all pre-existing).
732ee54 to
ee7e13e
Compare
The seven `cli_parse_corpus/` seeds all predate the escape-aware splitter, so the fuzzer had no starting point that exercises `cli_split()` / `cli_unescape()`. Add one NUL-separated argv seed covering, in a single input, the three constructs the new grammar introduces: an unescaped inner `=` in a value (`path=/dir=eq/...`, the silent-truncation case), a backslash-escaped delimiter (`m\:colon.json`), and a Windows drive-letter colon inside a `--feature` option value (`some_path=C:\x`). Force-added, like the seven seeds already tracked beside it: the `core/test/fuzz/*_corpus/` ignore rule exists to keep fuzzer-generated corpus growth out of the tree, not the checked-in seeds. Ported from PR #1310, which proposed the same idea but wrote the seed as one space-joined line with a trailing newline. `tokenise_argv()` in core/test/fuzz/fuzz_cli_parse.c splits on NUL, so that form collapses to a single argv token and never reaches the option-string parsers at all; this seed uses the NUL separation the harness and the other seeds use. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Closing in favour of #1336 ( Both binaries were built from their own branch tips (CPU-only,
Rows 1 and 2 are the two failures this row's own "Closes when" clause names, and they are the ones
This PR's 30/30 green suite does not contradict that: the drive-letter feature case is asserted against Smaller deltas, same direction: this PR leaves Nothing here is lost. The one salvageable unique artifact, The other unique change, Its intent is wrong for that layer too: #1336 is rebased onto current |
The seven `cli_parse_corpus/` seeds all predate the escape-aware splitter, so the fuzzer had no starting point that exercises `cli_split()` / `cli_unescape()`. Add one NUL-separated argv seed covering, in a single input, the three constructs the new grammar introduces: an unescaped inner `=` in a value (`path=/dir=eq/...`, the silent-truncation case), a backslash-escaped delimiter (`m\:colon.json`), and a Windows drive-letter colon inside a `--feature` option value (`some_path=C:\x`). Force-added, like the seven seeds already tracked beside it: the `core/test/fuzz/*_corpus/` ignore rule exists to keep fuzzer-generated corpus growth out of the tree, not the checked-in seeds. Ported from PR #1310, which proposed the same idea but wrote the seed as one space-joined line with a trailing newline. `tokenise_argv()` in core/test/fuzz/fuzz_cli_parse.c splits on NUL, so that form collapses to a single argv token and never reaches the option-string parsers at all; this seed uses the NUL separation the harness and the other seeds use. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The seven `cli_parse_corpus/` seeds all predate the escape-aware splitter, so the fuzzer had no starting point that exercises `cli_split()` / `cli_unescape()`. Add one NUL-separated argv seed covering, in a single input, the three constructs the new grammar introduces: an unescaped inner `=` in a value (`path=/dir=eq/...`, the silent-truncation case), a backslash-escaped delimiter (`m\:colon.json`), and a Windows drive-letter colon inside a `--feature` option value (`some_path=C:\x`). Force-added, like the seven seeds already tracked beside it: the `core/test/fuzz/*_corpus/` ignore rule exists to keep fuzzer-generated corpus growth out of the tree, not the checked-in seeds. Ported from PR #1310, which proposed the same idea but wrote the seed as one space-joined line with a trailing newline. `tokenise_argv()` in core/test/fuzz/fuzz_cli_parse.c splits on NUL, so that form collapses to a single argv token and never reaches the option-string parsers at all; this seed uses the NUL separation the harness and the other seeds use. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The seven `cli_parse_corpus/` seeds all predate the escape-aware splitter, so the fuzzer had no starting point that exercises `cli_split()` / `cli_unescape()`. Add one NUL-separated argv seed covering, in a single input, the three constructs the new grammar introduces: an unescaped inner `=` in a value (`path=/dir=eq/...`, the silent-truncation case), a backslash-escaped delimiter (`m\:colon.json`), and a Windows drive-letter colon inside a `--feature` option value (`some_path=C:\x`). Force-added, like the seven seeds already tracked beside it: the `core/test/fuzz/*_corpus/` ignore rule exists to keep fuzzer-generated corpus growth out of the tree, not the checked-in seeds. Ported from PR #1310, which proposed the same idea but wrote the seed as one space-joined line with a trailing newline. `tokenise_argv()` in core/test/fuzz/fuzz_cli_parse.c splits on NUL, so that form collapses to a single argv token and never reaches the option-string parsers at all; this seed uses the NUL separation the harness and the other seeds use. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The seven `cli_parse_corpus/` seeds all predate the escape-aware splitter, so the fuzzer had no starting point that exercises `cli_split()` / `cli_unescape()`. Add one NUL-separated argv seed covering, in a single input, the three constructs the new grammar introduces: an unescaped inner `=` in a value (`path=/dir=eq/...`, the silent-truncation case), a backslash-escaped delimiter (`m\:colon.json`), and a Windows drive-letter colon inside a `--feature` option value (`some_path=C:\x`). Force-added, like the seven seeds already tracked beside it: the `core/test/fuzz/*_corpus/` ignore rule exists to keep fuzzer-generated corpus growth out of the tree, not the checked-in seeds. Ported from PR #1310, which proposed the same idea but wrote the seed as one space-joined line with a trailing newline. `tokenise_argv()` in core/test/fuzz/fuzz_cli_parse.c splits on NUL, so that form collapses to a single argv token and never reaches the option-string parsers at all; this seed uses the NUL separation the harness and the other seeds use. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Summary
Make
--modeland--featureoption-string parsing escape-aware so paths containing=,:,., or Windows drive letters can be passed without premature delimiter splitting (Netflix/vmaf#766, ADR-1180). Replaced rawstrsep/vmaf_cli_strsepcalls incore/tools/cli_parse.cppwithvmaf_cli_splitwhich scans in place and compacts\:,\=,\., and\\. Added a Windows drive-letter affordance inparse_model_configpreserving[A-Za-z]:\and[A-Za-z]:/prefixes inpath=verbatim without requiring manual escaping. Updated Go surfaces (pkg/libvmaf,pkg/corpus) and in-tree FFmpeg tune filter patch (ffmpeg-patches/0008-add-libvmaf_tune-filter.patch) to escape and unescape delimiters consistently. Verified via incremental build and 30/30core/build/test/test_cli_parseunit tests, 115/115meson test --suite=fast(excluding GPU), 271 passed / 12 skipped / 0 failed Netflix CPU golden tests, and Go unit tests inpkg/libvmafandpkg/corpus. Note: this branch was stacked on PR #1287 (feat/vmafx-cli-alias), which merged to master on 2026-09-05 (b14a718); the branch is now rebased onto master (c2d22cea5, 2026-09-06). #1287's three follow-up fixes (the%%.6fusage-text escape, the argv null-check removal incli_parse(), and thetest_cli_parse.ctidy pass) are kept verbatim, and the ADR-1180 tests were split into six focused functions with citedNULLreturns so the file stays at its clang-tidy baseline (24 warnings, all pre-existing).Type
fix— make --model and --feature option strings escape-aware (ADR-1180, escaping of special characters in --model/--feature cli params Netflix/vmaf#766)Checklist
make format && make lintis green locally (pre-commit on every touched file).build-cpu/test/test_cli_parse, 114/114meson test -C build-cpu --suite=fast(0 fail),go test ./pkg/corpus/...ok.go test ./pkg/libvmaf/...cannot link on this workstation (stale localcore/build-cpumissingvmaf_dnn_*) — reproduced identically on unmodifiedorigin/master, so it is not this PR's regression;TestEscapeOptValue's 9-case table was verified out-of-tree against the shippedescapeOptValuebody.docs/usage/cli.md,docs/adr/1180-cli-option-string-escapes.md.Bug-status hygiene (ADR-0165)
docs/state.md— movedT-UPSTREAM-766-CLI-OPTION-STRING-DELIMITERS-2026-09-03to Recently closed, citingPR #1310 (fix/cli-option-string-escapes).Netflix golden-data gate (ADR-0024)
assertAlmostEqual(...)score in the Netflix golden Python tests.Deep-dive deliverables (ADR-0108)
AGENTS.mdinvariant note — core/tools/AGENTS.md § ADR-1180changelog.d/fixed/cli-option-string-escapes.mddocs/rebase-notes.mdentryReproducer
🤖 Generated with Claude Code