Research-0877: Error-code consistency audit — fork-added C surfaces¶
- Date: 2026-05-30
- Author: lusoris (agent-dispatched)
- Scope:
core/src/**C/C++/Obj-C TUs added by the fork (≥ 2026-04-15) - Related ADR: ADR-0877
Question¶
libvmaf's internal convention for status-returning C functions is negative POSIX errno (-EINVAL, -ENOMEM, -EIO, -ENODEV, -ENOSYS, …). Are fork-added C surfaces consistent with this, or have some drifted to bare -1 / wrong-sign +1 returns?
Method¶
- Enumerated every match of
return -?[12345];undercore/src/(filter outthird_party/,iqa/, vendored cJSON, libsvm). Initial hit set: 99 lines across 35 TUs. - Classified each file by first-commit date (
git log --all --pretty='%ad' --reverse -- libvmaf/src/<path>to traverse the ADR-0700 rename): pre-2026 = upstream-mirror, ≥ 2026-04-15 = fork-added. - For each fork-added match, read the surrounding function to determine whether the return value is:
- a true status code (candidate for errno conversion), OR
- a framework signal (e.g.
flush()"drain complete" → positive terminates the framework'swhile (!err)loop), OR - a boolean predicate (
vmaf_hip_available,vmaf_metal_dispatch_supports,vmaf_dnn_available), OR - a qsort comparator (
predict.c::score_compare). - Cross-referenced the call sites for each candidate to verify the change would not break the caller's branch logic.
- Checked in-flight PR file lists (
gh pr list --json files) to avoid colliding with #358 (eintr-and-io-error-audit — touches MCP transports), #359 (magic-number-audit — touchesmcp/mcp.c,transport_sse.c), and others.
Findings¶
Upstream-mirror — out of scope per CLAUDE.md §12 r7¶
These TUs predate the fork (Netflix-origin) and their return shape is the upstream contract. Touching them risks rebase conflicts and golden-data drift:
| TU | First commit |
|---|---|
core/src/feature/ssim.c | 2019-10-31 |
core/src/feature/motion.c | 2019-10-31 |
core/src/feature/ms_ssim.c | 2019-10-31 |
core/src/feature/psnr_tools.c | 2019-10-31 |
core/src/feature/common/blur_array.c | 2019-10-31 |
core/src/feature/mkdirp.c | 2021-12-13 (Stephen Mathieson MIT) |
core/src/predict.c | 2019-12-09 (qsort comparator) |
core/src/read_json_model.c | 2020-11-10 (positive = "skip key") |
core/src/pdjson.c | 2020-11-10 (vendored JSON parser) |
core/src/cuda/picture_cuda.c | 2022-07-16 |
core/src/cuda/common.c | 2022-07-16 |
core/src/feature/cuda/integer_adm_cuda.c | 2022-12-13 (Netflix CUDA port) |
core/src/feature/cuda/integer_vif_cuda.c | 2022-12-13 |
Fork-added — framework-correct (intentionally non-errno)¶
- Feature-extractor
flush()callbacks return positive on "drain complete"; the framework'svmaf_feature_extractor_context_flushloops onwhile (!(err = fex->flush(...)))— positive terminates the loop, negative surfaces an error. This applies to ALLreturn 1at the end offlush()in: core/src/feature/integer_motion_v2.c:430,487core/src/feature/hip/integer_motion_hip.c:629core/src/feature/hip/integer_motion_v2_hip.c:379,392,417core/src/feature/hip/integer_adm_hip.c:1280core/src/feature/hip/float_motion_hip.c:536,542core/src/feature/hip/integer_vif_hip.c:651core/src/feature/cuda/integer_motion_v2_cuda.c:282,307core/src/feature/sycl/{integer_motion_v2,integer_adm,integer_vif,float_motion}_sycl.cpp(4 sites)core/src/feature/metal/{integer_motion,integer_motion_v2,float_motion}_metal.mm(3 sites)core/src/feature/common/blur_array.c:63(close callback, same convention)core/src/mcp/mcp.c:48(transport loop terminator)- Boolean availability/predicate returns (NOT errors):
core/src/hip/common.c:96—vmaf_hip_available()returns 1 when HIP is compiled incore/src/dnn/dnn_api.c:35—vmaf_dnn_available()returns 1 when ONNX Runtime is linkedcore/src/metal/dispatch_strategy.c:49—vmaf_metal_dispatch_supports()returns 1 when feature matchescore/src/metal/common.mm:166,176,269— Apple7+ probe andvmaf_metal_available()- Documented
-1API contract (callers test== -1): core/src/dnn/model_loader.c:116,123—vmaf_dnn_sniff_kind()returnsVMAF_MODEL_KIND_*enum (0/1/2/3) or-1for "unknown"; documented inmodel_loader.h:131-132and asserted intest_model_loader.c:32-33.
Fork-added — in-flight PR overlap (skipped to avoid conflicts)¶
| TU | In-flight PR |
|---|---|
core/src/mcp/transport_stdio.c | #358 (eintr-audit) |
core/src/mcp/transport_uds.c | #358 |
core/src/mcp/transport_sse.c | #359 (magic-number-audit) |
core/src/mcp/mcp.c | #359 |
These will benefit from the same audit in a follow-up once the in-flight PRs land.
Fork-added — actually drifted (THIS PR's scope)¶
Four fork-added TUs (all introduced 2026-04-20 by the MS-SSIM SIMD pilot) return bare -1 on malloc failure where -ENOMEM is the right answer:
| TU | Line | Before | After |
|---|---|---|---|
core/src/feature/ms_ssim_decimate.c | 139 | return -1; | return -ENOMEM; |
core/src/feature/x86/ms_ssim_decimate_avx2.c | 216 | return -1; | return -ENOMEM; |
core/src/feature/x86/ms_ssim_decimate_avx512.c | 198 | return -1; | return -ENOMEM; |
core/src/feature/arm64/ms_ssim_decimate_neon.c | 197 | return -1; | return -ENOMEM; |
Plus a header doc tightening: core/src/feature/ms_ssim_decimate.h:54 "non-zero on allocation failure" → "-ENOMEM on allocation failure".
Caller-impact verification¶
The only direct caller is core/src/feature/ms_ssim.c:207-208:
if (ms_ssim_decimate(ref_imgs[idx - 1], cur_w, cur_h, ref_imgs[idx], 0, 0) ||
ms_ssim_decimate(cmp_imgs[idx - 1], cur_w, cur_h, cmp_imgs[idx], &cur_w, &cur_h)) {
Truthy check — works for any non-zero. No call sites compare against -1 specifically. Replacement strengthens the surface without breaking anything.
Recommendation¶
Land the four-TU + one-header change in this PR. Follow-up audits on the MCP transports (transport_stdio.c, transport_uds.c, transport_sse.c, mcp.c) once PRs #358 / #359 merge.
References¶
req— "Audit error-code return consistency in fork-added C code. The libvmaf convention is negative errno-style (-EINVAL,-ENOMEM, etc.) — every function that returns int as status should follow this."core/src/feature/feature_extractor.c:660-665— framework's flush loop contract (positive = terminate).- ADR-0700 —
libvmaf/→core/rename (used to classify file ages via pre-renamegit log). - ADR-0872 — sibling I/O-error / EINTR audit on MCP transports.