Skip to content

poser_mpfit: skip non-finite optical angles instead of passing to solver#353

Open
rocketmark wants to merge 1 commit intocollabora:masterfrom
rocketmark:upstream-pr/mpfit-nan-guard
Open

poser_mpfit: skip non-finite optical angles instead of passing to solver#353
rocketmark wants to merge 1 commit intocollabora:masterfrom
rocketmark:upstream-pr/mpfit-nan-guard

Conversation

@rocketmark
Copy link
Contributor

Summary

construct_input_from_scene in poser_mpfit.c feeds optical angles directly into the MPFIT solver without checking for non-finite values. When corrupt optical angle data reaches this function, the solver receives NaN or Inf as input, produces a garbage pose, and assert-crashes downstream (assert(!isnan(lhs[lh].Rot[0]))).

Dropping one non-finite measurement has negligible effect on the pose solve. Crashing does not.

Demonstration

Hardware trigger: a USB disturbance (cable flex, port brown-out) causes the FPGA to emit bad timestamps. The driver produces a non-finite optical angle. That angle propagates into construct_input_from_scene → MPFIT solver:

BEFORE fix:
a[axis] = NaN
meas->light.value = NaN ← passed directly to solver
MPFIT: produces garbage pose rotation
assert(!isnan(lhs[lh].Rot[0])) → fires
Process: SIGABRT
Result: crash, tracking lost

AFTER fix:
a[axis] = NaN
isfinite(NaN) == false → measurement skipped, continue
stderr: "[libsurvive WARN] poser_mpfit: NaN optical angle sensor N lh N axis N; suppressing further"
Process: continues normally
Result: one measurement dropped, pose solve unaffected

The missing check was presumably an oversight — the angles array is treated as valid whenever isReadingValue is true, but isReadingValue only checks the timestamp, not the angle value itself.

Impact

Any hardware that experiences USB instability is exposed. The FPGA timestamp corruption that produces non-finite angles is triggered by cable flex or port brown-out — common on embedded deployments with moving hardware. The crash is not recoverable without a process restart.

Change

One file, src/poser_mpfit.c. An isfinite() check is added before emplacing each measurement in construct_input_from_scene. Non-finite angles are skipped with a one-time stderr warning (to avoid log spam). The measurement count and solver input are otherwise unchanged.

Found via

Observed in production: tracker running on embedded hardware (Raspberry Pi, USB bus under load) would crash with assert(!isnan(lhs[lh].Rot[0])) after a cable disturbance. Backtrace confirmed the NaN originated from a corrupted optical angle passed through construct_input_from_scene without validation.

Corrupt optical angles (bad FPGA timestamps during USB disturbances) can
reach construct_input_from_scene() as NaN or Inf. Passing a non-finite
value into the MPFIT solver causes it to produce a garbage pose which then
assert-crashes downstream (observed as assert(!isnan(lhs[lh].Rot[0]))).

Add an isfinite() check before emplacing each measurement. Non-finite
angles are skipped with a one-time stderr warning. One dropped measurement
has negligible effect on the pose solve; crashing does not.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@rocketmark rocketmark force-pushed the upstream-pr/mpfit-nan-guard branch from 8b5e22c to a9d9441 Compare March 22, 2026 14:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant