Skip to content

refactor(core): C++23 pilot Wave 1 — opt.c → opt.cpp (ADR-0721) - #43

Merged
lusoris merged 1 commit into
masterfrom
feat/cpp23-pilot-opt-20260528
May 28, 2026
Merged

lusoris merged 1 commit into
masterfrom
feat/cpp23-pilot-opt-20260528

Conversation

@lusoris

@lusoris lusoris commented May 28, 2026

Copy link
Copy Markdown
Contributor

Summary

Converts core/src/opt.c → core/src/opt.cpp using C++23 std::optional<T> for the
three internal parse helpers (parse_bool, parse_int, parse_double). The public C
ABI (vmaf_option_set) is identical — same signature, same return contract, same
case-sensitive string comparison behavior. opt.h gains extern "C" guards. Follows
the ADR-0708 playbook for metadata_handler.cpp (C++20 Wave 0 pilot).

Also fixes a pre-existing meson setup failure: test_ansnr_simd.c was deleted in
ADR-0720/PR #38 but its core/test/meson.build stanza was not cleaned up.

Type

  • refactor — no behavior change

Checklist

  • Commits follow Conventional Commits (the commit-msg hook enforces this).
  • make format && make lint is green locally.
  • Unit tests pass: meson test -C build-cpp23-pilot --suite=fast — 50/50 PASS.
  • If I touched any SIMD/GPU code path, I ran /cross-backend-diff and the worst ULP is ≤ 2.
    no SIMD/GPU code path touched — pure C→C++ internal refactor.
  • If I touched a feature extractor with SIMD/GPU twins, I either updated every twin or listed the gap under "Known follow-ups" below.
    no feature extractor touched.
  • If I added a new .c / .cpp / .cu / .h / .hpp, it has the appropriate license header.
    core/src/opt.cpp carries the Netflix BSD+Patent header (upstream-touched file).
  • If this is a breaking change, the commit message uses ! or BREAKING CHANGE:.
    no breaking change.
  • If this PR adds an ADR, the ADR row lives in docs/adr/_index_fragments/<NNNN-slug>.md and the slug is appended to docs/adr/_index_fragments/_order.txt.
    docs/adr/_index_fragments/0721-cpp23-pilot-opt.md + _order.txt updated; scripts/docs/concat-adr-index.sh --write run.

Bug-status hygiene (ADR-0165)

no state delta: pure internal refactor with no bug opened, closed, or ruled out.

Netflix golden-data gate (ADR-0024)

  • I did not modify any assertAlmostEqual(...) score in the Netflix golden Python tests.

Cross-backend numerical results

no SIMD/GPU path touched; opt.c is pure string→scalar parsing with no arithmetic output.

Deep-dive deliverables (ADR-0108)

  • Research digest — no digest needed: mechanical conversion following ADR-0708 playbook; no novel design decisions.
  • Decision matrix — captured in ADR-0721 ## Alternatives considered (expected vs optional, string_view vs const char*, global cpp_std bump vs per-target override).
  • AGENTS.md invariant note — added to core/AGENTS.md: opt.cpp upstream-sync contract and extern "C" guard preservation.
  • Reproducer / smoke-test command — see Reproducer section below.
  • CHANGELOG fragment — changelog.d/changed/cpp23-opt.md.
  • Rebase note — docs/rebase-notes.md §core/src/opt.cpp — C++23 Wave 1 pilot (ADR-0721).

Reproducer

# Build host-side, CPU only
meson setup build-cpp23-pilot core -Denable_cuda=false -Denable_sycl=false
ninja -C build-cpp23-pilot

# Fast test suite — must be 50/50
meson test -C build-cpp23-pilot --suite=fast

# CLI smoke — flag list must be present
./build-cpp23-pilot/tools/vmaf 2>&1 | head -10
# Expected: Usage: ... options including --model, --feature, --reference, etc.

no user-discoverable surface change — internal refactor; CLI parse is bit-equivalent (verified via --help smoke).

Known follow-ups

  • Wave 2: log.c (ROI 3.0) and mem.c (ROI 2.0) — separate PR.
  • dict.c (Wave 3, ROI 0.83) deferred until cpp_std=c++23 is set project-wide (requires std::expected).
  • std::expected<T, int> as a replacement for std::optional + separate -EINVAL return: deferred until the host toolchain ships a stable <expected> (gcc ≥ 13 / clang ≥ 16 required; current CI uses gcc 12/clang 15).

@lusoris
lusoris marked this pull request as ready for review May 28, 2026 15:13
@lusoris
lusoris enabled auto-merge (squash) May 28, 2026 15:14
lusoris added a commit that referenced this pull request May 28, 2026
PR #46 caught 5 workflow files but 7 more retained `meson setup <BUILDDIR>
-<FLAGS>` without a positional source dir. Since the root-level meson.build
moved into core/ (ADR-0700), those calls fail with "no meson.build found".
Adds `core` between BUILDDIR and the first flag for:

- tests-and-quality-gates.yml: 10 occurrences (build, build-mcp,
  build-coverage, build-coverage-gpu)
- sanitizers.yml: 2
- security-scans.yml: 1
- rust-ci.yml: 1
- lint-and-format.yml: 3 (also swap stale libvmaf sourcedir → core)
- libvmaf-build-matrix.yml: 4 (same swap)
- fuzz.yml: 1 (same swap)

Unblocks the cpp23 merge train (PR #41, #43, #44, #45).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
lusoris added a commit that referenced this pull request May 28, 2026
* fix(ci): post-rename path refs — libvmaf/ → core/, enable dep graph

Following the ADR-0700 repo-layout rename (libvmaf/ → core/), five CI
workflow files still referenced the old source-directory path. This
caused CodeQL (Python/C++), Docker, FFmpeg-integration, nightly
clang-tidy, and supply-chain builds to fail, blocking all merges via
the Required Checks Aggregator.

Changes:
- docker-image.yml, ffmpeg-integration.yml: path filters libvmaf/** → core/**
- ffmpeg-integration.yml: meson setup sourcedir libvmaf → core (×3)
- supply-chain.yml: meson setup sourcedir libvmaf → core
- nightly.yml: cd libvmaf → cd core; find libvmaf/src libvmaf/tools → core/src core/tools
- tests-and-quality-gates.yml, libvmaf-build-matrix.yml: stale comments updated
- security-scans.yml: replace gitleaks-action@v2.3.9 (requires
  GITLEAKS_LICENSE on org repos) with direct gitleaks CLI binary
  install (Apache-2.0 CLI, no license required); keeps SARIF upload
- Repo: vulnerability alerts + dependency graph enabled via GitHub API

no user-discoverable surface change — CI infra repair
no digest needed: post-rename path fix, mechanical equivalent
no decision matrix needed: pure path-rename fix following ADR-0700
no rebase-sensitive invariants

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(ci): add explicit 'core' sourcedir to remaining meson setup calls

PR #46 caught 5 workflow files but 7 more retained `meson setup <BUILDDIR>
-<FLAGS>` without a positional source dir. Since the root-level meson.build
moved into core/ (ADR-0700), those calls fail with "no meson.build found".
Adds `core` between BUILDDIR and the first flag for:

- tests-and-quality-gates.yml: 10 occurrences (build, build-mcp,
  build-coverage, build-coverage-gpu)
- sanitizers.yml: 2
- security-scans.yml: 1
- rust-ci.yml: 1
- lint-and-format.yml: 3 (also swap stale libvmaf sourcedir → core)
- libvmaf-build-matrix.yml: 4 (same swap)
- fuzz.yml: 1 (same swap)

Unblocks the cpp23 merge train (PR #41, #43, #44, #45).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(test): remove orphan test_ansnr_simd meson entry (ADR-0720 fallout)

test_ansnr_simd.c was deleted by the ansnr drop (PR #38 / ADR-0720) but
the corresponding executable() and test() blocks in core/test/meson.build
were never cleaned up, causing `meson setup` to fail with
"File test_ansnr_simd.c does not exist" on every downstream PR.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(ci): default enable_rust_features=false (cbindgen unavailable in CI runners)

Flips the meson_options.txt default from true to false so CI builds
do not attempt to link libvmafx_tad.a when cargo/cbindgen are absent.
Opt-in with -Denable_rust_features=true on developer machines.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
@lusoris
lusoris force-pushed the feat/cpp23-pilot-opt-20260528 branch 2 times, most recently from 5e9b47c to b1de9ec Compare May 28, 2026 19:31
@lusoris

lusoris commented May 28, 2026

Copy link
Copy Markdown
Contributor Author

CRITICAL finding from adversarial review: opt.cpp parse_int/parse_double call std::strtol/std::strtod via sv.data() without guaranteed NUL-termination. If any future caller constructs a string_view over a substring (not a full C-string), strtol reads past the slice boundary — UB. Fix: copy sv to std::string before calling strtol/strtod, or add assert(sv.data()[sv.size()] == '\0'). See docs/research/cpp23-wave-adversarial-review-20260528.md finding #3.

@lusoris

lusoris commented May 28, 2026

Copy link
Copy Markdown
Contributor Author

Fix for CRITICAL adversarial review finding in PR #78 pushed as 59cbf81. See PR #78 digest for context.

lusoris added a commit that referenced this pull request May 28, 2026
Read-only adversarial review of the C to C++23 conversion wave. Found 4
CRITICAL, 2 HIGH, 10 MEDIUM, 3 LOW issues across all 9 PRs. No code
changes; documentation and findings only.

Critical findings:
- PR #48 dict.cpp: strtof (float) assigned to double, precision loss
  on option values causes potential score corruption
- PR #54 model.cpp: strlen(model->name) - 5U unsigned underflow can
  produce SIZE_MAX-4 calloc size, heap overflow
- PR #58 ref.cpp: make_unique/operator-new but C callers may free(),
  allocator mismatch is UB / heap corruption
- PR #43 opt.cpp: string_view::data() passed to strtol without
  guaranteed NUL-termination

All findings documented in docs/research/cpp23-wave-adversarial-review-20260528.md.
Recurring smell pattern added to core/AGENTS.md invariant list.
state.md row added. rebase-notes entry added.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
lusoris added a commit that referenced this pull request May 28, 2026
Read-only adversarial review of the C to C++23 conversion wave. Found 4
CRITICAL, 2 HIGH, 10 MEDIUM, 3 LOW issues across all 9 PRs. No code
changes; documentation and findings only.

Critical findings:
- PR #48 dict.cpp: strtof (float) assigned to double, precision loss
  on option values causes potential score corruption
- PR #54 model.cpp: strlen(model->name) - 5U unsigned underflow can
  produce SIZE_MAX-4 calloc size, heap overflow
- PR #58 ref.cpp: make_unique/operator-new but C callers may free(),
  allocator mismatch is UB / heap corruption
- PR #43 opt.cpp: string_view::data() passed to strtol without
  guaranteed NUL-termination

All findings documented in docs/research/cpp23-wave-adversarial-review-20260528.md.
Recurring smell pattern added to core/AGENTS.md invariant list.
state.md row added. rebase-notes entry added.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…rse_int/parse_double (adversarial review PR #78)

string_view is not guaranteed NUL-terminated; passing sv.data() directly to
strtol/strtod is UB when sv is a substring view. Copy to std::string first.
Fixes the CRITICAL finding flagged in adversarial review PR #78.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@lusoris
lusoris force-pushed the feat/cpp23-pilot-opt-20260528 branch from 59cbf81 to c811219 Compare May 28, 2026 21:56
@lusoris
lusoris merged commit 7a62d2f into master May 28, 2026
47 of 63 checks passed
@lusoris
lusoris deleted the feat/cpp23-pilot-opt-20260528 branch May 28, 2026 22:35
@lusoris lusoris added this to the 1.0.0 — First release milestone Sep 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant