BUG: Do fslio's size and offset arithmetic at 64-bit width - #73
hjmjohnson merged 2 commits into
Conversation
3fb47e3 to
267d71c
Compare
267d71c to
c5165f9
Compare
c5165f9 to
4e363e6
Compare
|
Rebased onto Message cleanupRemoved the Corrected one stale claim: the body said the same defect was "already fixed in Test and red proofAdded With the With the fix restored it passes. Worth recording: in a Release build the reverted code passes too. The Build and testConfigured with Follow-up for the maintainer, not fixed here. int offset;
offset = fslio->niftiptr->iname_offset +
vols * FslGetVolSize(fslio) * fslio->niftiptr->nbyper;Now that |
4e363e6 to
d0d5c2d
Compare
d0d5c2d to
3179ff6
Compare
A byte count or file offset is declared size_t, but the expression
assigned to it multiplies ints, so the arithmetic happens at 32 bits
and only the result is widened:
size_t FslGetVolSize(...)
{ return (nx * ny * nz); } /* int product */
offset = ((ydim * zVox + yVox) * xdim + xVox) * wordsize;
For a volume over 2GB the product overflows before it is ever assigned
to the size_t, so the destination type buys nothing. The signed
overflow is undefined, so whether the wide value survives is up to the
optimizer: clang folds it to the correct 64-bit result at -O2 and
yields 0 at -O0. Affects FslGetVolSize(), FslWriteVolumes(),
FslReadSliceSeries(), FslReadRowSeries() and FslReadTimeSeries().
Each operand is now widened before the multiply rather than after.
The slbytes and volbytes assignments in FslReadSliceSeries() and
FslReadTimeSeries() are left alone because another open pull request
changes those exact lines.
The test drives FslGetVolSize() with dimensions whose product exceeds INT_MAX and asserts the exact 64-bit value, plus a small volume so an over-broad change cannot pass it. It fails in a -O0 build without the widening fix and passes with it; at -O2 clang folds the signed overflow to the wide result, so only the unoptimized build observes it.
3179ff6 to
6ba8f4e
Compare
87b5264
into
InsightSoftwareConsortium:master
fsliocomputes buffer sizes and file offsets fromshortdimensions andintword sizes, so the products are evaluated inintand truncated before they are assigned to thesize_tthat holds them.FslGetVolSize()has the same shape. Each operand is now widened before the multiply, so the arithmetic happens at the width of the result.Split out of #52, which is otherwise mechanical cast work to silence
-Wshorten-64-to-32. This is the one real defect in that set, so it is worth reviewing on its own. #52 no longer contains it.Note
fsliolib/is behindUSE_FSL_CODE, which defaults to OFF, so the standard workflows do not compile it. Verified locally with-DUSE_FSL_CODE=ON; the test suite is unchanged.🤖 Generated with Claude Code