Skip to content

[5.9][RemoteMirror] Fix demangle node corruption caused by excessively eager clearing of the NodeFactory. #64769

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

mikeash
Copy link
Contributor

@mikeash mikeash commented Mar 30, 2023

Cherry-pick #64674 to release/5.9.

We clear the NodeFactory to prevent unbounded buildup of allocated memory, but this is done too eagerly. In particular, normalizeReflectionName can end up clearing the factory while the calling code is still using nodes that were allocated from it.

To keep peak memory usage low while avoiding this problem, we introduce a checkpoint mechanism in NodeFactory. A checkpoint can be pushed and then subsequently popped. When a checkpoint is popped, only the nodes allocated since the checkpoint was pushed are invalidated and the memory reclaimed. This allows us to quickly clear short-lived nodes like those created in normalizeReflectionName, while preserving longer-lived nodes used in code calling it. Uses of clearNodeFactory are replaced with this checkpoint mechanism.

rdar://106547092

…y eager clearing of the NodeFactory.

We clear the NodeFactory to prevent unbounded buildup of allocated memory, but this is done too eagerly. In particular, normalizeReflectionName can end up clearing the factory while the calling code is still using nodes that were allocated from it.

To keep peak memory usage low while avoiding this problem, we introduce a checkpoint mechanism in NodeFactory. A checkpoint can be pushed and then subsequently popped. When a checkpoint is popped, only the nodes allocated since the checkpoint was pushed are invalidated and the memory reclaimed. This allows us to quickly clear short-lived nodes like those created in normalizeReflectionName, while preserving longer-lived nodes used in code calling it. Uses of clearNodeFactory are replaced with this checkpoint mechanism.

rdar://106547092
(cherry picked from commit fbc3f69)
@mikeash mikeash requested review from al45tair and tbkka March 30, 2023 14:27
@mikeash mikeash requested a review from a team as a code owner March 30, 2023 14:27
@mikeash
Copy link
Contributor Author

mikeash commented Mar 30, 2023

Explanation: The demangler uses an internal bump allocator which can be cleared between uses to prevent memory buildup. Remote Mirror sometimes clears the allocator too eagerly, when some nodes are still in use, resulting in corrupted node structures and crashes. This fixes the problem by adding a checkpoint system to the bump allocator, where it can be partically cleared back to the checkpoint. This allows code to use the demangler for temporary local tasks and then clear the memory used without affecting the caller's use of the demangler.
Scope: This fixes a crash then using Remote Mirror on certain processes with types that happen to take paths through Remote Mirror that hit this premature clearing.
Risk: Low. This change only affects Remote Mirror, so normal Swift apps are completely unaffected. The Remote Mirror changes should be well tested by our test suite.
Testing: Swift's standard PR testing and CI exercises this code well. It has also been tested with a type known to trigger the original problem, and the new code works correctly with it.

@mikeash
Copy link
Contributor Author

mikeash commented Mar 30, 2023

@swift-ci please test

@mikeash mikeash merged commit 61a7396 into swiftlang:release/5.9 Mar 30, 2023
@AnthonyLatsis AnthonyLatsis added the 🍒 release cherry pick Flag: Release branch cherry picks label May 3, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🍒 release cherry pick Flag: Release branch cherry picks
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants