Skip to content

fix: fixed pc close/dispose race - #70

Merged
greenfrvr merged 2 commits into
masterfrom
pc-dispose-race
Sep 23, 2026
Merged

greenfrvr merged 2 commits into
masterfrom
pc-dispose-race

Conversation

@greenfrvr

@greenfrvr greenfrvr commented Sep 22, 2026 •

Copy link
Copy Markdown

A fix for a race, when peer-connection events were added to execution queue during disposal process, which lead to addressing already freed memory.

Implementation details

Previously, shutdown could happen in this order:

  1. WebRTC produces an event
  2. Event waits in the work queue
  3. App leaves → PeerConnection memory is freed
  4. Waiting event runs → touches freed memory → crash

This is a race condition as the result depends on unpredictable timing.

The PR changes shutdown to:

Close connection
↓
Process already queued events
↓
Dispose connection and free memory
↓
Dispose tracks and factory

It also adds several safety measures:

  • Rejects unfinished JavaScript operations with E_PC_DISPOSED instead of touching freed memory.
  • Queues factory creation and disposal operations, preventing a new call factory from being created while the previous one is still shutting down.
  • Makes repeated disposal safe instead of crashing.

@greenfrvr greenfrvr self-assigned this Sep 22, 2026
@coderabbitai

coderabbitai Bot commented Sep 22, 2026 •

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: df2374d9-b6fe-4040-9056-80876c4e09e2


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

A `createCallFactory()` queued during two-phase teardown can reuse a
factory that the pending teardown then destroys. Concurrent creates
replacing a bare-fork default can likewise destroy the first successful
create's factory. Queue factory lifecycle requests until teardown
completes, preserving request order and allowing peer-connection
callbacks to drain between phases.

Centralize the five success-callback disposal checks in
`runWithPeerConnection()`. The helper checks the connection inside the
executor task and passes it to the callback. Also share peer-connection
disposal, observer removal, and factory unbinding between the explicit
and factory teardown paths.

This draft targets `pc-dispose-race`, the branch of #70.

Validation:
- Android Java/Kotlin compilation passed with Gradle 9.4.1, AGP 9.2.1,
and React Native 0.87.0 using a temporary host project.
- Eight local JVM regression scenarios passed using the production
lifecycle methods, registry, and executor with native dependencies
stubbed: overlapping dispose/create, concurrent default replacement,
reference counts, FIFO request completion, close callback draining,
disposed/live callback handling, and cleanup after a PC disposal
exception.
- `git diff --check` passed.

The regression harness was local; no Android device runtime test was
performed.
@greenfrvr
greenfrvr merged commit 36956b9 into master Sep 23, 2026
6 checks passed
@greenfrvr
greenfrvr deleted the pc-dispose-race branch September 23, 2026 07:55
github-actions Bot pushed a commit that referenced this pull request Sep 23, 2026
## [145.3.3](v145.3.2...v145.3.3) (2026-09-23)

### Bug Fixes

* **android:** skip explicit Kotlin plugin when AGP registers the kotlin extension ([#67](#67)) ([5601e99](5601e99))
* fixed pc close/dispose race ([#70](#70)) ([36956b9](36956b9))
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 145.3.3 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants