Skip to content

Commit 2f5bc1e

Browse files
committed
fix: heap overflow in fit26 - x[1] written into a 1-element array
DecayFit26::fit writes the fitted fraction to x[0] and the complementary fraction to x[1], but the Fit26 Python wrapper allocated a 1-element parameter array (and the SWIG wrapper enforced exactly length 1), so every fit26 call wrote 8 bytes past the numpy buffer. The overflow was absorbed silently by allocator slack on macOS/Linux but corrupted the CRT heap on Windows, crashing the test suite later with 0xc0000374 (detected in whatever allocation-heavy code ran next). The parameter array now has both slots, the SWIG wrapper requires at least length 2, and the complementary fraction is returned to the caller.
1 parent fbb3f63 commit 2f5bc1e

3 files changed

Lines changed: 10 additions & 5 deletions

File tree

ext/python/DecayFit26.i

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,13 @@
1717
}
1818

1919
static double my_fit(double* x, int n_x, short* fixed, int n_fixed, DecayFitData* p){
20-
if (n_x != 1) {
20+
// fit26 writes the fitted fraction to x[0] and the complementary
21+
// fraction to x[1]; a 1-element array would overflow (heap corruption)
22+
if (n_x < 2) {
2123
PyErr_Format(PyExc_ValueError,
22-
"The length of the parameter vector must of length 1. "
23-
"Arrays of length (%d) given",
24+
"The parameter vector must be at least of length 2 "
25+
"(x[0] fraction in, x[1] complementary fraction out). "
26+
"Array of length (%d) given",
2427
n_x);
2528
return 0.0;
2629
}

ext/python/Fit2x.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,9 @@ def __call__(
365365
"length 5 to specify the fixed state for all 6 model "
366366
"parameters."
367367
)
368-
x = np.zeros(1, dtype=np.float64)
368+
# x[0]: fraction of pattern 1 (in/out); x[1]: 1 - x[0] (output).
369+
# fit26 writes both - a 1-element array would overflow.
370+
x = np.zeros(2, dtype=np.float64)
369371
x[0] = initial_values[0]
370372
if self._verbose:
371373
print("Fitting")

test/python/decayfit/test_DecayFit26.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ def test_fit26(self):
6262
}
6363
fit26 = tttrlib.Fit26(**settings)
6464
x1 = 0.5
65-
x = np.array([x1])
65+
x = np.array([x1, 0.0]) # x[1] receives the complementary fraction
6666
fixed = np.array([0])
6767
r = fit26(
6868
data=data,

0 commit comments

Comments
 (0)