Skip to content

Fix SIGSEGV from HDF5 library teardown and concurrent access - #13

Open
chraibi wants to merge 1 commit into
sir306:mainfrom
PedestrianDynamics:fix-hdf5-library-teardown
Open

Fix SIGSEGV from HDF5 library teardown and concurrent access#13
chraibi wants to merge 1 commit into
sir306:mainfrom
PedestrianDynamics:fix-hdf5-library-teardown

Conversation

@chraibi

@chraibi chraibi commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

Loading an HDF5 simulation could crash the editor outright:

LogHdf5SimulationReader: Error: Failed to open HDF5 file: .../mobius_ringed.h5
=== Critical error: ===
SIGSEGV: invalid attempt to access memory at address 0x20

Hdf5DataPlugin!H5P__access_class()
Hdf5DataPlugin!H5P_create_id()
Hdf5DataPlugin!H5T__init_package()
Hdf5DataPlugin!H5_init_library()
Hdf5DataPlugin!H5open()
Hdf5DataPlugin!FHdf5SimulationReader::OpenFile(FString const&)
ProjectMobius!FProcessSimulationDataRunnable::LoadAndDeserializeHDF5File()
ProjectMobius!FProcessSimulationDataRunnable::Run()
Core!FRunnableThreadPThread::Run()

Cause

Two independent problems combine:

1. H5close() is a process-wide shutdown, not a per-file close. It was called in three places — CloseFile(), OpenFile()'s error path, and DetectFormat(). Any reader finishing its work therefore demolished the HDF5 library for every other reader. In the crash above, one thread ran H5close() while the trajectory worker was still inside H5_init_library(), so the property-class table it was walking was freed underneath it.

2. The bundled HDF5 is not thread-safe. Plugins/Hdf5DataPlugin/Source/ThirdParty/hdf5-2.0.0/install/lib/libhdf5.settings reports Threadsafety: OFF, and the superbuild passes no HDF5_ENABLE_THREADSAFE. Two threads executing HDF5 code at once is undefined behaviour even when they are reading different files — and the geometry loader (FAssimpMeshLoaderRunnable) and the trajectory loader (FProcessSimulationDataRunnable) each open .h5 files on their own threads.

Change

  • Every public reader method takes a process-wide recursive critical section: OpenFile, CloseFile, DetectFormat, and the nine Read* methods. Recursive because OpenFile calls CloseFile internally.
  • All H5close() calls removed. The library now lives for the lifetime of the process, which is the normal way to use HDF5; H5Fclose(FileId) still releases each file.

Known trade-off: a geometry load and a trajectory load of the same file now queue rather than interleave. Ordered and slower beats concurrent and crashing. The alternative — rebuilding HDF5 with HDF5_ENABLE_THREADSAFE=ON — is a larger change and may conflict with HDF5_BUILD_HL_LIB=ON; worth considering separately if the serialization ever shows up as a bottleneck.

Verification

macOS, UE 5.5.4, 170 MB Juelich file (7.17M trajectory records, 516 entities): crashed reliably before, loads cleanly after, with geometry and trajectories read from the same file on different threads.

Note

Hdf5DataExampleTest.cpp still calls H5open()/H5close() directly. It is automation-test-only code and left untouched here to keep the change minimal, but running that test alongside a loaded simulation would reintroduce the same teardown hazard.

The bundled HDF5 is built without thread safety (Threadsafety: OFF in
libhdf5.settings), yet geometry and trajectory loading can read the same
.h5 concurrently from different threads. Worse, CloseFile(), OpenFile()'s
error path and DetectFormat() called H5close(), which shuts down the HDF5
library process-wide and crashes any reader that is mid-operation.

Observed as a SIGSEGV at address 0x20 when one thread ran H5close() while
another was still inside H5open():

  Hdf5DataPlugin!H5P__access_class -> H5P_create_id -> H5T_init
    -> H5_init_library -> H5open
  Hdf5DataPlugin!FHdf5SimulationReader::OpenFile
  ProjectMobius!FProcessSimulationDataRunnable::LoadAndDeserializeHDF5File

- Guard every public reader method with a process-wide recursive
  critical section.
- Remove all H5close() calls; the library now lives for the process.
  H5Fclose() still closes individual files.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR prevents editor crashes when loading HDF5 simulations by removing process-wide HDF5 shutdown calls (H5close) from the reader and serializing all HDF5 API usage in FHdf5SimulationReader to account for the bundled non-thread-safe HDF5 build.

Changes:

  • Introduces a process-wide critical section guard used by all public FHdf5SimulationReader methods that touch HDF5.
  • Removes H5close() calls from OpenFile() error paths, CloseFile(), and DetectFormat() so one reader cannot tear down the HDF5 library for the entire process.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +33 to +37
* The bundled HDF5 library is built without thread safety (Threadsafety: OFF in
* libhdf5.settings), so no two threads may execute HDF5 code concurrently.
* Geometry and trajectory loading both read the same .h5 from different threads,
* so every public reader method serializes on this process-wide lock.
* The lock is recursive on all UE platforms, so public methods may call each other.
sir306 added a commit that referenced this pull request Aug 14, 2026
HDF5 thread-safety (real fix, equivalent to PR #13 re-pathed to the
relocated MobiusDataImporter plugin):
- Add a process-wide recursive FCriticalSection guarding every public
  FHdf5SimulationReader method (OpenFile, CloseFile, DetectFormat, and
  the nine Read* methods). The bundled HDF5 is built Threadsafety: OFF,
  so geometry + trajectory loaders on separate threads must serialize.
- Remove all four H5close() calls. H5close() is a process-wide library
  teardown, not a per-file close; one thread calling it demolished the
  library under another mid-operation. H5Fclose(FileId) still releases
  each file; the library now lives for the process lifetime.

Font GC root (WIP, does NOT resolve the reported crash yet):
- AddToRoot the shared Font_Inter at its Slate load sites
  (SFieldAndTitleText::SetFieldFontFace, UIThemeSubsystem::GetInterFont)
  so a file-switch GC cannot collect it.
- The SIGSEGV at 0xdd... in FSlateFontInfo::GetCompositeFont during
  UStatisticSubsystem::ResetForFileSwitch still reproduces on
  consecutive .h5 loads. Now also reproduces on Windows; continuing
  the investigation there.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants