Skip to content

Conversation

christophpurrer
Copy link
Contributor

Summary:
Recently we saw use-after-free race condition where the ImageFetcher object was being destroyed while still registered as a UIManagerCommitHook.

The crash occurred in std::vector::size() at line 635 when accessing corrupted memory.
The root cause could be improper lifecycle management between ImageFetcher destruction and commit hook execution.

The fix here modifies UIManager::shadowTreeWillCommit() to create a stable snapshot by copying the commitHooks_ vector while holding the lock.

Changelog: [Internal]

Differential Revision: D82846245

@meta-cla meta-cla bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Sep 19, 2025
@facebook-github-bot
Copy link
Contributor

@christophpurrer has exported this pull request. If you are a Meta employee, you can view the originating diff in D82846245.

christophpurrer added a commit to christophpurrer/react-native-macos that referenced this pull request Sep 19, 2025
)

Summary:

Recently we saw `use-after-free race condition` where the ImageFetcher object was being destroyed while still registered as a UIManagerCommitHook.

The crash occurred in `std::vector::size()` at line 635 when accessing corrupted memory.
The root cause could be improper lifecycle management between ImageFetcher destruction and commit hook execution.

The fix here modifies `UIManager::shadowTreeWillCommit()` to create a stable snapshot by copying the commitHooks_ vector while holding the lock.

## Reason
- If a thread is iterating over `commitHooks_` with a `shared_lock`, and another thread acquires a `unique_lock` to modify the vector (add/remove), the iterator in the first thread can become invalid, leading to a crash (use-after-free or out-of-bounds).
- This can happen if the lock is not held for the entire duration of the read or write, or if the lock is not correctly used everywhere commitHooks_ is accessed.

Changelog: [Internal]

Differential Revision: D82846245
@facebook-github-bot
Copy link
Contributor

@christophpurrer has exported this pull request. If you are a Meta employee, you can view the originating diff in D82846245.

christophpurrer added a commit to christophpurrer/react-native-macos that referenced this pull request Sep 19, 2025
)

Summary:

Recently we saw `use-after-free race condition` where the ImageFetcher object was being destroyed while still registered as a UIManagerCommitHook.

The crash occurred in `std::vector::size()` at line 635 when accessing corrupted memory.
The root cause could be improper lifecycle management between ImageFetcher destruction and commit hook execution.

The fix here modifies `UIManager::shadowTreeWillCommit()` to create a stable snapshot by copying the commitHooks_ vector while holding the lock.

## Reason
- If a thread is iterating over `commitHooks_` with a `shared_lock`, and another thread acquires a `unique_lock` to modify the vector (add/remove), the iterator in the first thread can become invalid, leading to a crash (use-after-free or out-of-bounds).
- This can happen if the lock is not held for the entire duration of the read or write, or if the lock is not correctly used everywhere commitHooks_ is accessed.

Changelog: [Internal]

Differential Revision: D82846245
@facebook-github-bot
Copy link
Contributor

@christophpurrer has exported this pull request. If you are a Meta employee, you can view the originating diff in D82846245.

christophpurrer added a commit to christophpurrer/react-native-macos that referenced this pull request Sep 20, 2025
)

Summary:

Recently we saw `use-after-free race condition` where the ImageFetcher object was being destroyed while still registered as a UIManagerCommitHook.

The crash occurred in `std::vector::size()` at line 635 when accessing corrupted memory.
The root cause could be improper lifecycle management between ImageFetcher destruction and commit hook execution.

The fix here modifies `UIManager::shadowTreeWillCommit()` to create a stable snapshot by copying the commitHooks_ vector while holding the lock.

## Reason
- If a thread is iterating over `commitHooks_` with a `shared_lock`, and another thread acquires a `unique_lock` to modify the vector (add/remove), the iterator in the first thread can become invalid, leading to a crash (use-after-free or out-of-bounds).
- This can happen if the lock is not held for the entire duration of the read or write, or if the lock is not correctly used everywhere commitHooks_ is accessed.

Changelog: [Internal]

Differential Revision: D82846245
christophpurrer added a commit to christophpurrer/react-native-macos that referenced this pull request Sep 20, 2025
)

Summary:

Recently we saw `use-after-free race condition` where the ImageFetcher object was being destroyed while still registered as a UIManagerCommitHook.

The crash occurred in `std::vector::size()` at line 635 when accessing corrupted memory.
The root cause could be improper lifecycle management between ImageFetcher destruction and commit hook execution.

The fix here modifies `UIManager::shadowTreeWillCommit()` to create a stable snapshot by copying the commitHooks_ vector while holding the lock.

## Reason
- If a thread is iterating over `commitHooks_` with a `shared_lock`, and another thread acquires a `unique_lock` to modify the vector (add/remove), the iterator in the first thread can become invalid, leading to a crash (use-after-free or out-of-bounds).
- This can happen if the lock is not held for the entire duration of the read or write, or if the lock is not correctly used everywhere commitHooks_ is accessed.

Changelog: [Internal]

Differential Revision: D82846245
@facebook-github-bot
Copy link
Contributor

@christophpurrer has exported this pull request. If you are a Meta employee, you can view the originating diff in D82846245.

christophpurrer added a commit to christophpurrer/react-native-macos that referenced this pull request Sep 20, 2025
)

Summary:

Recently we saw `use-after-free race condition` where the ImageFetcher object was being destroyed while still registered as a UIManagerCommitHook.

The crash occurred in `std::vector::size()` at line 635 when accessing corrupted memory.
The root cause could be improper lifecycle management between ImageFetcher destruction and commit hook execution.

The fix here modifies `UIManager::shadowTreeWillCommit()` to create a stable snapshot by copying the commitHooks_ vector while holding the lock.

## Reason
- If a thread is iterating over `commitHooks_` with a `shared_lock`, and another thread acquires a `unique_lock` to modify the vector (add/remove), the iterator in the first thread can become invalid, leading to a crash (use-after-free or out-of-bounds).
- This can happen if the lock is not held for the entire duration of the read or write, or if the lock is not correctly used everywhere commitHooks_ is accessed.

Changelog: [Internal]

Differential Revision: D82846245
christophpurrer added a commit to christophpurrer/react-native-macos that referenced this pull request Sep 24, 2025
…mitHooks (facebook#53862)

Summary:

Recently, we observed a `use-after-free race condition` where the ImageFetcher object was destroyed while it was still registered as a UIManagerCommitHook.

The crash occurred in `std::vector::size()` at line 635 when accessing corrupted memory.

The root cause appears to be improper lifecycle management between ImageFetcher destruction and commit hook execution.

The issue seems to be that `UIManagerCommitHook*` are raw pointers. If we register or unregister them off the JS thread, we will encounter issues with the lifecycle management of the commit hooks.

Therefore, it is advisable to revert parts of this change: [https://github.com/facebook/react-native/pull/53491/files](https://github.com/facebook/react-native/pull/53491/files) and remove `UIManagerCommitHookManager`.

Alternatively, we can register or unregister the CommitHook by scheduling a task on the RuntimeScheduler and accessing the UIManagerBinding.


Changelog: [Internal]

Differential Revision: D82846245
@facebook-github-bot
Copy link
Contributor

@christophpurrer has exported this pull request. If you are a Meta employee, you can view the originating diff in D82846245.

christophpurrer added a commit to christophpurrer/react-native-macos that referenced this pull request Sep 24, 2025
…mitHooks (facebook#53862)

Summary:

Recently, we observed a `use-after-free race condition` where the ImageFetcher object was destroyed while it was still registered as a UIManagerCommitHook.

The crash occurred in `std::vector::size()` at line 635 when accessing corrupted memory.

The root cause appears to be improper lifecycle management between ImageFetcher destruction and commit hook execution.

The issue seems to be that `UIManagerCommitHook*` are raw pointers. If we register or unregister them off the JS thread, we will encounter issues with the lifecycle management of the commit hooks.

Therefore, it is advisable to revert parts of this change: [https://github.com/facebook/react-native/pull/53491/files](https://github.com/facebook/react-native/pull/53491/files) and remove `UIManagerCommitHookManager`.

Alternatively, we can register or unregister the CommitHook by scheduling a task on the RuntimeScheduler and accessing the UIManagerBinding.


Changelog: [Internal]

Differential Revision: D82846245
@facebook-github-bot
Copy link
Contributor

@christophpurrer has exported this pull request. If you are a Meta employee, you can view the originating diff in D82846245.

christophpurrer added a commit to christophpurrer/react-native-macos that referenced this pull request Sep 24, 2025
…mitHooks (facebook#53862)

Summary:

Recently, we observed a `use-after-free race condition` where the ImageFetcher object was destroyed while it was still registered as a UIManagerCommitHook.

The crash occurred in `std::vector::size()` at line 635 when accessing corrupted memory.

The root cause appears to be improper lifecycle management between ImageFetcher destruction and commit hook execution.

The issue seems to be that `UIManagerCommitHook*` are raw pointers. If we register or unregister them off the JS thread, we will encounter issues with the lifecycle management of the commit hooks.

Therefore, it is advisable to revert parts of this change: [https://github.com/facebook/react-native/pull/53491/files](https://github.com/facebook/react-native/pull/53491/files) and remove `UIManagerCommitHookManager`.

Alternatively, we can register or unregister the CommitHook by scheduling a task on the RuntimeScheduler and accessing the UIManagerBinding.


Changelog: [Internal]

Differential Revision: D82846245
@facebook-github-bot
Copy link
Contributor

@christophpurrer has exported this pull request. If you are a Meta employee, you can view the originating diff in D82846245.

…mitHooks (facebook#53862)

Summary:

Recently, we observed a `use-after-free race condition` where the ImageFetcher object was destroyed while it was still registered as a UIManagerCommitHook.

The crash occurred in `std::vector::size()` at line 635 when accessing corrupted memory.

The root cause appears to be improper lifecycle management between ImageFetcher destruction and commit hook execution.

The issue seems to be that `UIManagerCommitHook*` are raw pointers. If we register or unregister them off the JS thread, we will encounter issues with the lifecycle management of the commit hooks.

Therefore, it is advisable to revert parts of this change: [https://github.com/facebook/react-native/pull/53491/files](https://github.com/facebook/react-native/pull/53491/files) and remove `UIManagerCommitHookManager`.

Alternatively, we can register or unregister the CommitHook by scheduling a task on the RuntimeScheduler and accessing the UIManagerBinding.


Changelog: [Internal]

Differential Revision: D82846245
@facebook-github-bot
Copy link
Contributor

@christophpurrer has exported this pull request. If you are a Meta employee, you can view the originating diff in D82846245.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. fb-exported meta-exported p: Facebook Partner: Facebook Partner
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants