Skip to content

Fence FFmpeg close cleanup by load generation - #142

Draft
Blackspirits wants to merge 1 commit into
audit/ffmpeg-session-self-reclaim-0882from
audit/ffmpeg-close-cleanup-generation-4edd
Draft

Blackspirits wants to merge 1 commit into
audit/ffmpeg-session-self-reclaim-0882from
audit/ffmpeg-close-cleanup-generation-4edd

Conversation

@Blackspirits

@Blackspirits Blackspirits commented Sep 15, 2026

Copy link
Copy Markdown
Owner

Purpose

Dependent owner-lifetime follow-up to #140 ("Reclaim FFmpeg sessions after late worker exit").

#139 fences late Session workers from publishing stale decoder/frame state, and #140 allows a timed-out Session to reclaim itself once its last worker exits. This audit found the inverse race in the owner's own CloseFile cleanup: an older CloseFile can finish after a newer load has already published state and erase that newer state.

Current upstream SubtitleEdit/subtitleedit main was rechecked at d6917286e355976da953d0ee22208b4bf9461699; no relevant drift or open upstream PR was found.

Finding fixed

CloseFile() previously did:

  1. increment _loadGeneration;
  2. detach the current Session;
  3. call session.Dispose();
  4. unconditionally clear _decoderName and _currentFrame.

#115/#140 deliberately allow Session teardown to wait on workers and, on timeout, retain resources safely. During that wait another LoadFile can run, create a newer generation and publish its own decoder badge/frame.

When the older CloseFile eventually resumes, its unconditional cleanup could then erase the new Session's owner-visible media state.

Fix

  • capture the generation created by this CloseFile;
  • after Session teardown, call TryClearOwnerMediaStateForGeneration(generation);
  • decoder/frame cleanup is accepted only if that generation is still current;
  • decoder clear, frame dispose/null and frame-version increment are ordered under the existing current-frame lock;
  • FrameReady fires only for accepted/current cleanup.

This mirrors #139's generation fence in the opposite direction: stale workers cannot publish forward, and stale closes cannot erase forward.

Regression coverage

A native-free test creates generation 1 media state and proves:

  • cleanup from generation 0 is rejected;
  • decoder badge, current frame and FrameVersion are unchanged;
  • cleanup from generation 1 succeeds;
  • decoder/frame state is cleared and FrameVersion increments exactly once.

Scope / branch state

  • dependency/base PR: Reclaim FFmpeg sessions after late worker exit #140
  • base HEAD: 4edde2ba42d0e81ce3d1504818eb13a3e7af606f
  • HEAD: 6cfde218dfd95e43e7e12077178e95b6969a57c4
  • 1 commit
  • 2 files
  • +42 / -6
  • current upstream main checked: d6917286e355976da953d0ee22208b4bf9461699
  • audit draft only; no merge/promotion intended

AI assistance: ChatGPT was used for adversarial concurrent CloseFile/LoadFile ordering review, owner-state generation fencing and focused frame/decoder regression design.

Final CI

Authoritative run: SubtitleEdit#281 on 6cfde218dfd95e43e7e12077178e95b6969a57c4

  • SeConv: 488 passed / 2 skipped / 0 failed
  • LibUiLogic: 905 passed / 0 skipped / 0 failed
  • LibSE: 2017 passed / 0 skipped / 0 failed
  • UI: 5241 passed / 9 skipped / 0 failed
  • build: 0 errors / 7 pre-existing warnings
  • retry step skipped
  • failure-artifact upload skipped

Final adversarial review was performed on this exact HEAD after CI; no blocker found.

@Blackspirits Blackspirits left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Final adversarial review on 6cfde218dfd95e43e7e12077178e95b6969a57c4 after CI SubtitleEdit#281: no blocker found. The close-generated load generation is captured before teardown wait; owner cleanup is rejected after a replacement load advances generation; accepted cleanup orders decoder/frame clear and frame-version increment under the current-frame lock; FrameReady is emitted only for accepted cleanup. No merge/promotion performed.

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.

1 participant