Skip to content

Update metaio release 5.4 - #6836

Closed
blowekamp wants to merge 2 commits into
InsightSoftwareConsortium:release-5.4from
blowekamp:update_metaio-release-5.4
Closed

Update metaio release 5.4#6836
blowekamp wants to merge 2 commits into
InsightSoftwareConsortium:release-5.4from
blowekamp:update_metaio-release-5.4

Conversation

@blowekamp

Copy link
Copy Markdown
Member

PR Checklist

  • No API changes were made (or the changes have been approved)
  • No major design changes were made (or the changes have been approved)
  • Added test (or behavior not changed)
  • Updated API documentation (or API not changed)
  • Added license to new files (if any)
  • Added Python wrapping to new files (if any) as described in ITK Software Guide Section 9.5
  • Added ITK examples for all new major features (if any)

Refer to the ITK Software Guide for
further development details if necessary.

MetaIO Maintainers and others added 2 commits September 4, 2026 09:14
Code extracted from:

    https://github.com/Kitware/MetaIO.git

at commit 1755773c8d678c5c9a57999c8ec373703134c0e2 (master).
# By MetaIO Maintainers
* upstream-MetaIO:
  MetaIO 2026-09-04 (1755773c)
@github-actions github-actions Bot added type:Infrastructure Infrastructure/ecosystem related changes, such as CMake or buildbots area:ThirdParty Issues affecting the ThirdParty module labels Sep 4, 2026
@blowekamp

Copy link
Copy Markdown
Member Author

@dzenanz There are more changes than I was hoping there were.

@greptile-apps

greptile-apps Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This MetaIO update introduces correctness regressions in Windows shared-library exports, default spatial transforms for supported 10-dimensional objects, corrupt MetaArray handling, scene-object dispatch, and filename-based version state.

T-Rex validation blocked

The focused MetaArray fixture could not be completed in the available standalone setup. The focused scene-dispatch reproduction could not compile because generated MetaIO and ITK ZLIB headers are unavailable in this checkout.

Confidence Score: 1/5

Not safe to merge: shared Windows builds, corrupt-file handling, scene object dispatch, and version-dependent behavior can fail until the identified fixes are applied. The ten-dimensional transform issue is non-blocking but should also be corrected.

Four likely correctness failures affect library construction, data loading, scene parsing, or version state. A separate lower-impact transform-default failure was reproduced for the supported ten-dimensional boundary.

Files Needing Attention: Modules/ThirdParty/MetaIO/src/MetaIO/src/localMetaConfiguration.h; Modules/ThirdParty/MetaIO/src/MetaIO/src/metaObject.cxx; Modules/ThirdParty/MetaIO/src/MetaIO/src/metaArray.cxx; Modules/ThirdParty/MetaIO/src/MetaIO/src/metaScene.cxx; Modules/ThirdParty/MetaIO/src/MetaIO/src/metaObject.h

T-Rex T-Rex Logs

What T-Rex did

  • T-Rex produced a proof for the posted P1 finding and attached artifacts detailing the Windows export macro reproduction, the current export macro expansion, the corrected export macro expansion, and the ITKMetaIO target definition inspection.
  • T-Rex produced a proof for the posted P2 finding and attached artifacts showing the source and script for the 10D transform reproduction and the current and corrected 10D transform results.
  • T-Rex produced a proof for the posted P1 filename-constructor version reproduction, documenting the current and initialized results of the filename-constructor test.
  • T-Rex documented a blocked validation path with fixture setup failures for the MetaArray and scene-dispatch repros, including the truncated MetaArray reproduction and the initial and revised scene-dispatch build outputs.
  • T-Rex produced a proof for the posted P2 finding.

View all artifacts

T-Rex Ran code and verified through T-Rex

Comments Outside Diff (2)

  1. Modules/ThirdParty/MetaIO/src/MetaIO/src/metaArray.cxx, line 654-675 (link)

    P1 Propagate element read failures

    The new decompression and short-read checks return false from M_ReadElements, but the local-data call here and the external-data call at line 675 discard that result. A truncated or corrupt MetaArray can consequently report a successful read while exposing incomplete or invalid element data. Return failure from both paths when element reading fails.

  2. General comment

    P2 Ten-dimensional MetaObject defaults to a zero transform

    • Bug
      • MetaObject(10) and the no-TransformMatrix read path produce a 10×10 matrix with every diagonal entry equal to 0, despite TransformMatrix being the optional physical orientation field and lower dimensions receiving an identity default.
    • Cause
      • Clear() initializes spacing, transform diagonal, and orientation only when m_NDims < 10; exactly 10 is allowed by InitializeEssential(). The read flow calls InitializeEssential(m_NDims) and then Clear(), which clears the just-created identity for NDims = 10.
    • Fix
      • Change if (m_NDims < 10) at Modules/ThirdParty/MetaIO/src/MetaIO/src/metaObject.cxx:1140 to if (m_NDims <= 10), and add a regression test covering direct 10-D construction plus reading a NDims = 10 MetaObject file with no TransformMatrix field.

    T-Rex Ran code and verified through T-Rex

Reviews (1): Last reviewed commit: "Merge branch 'upstream-MetaIO' into upda..." | Re-trigger Greptile

Comment on lines +38 to +42
# ifdef metaio_EXPORTS
# define METAIO_EXPORT __declspec(dllexport)
# define METAIO_EXTERN
# else
# define METAIO_EXPORT __declspec(dllimport)

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.

P1 Export ITKMetaIO symbols

In Windows shared builds, ITKMetaIO receives the target definition ITKMetaIO_EXPORTS, but this branch checks metaio_EXPORTS. The condition is therefore false while compiling the library itself, causing its public declarations to use __declspec(dllimport) instead of __declspec(dllexport). This prevents the shared library from exporting its API correctly; test ITKMetaIO_EXPORTS here or configure the target export definition consistently.

Knowledge Base Used: Module build and distribution system

Artifacts

Windows export macro reproduction

  • The script preprocesses the header with the ITK shared-library target definitions and compares the current and corrected export macro expansions.

Current export macro expansion

  • The current header expands the public API macro to a DLL import declaration while compiling the library.

Corrected export macro expansion

  • Changing the tested definition to the ITKMetaIO target definition expands the public API macro to a DLL export declaration.

ITKMetaIO target definition inspection

  • The inspected CMake configuration shows that the ITK build target is named ITKMetaIO, establishing the expected target export definition.

View artifacts

T-Rex Ran code and verified through T-Rex

Comment on lines +1140 to 1148
if (m_NDims < 10)
{
m_ElementSpacing[i] = 1;
m_AnatomicalOrientation[i] = MET_ORIENTATION_UNKNOWN;
for (int i = 0; i < m_NDims; i++)
{
m_ElementSpacing[i] = 1;
m_TransformMatrix[i * m_NDims + i] = 1;
m_AnatomicalOrientation[i] = MET_ORIENTATION_UNKNOWN;
}
}

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.

P2 Initialize 10D transforms

Exactly 10 dimensions are supported, but this condition skips identity initialization at that boundary. Constructing a 10-dimensional object, or reading one without a TransformMatrix, leaves its transform diagonal as zero instead of the default identity matrix. This is a non-blocking metadata correctness concern, but it produces invalid spatial metadata for supported 10D objects.

Suggested change
if (m_NDims < 10)
{
m_ElementSpacing[i] = 1;
m_AnatomicalOrientation[i] = MET_ORIENTATION_UNKNOWN;
for (int i = 0; i < m_NDims; i++)
{
m_ElementSpacing[i] = 1;
m_TransformMatrix[i * m_NDims + i] = 1;
m_AnatomicalOrientation[i] = MET_ORIENTATION_UNKNOWN;
}
}
for (int i = 0; i < m_NDims; i++)
{
m_ElementSpacing[i] = 1;
m_TransformMatrix[i * m_NDims + i] = 1;
m_AnatomicalOrientation[i] = MET_ORIENTATION_UNKNOWN;
}
Artifacts

Evidence from the check

  • The C++ test constructs a 10-D MetaObject and reads a minimal 10-D header without TransformMatrix, checking every diagonal value; it directly exercises the claimed paths.

Evidence from the check

  • The shell command compiles the authored test against current source and a one-condition corrected source copy, then runs both; it produces an executable before-and-after comparison.

Current-source 10D transform result

  • The executed current-source test exits 1 and records zeros for all ten construction and read-path diagonal entries; it confirms the reported defect.

Corrected 10D transform result

  • The executed one-condition corrected-source test exits 0 and records ones for all ten construction and read-path diagonal entries; it confirms the proposed boundary fix resolves the defect.

View artifacts

T-Rex Ran code and verified through T-Rex

Comment on lines +169 to 205
if (objectType.find("Tube") != std::string::npos || ((objectType.empty()) && !strcmp(suf, "tre")))
{
char * subtype = MET_ReadSubType(*m_ReadStream);
if (!strncmp(subtype, "Vessel", 6))
const std::string subtype = MET_ReadSubType(*m_ReadStream);
if (subtype.find("Vessel") != std::string::npos)
{
auto * vesseltube = new MetaVesselTube();
vesseltube->APIVersion(m_APIVersion);
vesseltube->SetEvent(m_Event);
vesseltube->ReadStream(m_NDims, m_ReadStream);
m_ObjectList.push_back(vesseltube);
}
else if (!strncmp(subtype, "DTI", 3))
else if (subtype.find("DTI") != std::string::npos)
{
auto * dtitube = new MetaDTITube();
dtitube->APIVersion(m_APIVersion);
dtitube->SetEvent(m_Event);
dtitube->ReadStream(m_NDims, m_ReadStream);
m_ObjectList.push_back(dtitube);
}
else
{
auto * tube = new MetaTube();
tube->APIVersion(m_APIVersion);
tube->SetEvent(m_Event);
tube->ReadStream(m_NDims, m_ReadStream);
m_ObjectList.push_back(tube);
}
delete[] subtype;
}

else if (!strncmp(objectType.c_str(), "Transform", 9))
else if (objectType.find("Transform") != std::string::npos)
{
auto * transform = new MetaTransform();
transform->APIVersion(m_APIVersion);
transform->SetEvent(m_Event);
transform->ReadStream(m_NDims, m_ReadStream);
m_ObjectList.push_back(transform);
}

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.

P1 Preserve scene object types

The generic Tube and Transform substring checks run before the TubeGraph and AffineTransform cases. TubeGraph is therefore constructed as MetaTube, and AffineTransform as MetaTransform, so callers receive objects of the wrong class from otherwise valid scenes. Check specific types first or restore exact or prefix matching.

Comment on lines +68 to +69
unsigned int m_FileFormatVersion;
unsigned int m_APIVersion;

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.

P1 Initialize API version state

The filename constructor calls Read() before initializing these new scalar members. The read path sets the file-format version but never assigns m_APIVersion, leaving it indeterminate after a successful read; later version-dependent behavior can therefore branch unpredictably. Give both members in-class defaults, or initialize them before reading.

Suggested change
unsigned int m_FileFormatVersion;
unsigned int m_APIVersion;
unsigned int m_FileFormatVersion{};
unsigned int m_APIVersion{};
Artifacts

Filename constructor version reproduction

  • The C++ reproduction constructs MetaObject from a valid file after patterned initialization and records both version values.

Version reproduction runner

  • The script builds and runs the version reproduction against the current implementation and an initialized comparison copy.

Current filename-constructor version result

  • The current implementation reports a successful read while retaining the patterned API-version value.

Initialized filename-constructor version result

  • Initializing both version members before reading produces the deterministic API-version value of zero.

View artifacts

T-Rex Ran code and verified through T-Rex

@@ -46,9 +49,10 @@ MetaObject::MetaObject()
MetaObject::MetaObject(const char * _fileName)

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.

P1 Initialize read versions

  • Bug
    • The filename constructor calls Read() before initializing the newly added version members. M_Read() resets m_FileFormatVersion, but no read path assigns m_APIVersion. A successfully read object therefore retains an indeterminate API version, so deprecated-API checks can branch unpredictably.
  • Cause
    • m_FileFormatVersion and m_APIVersion have no in-class initializer; MetaObject(const char *) does not assign either before Read(), and M_Read() only assigns m_FileFormatVersion.
  • Fix
    • Initialize both members before MetaObject::Read(_fileName), or add in-class default initializers. m_APIVersion needs an explicit default because no file field supplies it.

T-Rex Ran code and verified through T-Rex

@dzenanz

dzenanz commented Sep 4, 2026

Copy link
Copy Markdown
Member

Agreed. Let's close this, and merge the small patch from #6834.

@blowekamp

Copy link
Copy Markdown
Member Author

Abandoning in favor of just the minimal fix.

@blowekamp blowekamp closed this Sep 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:ThirdParty Issues affecting the ThirdParty module type:Infrastructure Infrastructure/ecosystem related changes, such as CMake or buildbots

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants