Crash in FProceduralMeshSceneProxy::GetDynamicMeshElements() in Editor with async collision cooking enabled

We’re seeing a sporadic crash in FProceduralMeshSceneProxy::GetDynamicMeshElements() in the Editor when ejecting out of the player with F8, and it seems to be triggered by an issue in the collision visualization code in ProceduralMeshComponent with bUseAsyncCooking=true. What seems to be happening:

  • A mesh update is triggered on the ProceduralMeshComponent that requires updates to both the scene proxy and the collision data.
  • ProceduralMeshComponent (re)creates its scene proxy at end of frame, which caches a pointer to the current BodySetup object in a private member variable from ProcMeshBodySetup.
  • The async collision cook completes and UProceduralMeshComponent::FinishPhysicsAsyncCook() replaces the ProcMeshBodySetup reference with a pointer to a new UBodySetup object. Crucially, there is no path to update the reference in or replace the scene proxy.
  • No further updates to the ProceduralMeshComponent happen for a while, and the GC eventually purges the old UBodySetup object.
  • F8 eject -> crash when GetDynamicMeshElements() tries to access the old, dead UBodySetup object through its dangling pointer to render the collision visualization.

This is on 5.4.1 as our engine upgrade is in progress, but the relevant code appears the same at head revision in Main.

A potential local fix being considered is to have FinishPhysicsAsyncCook() queue a render call to update the reference in the scene proxy to the most up to date UBodySetup object -- we’re wondering if this is a good idea or if there is already a better fix in P4/GitHub available to pull.

[Attachment Removed]

Steps to Reproduce
We don’t have a solid repro, but the following elements seem required:

  • Running game in Play-in-Editor
  • ProceduralMeshComponent with bUseAsyncCooking=1
  • The PMC is updated over a couple of frames so that its scene proxy is created with a BodySetup reference, with another async collision update queued.
  • The PMC is then not updated again for some time.
  • F8 (eject) is used to view the world in the level editor, with Collision visualization enabled.

Repro rate is somewhat more reliable with -stompmalloc and gc.ForceCollectGarbageEveryFrame=1.

[Attachment Removed]

Hi Avery, and thank you for the investigation.

That makes sense, and I’ll get a bug raised on the public issue tracker shortly. Assumedly this won’t happen if the collision visualization isn’t enabled?

I’m unaware of any fixes in this area - I know there have been some reports, not directly the same as this one - but we’ve not been able to get a repro that we can action.

Let me reach out to the dev side and pool some knowledge

All the best

Geoff Stacey

Developer Relations

EPIC Games

[Attachment Removed]

That is awesome. Thanks Avery and I’ll try this out!

[Attachment Removed]

Hi Avery, could I get a quick check as to which visualisation system you are using?

[Attachment Removed]

Apologies Avery, I’ll get on this today!

Geoff

[Attachment Removed]

Hi Avery, I’ve been trying to get this reproing this morning, after this admittedly fell between the cracks, and I am struggling. Is this still a blocker for you folks?

Best

Geoff

[Attachment Removed]

Correct, it does not occur if the Collision visualization is disabled as that bypasses the problematic rendering path.

Attached is a min repro for the crash on stock 5.5.4. Run Editor with -stompmalloc, ensure Collision visualization is enabled, start PIE, F8 > crash. It’s not 100% due to async cook timing, but generally happens within 1-2 tries. The actor BP turns on GC-every-frame, then adds a couple of collision-enabled sections to a ProceduralMeshComponent with async cooking enabled, spaced a frame apart.

[Attachment Removed]

It is the standard Collision visualization in the level editor viewport’s Show menu.

[Image Removed]

[Attachment Removed]