Skip to content

Fix uninitialized TMS_KalmanNode::chi2 read in Kalman fitting - #305

Open
SFBayLaser wants to merge 1 commit into
mainfrom
fix/kalman-node-chi2-uninitialized
Open

Fix uninitialized TMS_KalmanNode::chi2 read in Kalman fitting#305
SFBayLaser wants to merge 1 commit into
mainfrom
fix/kalman-node-chi2-uninitialized

Conversation

@SFBayLaser

Copy link
Copy Markdown
Member

Summary

  • TMS_Kalman::Runchi2() deliberately skips computing chi2 for nodes 0 and 1 of every track ("too sensitive at the end"), but TMS_KalmanNode::chi2 was never initialized anywhere -- not in the constructor's member-init list, not in the body.
  • GetTrackChi2() unconditionally sums chi2 across all nodes in KalmanNodes, so it always includes uninitialized stack memory for at least the first node (and the first two, for tracks with 3+ nodes) of every single Kalman fit.
  • That garbage value feeds directly into TMS_TrackFinder::FindTracks()'s plus/minus charge-sign selection (use_minus), so every track's reported charge sign, chi2, and momentum could be affected.

How this was found

Found via valgrind --track-origins=yes while investigating an unrelated, pre-existing TMS_TimeSlicer build-to-build non-determinism issue. Of 177 distinct Valgrind error contexts in a full pipeline run, this was the only one pointing into dune-tms source rather than well-known ROOT (TStorage::UpdateIsOnHeap) or Geant4-bundled-zlib (longest_match/deflate_fast) false positives.

Fix

Initialize chi2(0.0) in TMS_KalmanNode's constructor member-init list, matching the apparent intent that chi2-excluded nodes contribute nothing to the sum rather than garbage.

Test plan

  • Rebuild and rerun the standard validation sample; confirm no crash/behavior regression
  • Compare Charge_Kalman/chi2/momentum distributions before and after (may shift slightly now that the calculation is well-defined instead of UB)

TMS_Kalman::Runchi2() deliberately skips nodes 0 and 1 when computing
chi2 ("too sensitive at the end"), but TMS_KalmanNode::chi2 was never
initialized in the constructor. GetTrackChi2() unconditionally sums
chi2 across all nodes, so every track's chi2 -- and therefore the
plus/minus charge-sign selection at TMS_TrackFinder::FindTracks()'s
use_minus decision -- included uninitialized stack memory.

Confirmed via valgrind --track-origins=yes: this was the only
non-ROOT/zlib finding in the whole reconstruction pipeline (everything
else was well-known ROOT TStorage::UpdateIsOnHeap and Geant4's bundled
zlib longest_match/deflate_fast false positives). Initializing chi2 to
0.0 matches the apparent intent -- nodes excluded from the chi2 sum
should contribute nothing, not garbage.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes undefined behavior in the Kalman fit by ensuring TMS_KalmanNode::chi2 is initialized to a known value (0.0) for nodes where TMS_Kalman::Runchi2() intentionally does not compute chi2, preventing GetTrackChi2() from summing indeterminate data across nodes.

Changes:

  • Initialize TMS_KalmanNode::chi2 to 0.0 in the constructor member-initializer list.
  • Add an in-code comment documenting why chi2 defaults to zero (nodes 0 and 1 skipped by Runchi2()).

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@jdkio jdkio left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

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.

3 participants