[UE 5.8.4][Editor][Mac] Crash: pthread rwlock init fails with EBUSY (16) copying Mass shared fragment values during a TEDS command flush

Summary

On macOS the editor crashes intermittently with “Assertion failed: Err == 0 [File:Runtime/Core/Public/HAL/PThreadsSharedMutex.h] [Line: 32] pthread_rwlock_init failed with error: 16” while TEDS (the EditorDataStorage plugin) flushes its commands into the editor’s Mass entity manager. It happens in about 1% of our automation runs: 3 crashes in 670 large suite runs in October, 9 crash reports in all since August, every one with the same assertion.

What Type of Bug are you experiencing?

Editor

Steps to Reproduce

Not deterministic; this is the shape that triggers it in our automation suite.

  1. Run the editor headless on macOS with an automation test that calls UWorld::CreateWorld(EWorldType::Game, false), UWorld::CreateWorld(EWorldType::PIE, false) and UWorld::CreateWorld(EWorldType::Editor, false), each with a world context, optionally spawning actors with registered components and selecting some of them with GEditor->SelectActor / SelectComponent.
  2. Destroy each world in the same frame with World->DestroyWorld(false) and GEngine->DestroyWorldContext(World), without a garbage collection.
  3. Let the editor tick. About once in a hundred runs of a suite of such tests, the editor crashes in the next frame’s TEDS / Mass editor tick with the assertion above.

Expected Result

The editor keeps running: TEDS’s command flush never asserts while building a Mass chunk.

Observed Result

The editor crashes in the next frame’s TEDS / Mass editor tick with:
Assertion failed: Err == 0 [File:Runtime/Core/Public/HAL/PThreadsSharedMutex.h] [Line: 32]
pthread_rwlock_init failed with error: 16

Affects Versions

5.8

Platform(s)

Mac

For crash reports, include your callstack

Symbolicated callstack (innermost first), from one of the reports:
FMassArchetypeSharedFragmentValues::FMassArchetypeSharedFragmentValues(const FMassArchetypeSharedFragmentValues&)
FMassArchetypeChunk::FMassArchetypeChunk(unsigned long, TArrayView<FInstancedStruct const, int>, FMassArchetypeSharedFragmentValues const&)
FMassArchetypeData::GetOrAddChunk(FMassArchetypeSharedFragmentValues const&, int&, int&)
FMassArchetypeData::MoveEntityToAnotherArchetype(FMassEntityHandle, FMassArchetypeData&, FMassArchetypeSharedFragmentValues const*)
FMassEntityManager::InternalAddFragmentListToEntity(FMassEntityHandle, UE::Mass::FElementBitSet const&)
FMassEntityManager::AddFragmentToEntity(FMassEntityHandle, TNotNull<UScriptStruct const*>, TFunctionRef<…>)
UEditorDataStorage::AddColumnData(unsigned long long, UScriptStruct const*, TFunctionRef<…>, …)
UE::Editor::DataStorage::FAdjacencyListBackedHierarchyAccess::SetParentRow(…)
UE::Editor::DataStorage::FEnvironment::FlushCommands()
UEditorDataStorage::FinalizePhase(UE::Editor::DataStorage::EQueryTickPhase, float)
TMulticastDelegateBase::Broadcast<…>(float)
FMassProcessingPhase::OnParallelExecutionDone(float)
UE::Mass::FProcessingQueue::FinalizeAsyncCleanup(…)

Other reports reach the same copy constructor through FMassEntityManager::FlushCommands under FMassEditorPhaseTickTask, through FMassEntityManager::AddTagToEntity, and through BatchChangeCompositionForEntities, all under the Mass editor tick.

Additional Notes

We measured that on macOS pthread_rwlock_init returns EBUSY only when the memory holds the image of a rwlock that is still LOCKED. Never-locked, unlocked, and contended-then-released locks all re-initialize with 0. So the chunk is being built over memory where a lock was left held: a lock moved or freed while held. One candidate is the HashLock inside a TArray of FMassArchetypeChunk, which TArray relocates bitwise. On Windows, SRWLock initialization would silently overwrite, so the same race may corrupt state there without asserting.

Every crash fired in the frame after a test destroyed its private world (UWorld::CleanupWorld in the log just before the assert).

Workaround: -ini:Engine:[ConsoleVariables]:TEDS.Enable=0 for automation runs. -DisablePlugins=EditorDataStorage does not work, because Dataflow and ChaosVD require the plugin and the engine loads it anyway.