-
Notifications
You must be signed in to change notification settings - Fork 14.6k
fix(core): address memory leaks in oauth flow, chat history, and shell parsing #24963
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
Changes from all commits
200d240
9b0c10f
a58035a
a020164
e79064c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -108,6 +108,8 @@ export async function resolveExecutable( | |
| let bashLanguage: Language | null = null; | ||
| let treeSitterInitialization: Promise<void> | null = null; | ||
| let treeSitterInitializationError: Error | null = null; | ||
| let parserState: 'uninitialized' | 'initializing' | 'initialized' | 'error' = | ||
| 'uninitialized'; | ||
|
|
||
| class ShellParserInitializationError extends Error { | ||
| constructor(cause: Error) { | ||
|
|
@@ -163,16 +165,37 @@ async function loadBashLanguage(): Promise<void> { | |
| } | ||
|
|
||
| export async function initializeShellParsers(): Promise<void> { | ||
| if (!treeSitterInitialization) { | ||
| treeSitterInitialization = loadBashLanguage().catch((error) => { | ||
| treeSitterInitialization = null; | ||
| // Log the error but don't throw, allowing the application to fall back to safe defaults (ASK_USER) | ||
| // or regex checks where appropriate. | ||
| debugLogger.debug('Failed to initialize shell parsers:', error); | ||
| if (parserState === 'uninitialized') { | ||
| parserState = 'initializing'; | ||
| let timerId: NodeJS.Timeout | undefined; | ||
| const timeoutPromise = new Promise<void>((_, reject) => { | ||
| timerId = setTimeout( | ||
| () => reject(new Error('Tree-sitter initialization timed out')), | ||
| 30000, | ||
| ); | ||
| }); | ||
| treeSitterInitialization = Promise.race([ | ||
| loadBashLanguage(), | ||
| timeoutPromise, | ||
|
Comment on lines
+170
to
+179
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The setTimeout for tree-sitter initialization is not cleared if the operation succeeds, creating a memory leak. Also, the 5-second timeout might be too short for some environments, leading to premature failures. Furthermore, avoid using the treeSitterInitialization promise object itself to track operation state; use an explicit state variable instead. let timeoutId: NodeJS.Timeout | undefined;
const timeoutPromise = new Promise<void>((_, reject) => {
timeoutId = setTimeout(
() => reject(new Error('Tree-sitter initialization timed out')),
5000,
);
});
treeSitterInitialization = Promise.race([
loadBashLanguage(),
timeoutPromise,
])
.finally(() => {
if (timeoutId) clearTimeout(timeoutId);
})
.catch((error) => {References
|
||
| ]) | ||
| .finally(() => { | ||
| if (timerId) clearTimeout(timerId); | ||
| }) | ||
| .then(() => { | ||
| parserState = 'initialized'; | ||
| }) | ||
| .catch((error) => { | ||
| parserState = 'error'; | ||
| treeSitterInitialization = null; | ||
| // Log the error but don't throw, allowing the application to fall back to safe defaults (ASK_USER) | ||
| // or regex checks where appropriate. | ||
| debugLogger.debug('Failed to initialize shell parsers:', error); | ||
| }); | ||
| } | ||
|
|
||
| await treeSitterInitialization; | ||
| if (treeSitterInitialization) { | ||
| await treeSitterInitialization; | ||
| } | ||
| } | ||
|
|
||
| export interface ParsedCommandDetail { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While this change limits the history in the UI state, it does not address the unbounded growth in the ChatRecordingService itself, which was identified as the source of the ~350MB leak. The recordMessage method continues to append to an internal array without truncation. To resolve this, the messages state should be managed using the repository's standard LruCache implementation to prevent memory issues and ensure bounded growth. When implementing truncation, prefer a simple approach over complex logic if the inaccuracy is trivial.
References