Skip to content

BUG: Fix GDCMImageIO::Write crash on unknown DICOM tags (supersedes #2553)#6185

Merged
hjmjohnson merged 2 commits intoInsightSoftwareConsortium:mainfrom
hjmjohnson:fix-gdcm-invalid-vrtype-crash
May 5, 2026
Merged

BUG: Fix GDCMImageIO::Write crash on unknown DICOM tags (supersedes #2553)#6185
hjmjohnson merged 2 commits intoInsightSoftwareConsortium:mainfrom
hjmjohnson:fix-gdcm-invalid-vrtype-crash

Conversation

@hjmjohnson
Copy link
Copy Markdown
Member

Fixes a process-terminating crash in GDCMImageIO::Write() when MetaDataDictionary contains a well-formed (group,element) key that is not in GDCM's public DICOM dictionary (private vendor tags, custom client-added tags, typos). Supersedes #2553. The first commit is the regression test (fails against main); the second commit is the fix.

Root cause

GDCMImageIO::Write() looks up each metadata key's VR via pubdict.GetDictEntry(tag).GetVR(). For tags missing from the public dictionary, the lookup returns gdcm::VR::INVALID. The downstream call to gdcm::StringFilter::FromString(tag, value, len) falls through to its switch(vr) default branch in gdcmStringFilter.cxx, which calls gdcm_assert(0) — terminating the host process.

Reproducer (in commit 1): create an itk::Image<unsigned short, 2>, populate metadata with a normal CT-style tag set, add EncapsulateMetaData<std::string>(dict, "9999|9999", "x"), write via ImageFileWriter. On unfixed main, the writer dies with gdcm::Exception "An invalid logic behavior occurred" (gdcmVR.cxx:263). On the fixed code the writer completes, the unknown tag is reported via the existing itkWarningMacro("ignoring non-DICOM and non-ITK standard keys = ...") channel, and all valid metadata + pixel data is written.

Why the original PR #2553 approach was insufficient

PR #2553 (mrc-sys, 2021-05-26) proposed elseelse if (vrtype != gdcm::VR::INVALID) inside the VRASCII branch, which suppresses the crash but constructs an empty gdcm::DataElement and inserts it into the DICOM header anyway. malaterre's CHANGES_REQUESTED review flagged this exact concern: "You're avoiding a segfault by hiding the symptoms. I suspect this creates an empty Data Element, this is not a desired behavior AFAIK."

This PR lifts the VR::INVALID check ahead of the per-VR dispatch and routes unknown tags through problematicKeys (the existing warning channel already used in this function for non-DICOM keys) — so no empty DataElement is ever constructed.

Files changed
Commit File Δ
1 (tests) Modules/IO/GDCM/test/itkGDCMImageIOInvalidVRTypeGTest.cxx new file, 2 TEST() cases
1 (tests) Modules/IO/GDCM/test/CMakeLists.txt first creategoogletestdriver() for the GDCM module + target_compile_definitions(ITK_TEST_OUTPUT_DIR=...)
1 (tests) Documentation/docs/releases/5.4.6.md unrelated pre-existing trailing-blank-line fix flagged by pre-commit run --all-files (introduced today by upstream 5.4.5 release-notes commit)
2 (fix) Modules/IO/GDCM/src/itkGDCMImageIO.cxx +11 −1 — the if (vrtype == gdcm::VR::INVALID) { problematicKeys.push_back(key); } branch, ahead of the per-VR dispatch
Local verification

Built ITKIOGDCMGTestDriver against ~/src/ITK/build at:

  1. Pre-fix (test sources + CMakeLists wiring only, source unchanged): bin/ITKIOGDCMGTestDriver --gtest_filter='GDCMImageIOInvalidVRType*' ⇒ first test crashes with gdcm::Exception "An invalid logic behavior occurred".
  2. Post-fix (full branch): same command ⇒ both tests PASS, warning emitted: WARNING: ... ignoring non-DICOM and non-ITK standard keys = 9999|9999.

pre-commit run --all-files exits 0 against the pushed HEAD.

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)
  • Added ITK examples for all new major features (if any)

@github-actions github-actions Bot added type:Bug Inconsistencies or issues which will cause an incorrect result under some or all circumstances type:Infrastructure Infrastructure/ecosystem related changes, such as CMake or buildbots type:Testing Ensure that the purpose of a class is met/the results on a wide set of test cases are correct area:IO Issues affecting the IO module area:Documentation Issues affecting the Documentation module labels May 1, 2026
@hjmjohnson hjmjohnson requested a review from malaterre May 1, 2026 22:45
Adds two regression tests that demonstrate the bug originally reported
in PR InsightSoftwareConsortium#2553: when MetaDataDictionary contains a key that parses as a
well-formed (group,element) DICOM tag but is not in GDCM's public
dictionary (e.g., a private vendor tag, or any custom tag added by
ITK clients without a private creator), GDCMImageIO::Write() looks up
its VR via gdcm::Dict::GetDictEntry(tag).GetVR() which returns
gdcm::VR::INVALID.  The downstream call to
gdcm::StringFilter::FromString hits the switch's default branch in
gdcmStringFilter.cxx, which calls gdcm_assert(0) and terminates the
process.

These two tests run against the unfixed code and reproduce the crash
(EXPECT_NO_THROW fails because the writer dies inside gdcm_assert(0)).
They are added in this separate commit so the bisection / regression
window is unambiguous.

The accompanying COMP commit lifts the gdcm::VR::INVALID detection out
of the per-VR dispatch in itkGDCMImageIO.cxx and routes unknown tags
through the existing problematicKeys warning channel, after which both
tests pass.

Adds the first creategoogletestdriver() entry to Modules/IO/GDCM/test/
CMakeLists.txt; subsequent gtests for this module can be appended to
ITKIOGDCMGTests.

Co-Authored-By: mrc-sys <65188023+mrc-sys@users.noreply.github.com>
@hjmjohnson hjmjohnson force-pushed the fix-gdcm-invalid-vrtype-crash branch from fb8351b to dae43f9 Compare May 2, 2026 00:22
@github-actions github-actions Bot removed the area:Documentation Issues affecting the Documentation module label May 2, 2026
@hjmjohnson
Copy link
Copy Markdown
Member Author

@greptileai review this draft before I make it official

@greptile-apps

This comment was marked as resolved.

Comment thread Modules/IO/GDCM/src/itkGDCMImageIO.cxx Outdated
GDCMImageIO::Write looks up each MetaDataDictionary entry's DICOM VR via
gdcm::Dict::GetDictEntry(tag).GetVR() against the public dictionary.
For tags that are not in the public dictionary (private vendor tags,
custom client-added tags, typos), the lookup returns gdcm::VR::INVALID.
The downstream call to gdcm::StringFilter::FromString in the VRASCII
branch hits the switch's default case in gdcmStringFilter.cxx and
calls gdcm_assert(0), terminating the host process.

PR InsightSoftwareConsortium#2553 (mrc-sys, 2021-05-26) proposed guarding the inner FromString
call only, but as Mathieu Malaterre noted in his CHANGES_REQUESTED
review, that approach silently writes an empty Data Element to the
DICOM header --- masking the symptom rather than fixing the underlying
issue.

Lift the VR::INVALID check ahead of the per-VR dispatch and route the
tag through the existing problematicKeys channel (already used in this
function for unrecognized non-DICOM keys).  The problematicKeys
accumulator emits a single warning at the end of the dictionary
iteration listing every unknown key, which is the same UX a typo or a
mis-encoded private tag has always produced for ITK clients --- now
extended to cover well-formed-(group,element)-but-unknown tags.

The two regression tests added in the preceding commit
(itkGDCMImageIOInvalidVRTypeGTest.cxx) which crashed against the
previous tip now complete cleanly and produce the expected warning.

Supersedes PR InsightSoftwareConsortium#2553.

Co-Authored-By: mrc-sys <65188023+mrc-sys@users.noreply.github.com>
@hjmjohnson hjmjohnson force-pushed the fix-gdcm-invalid-vrtype-crash branch from dae43f9 to 08f9fcd Compare May 2, 2026 16:43
@hjmjohnson hjmjohnson requested a review from zivy May 2, 2026 18:05
@hjmjohnson hjmjohnson marked this pull request as ready for review May 2, 2026 18:05
@hjmjohnson hjmjohnson added this to the ITK 6.0 Release Candidate 1 milestone May 5, 2026
Copy link
Copy Markdown
Member

@zivy zivy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@hjmjohnson hjmjohnson merged commit da54da4 into InsightSoftwareConsortium:main May 5, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:IO Issues affecting the IO module type:Bug Inconsistencies or issues which will cause an incorrect result under some or all circumstances type:Infrastructure Infrastructure/ecosystem related changes, such as CMake or buildbots type:Testing Ensure that the purpose of a class is met/the results on a wide set of test cases are correct

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants