BUG: Fix silent-corruption defects in VTKImageIO read and write#6610
Conversation
|
| Filename | Overview |
|---|---|
| Modules/IO/VTK/src/itkVTKImageIO.cxx | Hardens VTK parsing and data reads, but the new keyword extraction rejects indented header lines that previously matched. |
| Modules/IO/VTK/test/CMakeLists.txt | Adds the new VTKImageIO GoogleTest source to the existing test driver. |
| Modules/IO/VTK/test/itkVTKImageIOGTest.cxx | Adds focused tests for malformed headers, short reads, tensor parse failures, precision, and CanReadFile behavior. |
Reviews (1): Last reviewed commit: "BUG: Check stream state after each ASCII..." | Re-trigger Greptile
708c4e2 to
11aeb00
Compare
|
First force-push ( |
|
Follow-up push = one review commit from a high-effort automated review: Intentional-strictness notes (not changed)
|
A truncated BINARY .vtk file left the tail of the pixel buffer unset instead of raising an error, since the read status was discarded. Addresses item B57 of InsightSoftwareConsortium#6575.
DIMENSIONS, SPACING, ORIGIN, and the VECTORS/SCALARS/TENSORS type tokens were scanned into uninitialized locals without checking how many fields sscanf actually filled, so an under-filled line sized or typed the image from indeterminate values. Addresses item B58 of InsightSoftwareConsortium#6575.
The header parser matched attribute keywords (SPACING, ORIGIN, VECTORS, COLOR_SCALARS, SCALARS, TENSORS) as substrings, so a SCALARS array whose name contained another keyword, such as "vector_field", was misparsed as that other attribute. Addresses item B59 of InsightSoftwareConsortium#6575.
The 16-digit precision set on the header stream did not carry over to the separate stream used to write pixel data, so ASCII output silently dropped to the default 6 significant digits. Addresses item B60 of InsightSoftwareConsortium#6575.
GetNextLine's premature-EOF exception propagated out of CanReadFile when the header was fewer than four lines, so a short .vtk file threw instead of yielding a plain false. Addresses item B62 of InsightSoftwareConsortium#6575.
ReadTensorBuffer kept one temp across all nine per-row extractions and never checked the stream, so a malformed or overflowing tensor field left failbit set and silently replayed the same stale value into every remaining component instead of failing. Addresses item B61 of InsightSoftwareConsortium#6575.
ReadHeaderSize now uses the same first-token attribute dispatch as InternalReadImageInformation, so the streamed-write header re-scan cannot stop at a different line (e.g. a FIELD array whose name merely contains "vector"). DIMENSIONS tokens are parsed as signed values and rejected when non-positive; %u silently wrapped negatives to huge sizes. The tensor test name now states the non-numeric-field fixture.
|
Force-push = plain rebase onto current main, folding the new GTest source into the |
85453ce to
b768a7d
Compare
Six defects in
VTKImageIO's reader and writer: truncated files read as success,sscanfresults ignored over uninitialized locals, substring-based attribute dispatch, ASCII precision loss, andCanReadFile()throwing. Addresses B57–B60, B62 of #6575 (and theReadTensorBuffersibling of B61).The six commits
VTKImageIO::Read()'s non-streaming binary path discardedReadBufferAsBinary()'sbool, so a truncated file returned partially-uninitialized pixels as success. The other call sites (inStreamReadBufferAsBinary/StreamWriteBufferAsBinary) already throw internally before returning false — distinct, untouched.sscanfcalls inInternalReadImageInformation()discarded their returned field count while writing into uninitialized locals, so a malformedDIMENSIONS 5line sized the image from indeterminate values. All six destinations are now zero-initialized and the field count is checked, throwing and naming the malformed line.color_scalars/scalarsnumCompalready had a default assigned before thesscanf— an undercount leaves a defined value there, so those are distinct and untouched.text.find("vector") < text.length()), soSCALARS vector_field floatmatched thevectorarm and was misparsed as a 3-component VECTORS line. Now dispatches on the line's first whitespace-delimited token.precision(16)on the header stream, but the pixel data went out through a second stream at the default 6 significant digits. The precision is now set on the stream that actually writes the pixels.GetNextLine()calls sat outsideCanReadFile()'s try block, so a.vtkfile shorter than four lines threw "Premature EOF" out through the IO factory.CanReadFile()must never throw; the calls moved inside.ReadTensorBuffer()has the identical defect B61 fixes inImageIOBase(see BUG: Check stream state after each ASCII component read #6609): aPrintType temphoisted outside the read loop with no stream check, so one bad field latches its stale value into every later component. Fixed here because it is the same defect family and lives in this file. Each of the nine per-tensor extractions now goes through a helper that zero-initializes a fresh value, extracts, and throws onis.fail()— including the redundant symmetric "skip" reads, which previously swallowed corruption silently.Sweep of the rest of the file for the same anchors turned up nothing else: the
os <<ASCII writes have no stale-latch failure mode, and the remaining.find()calls are single-purpose presence gates, not differentiated dispatch.Local validation
New GoogleTest
itkVTKImageIOGTest.cxx(the module had no GTest driver). Every fixture is synthesized byte-for-byte in the test body — no ExternalData added.TruncatedBinaryFileThrowsOnRead(B57)MalformedDimensionsLineThrows(B58)ScalarsNameContainingVectorSubstringParsesAsScalars(B59)AsciiWriteRetainsDoublePrecision(B60)EXPECT_NEARfailedCanReadFileReturnsFalseOnShortFile(B62)TensorOverflowingFieldThrowsOnRead(B61 sibling)ctest -R "VTKImageIO|VTIImageIO": 46/46 pass, no pre-existing test changed result.AI assistance