Skip to content

BUG: Remove unnecessary global fflush(nullptr) causing MetaIO read deadlocks (release-5.4 backport) - #6834

Merged
dzenanz merged 1 commit into
InsightSoftwareConsortium:release-5.4from
blowekamp:backport-metaio-fflush-concurrency-deadlock-5.4
Sep 4, 2026
Merged

BUG: Remove unnecessary global fflush(nullptr) causing MetaIO read deadlocks (release-5.4 backport)#6834
dzenanz merged 1 commit into
InsightSoftwareConsortium:release-5.4from
blowekamp:backport-metaio-fflush-concurrency-deadlock-5.4

Conversation

@blowekamp

Copy link
Copy Markdown
Member

Summary

Backport of #6833 to release-5.4.

MetaObject::ReadStream() and MetaForm::ReadStream() unconditionally call fflush(nullptr) before parsing header fields. This line dates back to MetaIOs very first file-IO commit, long before multithreading was a design concern for this library.

fflush(NULL) flushes every open FILE* stream in the entire process, not just the one being read. On platforms such as macOS, this requires walking the process-wide list of all open FILE* streams and locking each one in turn (_fwalk -> sflush_locked -> flockfile).

Under heavy concurrent MetaImage/.mha reads (many threads, each opening/reading/closing its own file), this global flush-all creates severe lock contention: every threads fflush(nullptr) call competes to lock every other threads in-flight FILE* handle. In practice this can grind concurrent reads to a halt indefinitely (observed via a native C++ gtest reproducer with 70+ threads reading distinct .mha files concurrently; lldb backtraces showed the large majority of threads parked in flockfile/sflush_locked/_fwalk called from MetaObject::ReadStream).

Reading a file does not require flushing any previously written data (nothing was just written), so this call serves no purpose and can simply be removed.

Test plan

  • The native C++ gtest reproducer used to validate the fix on main (BUG: Remove unnecessary global fflush(nullptr) causing MetaIO read deadlocks #6833) confirmed both the hang and the fix against the current main sources.
  • Not separately rebuilt/retested against this release-5.4 branch specifically; the affected code in metaObject.cxx/metaForm.cxx is unchanged between main and release-5.4, so the same root cause and fix apply, but this backport has not yet been independently verified on this branch.

…adlocks

MetaObject::ReadStream() and MetaForm::ReadStream() unconditionally call
fflush(nullptr) before parsing, a leftover from the original MetaIO commit
that predates any multithreading concerns for this library. fflush(NULL)
flushes every open FILE* stream in the entire process, not just the one
being read.

On platforms such as macOS, this requires walking the process-wide list of
all open FILE* streams and locking each one in turn. Under heavy concurrent
MetaImage/MHA reads (many threads each opening/reading/closing their own
files), this global flush-all creates severe lock contention that can grind
concurrent reads to a halt indefinitely, since each thread's fflush(nullptr)
call competes to lock every other thread's in-flight FILE* handle.

Reading does not require flushing any previously written data, so this call
serves no purpose and can simply be removed.

Backport of the same fix on main (PR InsightSoftwareConsortium#6833).
@github-actions github-actions Bot added type:Bug Inconsistencies or issues which will cause an incorrect result under some or all circumstances area:ThirdParty Issues affecting the ThirdParty module labels Sep 3, 2026
@greptile-apps

greptile-apps Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This change removes process-wide fflush(nullptr) calls from the MetaIO object and form read paths, avoiding unnecessary global stdio flushing during concurrent reads.

Focused native execution compiled and ran the same valid-header regression against the base revision and this revision. Filename-based and stream-based reads for both MetaObject and MetaForm completed successfully and produced the expected parsed fields in both versions. No defects were found.

Confidence Score: 5/5

Safe to merge based on focused base-to-head parsing checks and the narrowly scoped removal of global flush calls.

The modified read paths were exercised through both file and stream APIs for MetaObject and MetaForm, with identical successful behavior before and after the change.

Files Needing Attention: No files need further attention.

T-Rex T-Rex Logs

What T-Rex did

  • I ran the focused MetaIO parsing regression script against the base revision e125751 and observed PASS valid MetaIO headers on both parsing paths with exit code 0.
  • I ran the same script against the head revision 183f394 and observed PASS valid MetaIO headers on both parsing paths with exit code 0.
  • The regression harness exercised MetaObject::Read, MetaObject::ReadStream, MetaForm::Read, and MetaForm::ReadStream with valid headers and verified parsed field values, and the results matched between revisions, indicating that removing the global flush preserved parsing behavior.
  • I confirmed that no tracked project files were modified and that the authored harness and runner are untracked artifacts only.
  • I collected and linked artifacts including the focused MetaIO parsing regression source, the standalone MetaIO build and run script, and the base/head parsing run logs for reviewer inspection.

View all artifacts

T-Rex Ran code and verified through T-Rex

Reviews (1): Last reviewed commit: "BUG: Remove unnecessary global fflush(nu..." | Re-trigger Greptile

@blowekamp

Copy link
Copy Markdown
Member Author

Should metaio be updated from upstream or just patched like this for the release branch?

@dzenanz

dzenanz commented Sep 4, 2026

Copy link
Copy Markdown
Member

Good question, which I thought about too. There should not a lot of changes in it, so probably update MetaIO.

@dzenanz dzenanz mentioned this pull request Sep 4, 2026
7 tasks
@dzenanz
dzenanz merged commit a6202b3 into InsightSoftwareConsortium:release-5.4 Sep 4, 2026
17 checks passed
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:Bug Inconsistencies or issues which will cause an incorrect result under some or all circumstances

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants