From 926bb4c8bbc5d965d2bf7ddfa682cbf28a65eee4 Mon Sep 17 00:00:00 2001 From: Sang Woo Kim Date: Fri, 17 Jul 2026 00:38:51 +0900 Subject: [PATCH] NDPluginStats: value-initialise stats structs so dark frames don't broadcast garbage processCallbacks() declared its working statistics structs as NDStats_t stats, *pStats=&stats, statsTemp, *pStatsTemp=&statsTemp; NDStats_t is a POD with no constructor and the locals were never zeroed. The central-moment fields -- sigmaXY, skewX/Y, kurtosisX/Y, eccentricity and orientation -- are assigned only inside the if (M00 > 0.) block of doComputeCentroid(). A frame whose every pixel is below CentroidThreshold (a dark frame, a closed shutter, below-threshold illumination), or a run with ComputeCentroid disabled, leaves M00 == 0 and those fields unwritten. They are then copied unconditionally into the broadcast time-series NDArray and the corresponding _RBV parameters, so SigmaXY_RBV, SkewX/Y_RBV, KurtosisX/Y_RBV, Eccentricity_RBV, Orientation_RBV and their time-series waveforms carry stack garbage -- run-to-run varying, possibly NaN/inf -- on any dark or below-threshold frame. Dark frames are routine, so archives are corrupted and alarm thresholds on those PVs fire spuriously. Value-initialise both structs (NDStats_t stats={}, statsTemp={}) so every field defaults to zero and an unassigned central moment reads as 0 rather than uninitialised memory. The pointer members (profileX/Y, histogram, totalArray, netArray) are still assigned and freed under their existing guards; zero-init only makes them null when unused. Verified with a proof driver: a struct placed on memory pre-filled with 0xAA and processed as a dark frame (M00 == 0) broadcasts the garbage without the initialiser and 0 with it. --- ADApp/pluginSrc/NDPluginStats.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/ADApp/pluginSrc/NDPluginStats.cpp b/ADApp/pluginSrc/NDPluginStats.cpp index 1400207c7..ce04be707 100644 --- a/ADApp/pluginSrc/NDPluginStats.cpp +++ b/ADApp/pluginSrc/NDPluginStats.cpp @@ -427,7 +427,15 @@ void NDPluginStats::processCallbacks(NDArray *pArray) size_t bgdPixels; int bgdWidth; int dim; - NDStats_t stats, *pStats=&stats, statsTemp, *pStatsTemp=&statsTemp; + // Value-initialise both stats structs. NDStats_t is a POD with no + // constructor, and several fields (sigmaXY, skewX/Y, kurtosisX/Y, + // eccentricity, orientation) are assigned only inside the M00 > 0 block of + // doComputeCentroid. A dark or below-threshold frame (M00 == 0), or + // ComputeCentroid disabled, leaves them unwritten while they are copied + // unconditionally into the broadcast time-series array and the _RBV + // parameters below. Zero-init makes an unassigned field read as 0 instead + // of stack garbage. + NDStats_t stats={}, *pStats=&stats, statsTemp={}, *pStatsTemp=&statsTemp; double bgdCounts, avgBgd; NDArray *pBgdArray=NULL; int computeStatistics, computeCentroid, computeProfiles, computeHistogram;