Skip to content

Commit d92c1a8

Browse files
committed
Disallow writes to pty larger than 50
Fixes #38137
1 parent 4cd3ec3 commit d92c1a8

1 file changed

Lines changed: 39 additions & 1 deletion

File tree

src/vs/workbench/contrib/terminal/node/terminalProcess.ts

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@ import { findExecutable } from 'vs/workbench/contrib/terminal/node/terminalEnvir
1818
import { URI } from 'vs/base/common/uri';
1919
import { localize } from 'vs/nls';
2020

21+
// Writing large amounts of data can be corrupted for some reason, after looking into this is
22+
// appears to be a race condition around writing to the FD which may be based on how powerful the
23+
// hardware is. The workaround for this is to space out when large amounts of data is being written
24+
// to the terminal. See https://github.com/microsoft/vscode/issues/38137
25+
const WRITE_MAX_CHUNK_SIZE = 50;
26+
const WRITE_INTERVAL_MS = 5;
27+
2128
export class TerminalProcess extends Disposable implements ITerminalChildProcess {
2229
private _exitCode: number | undefined;
2330
private _exitMessage: string | undefined;
@@ -27,6 +34,8 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess
2734
private _processStartupComplete: Promise<void> | undefined;
2835
private _isDisposed: boolean = false;
2936
private _titleInterval: NodeJS.Timer | null = null;
37+
private _writeQueue: string[] = [];
38+
private _writeTimeout: NodeJS.Timeout | undefined;
3039
private readonly _initialCwd: string;
3140
private readonly _ptyOptions: pty.IPtyForkOptions | pty.IWindowsPtyForkOptions;
3241

@@ -232,8 +241,37 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess
232241
if (this._isDisposed || !this._ptyProcess) {
233242
return;
234243
}
244+
for (let i = 0; i <= Math.floor(data.length / WRITE_MAX_CHUNK_SIZE); i++) {
245+
this._writeQueue.push(data.substr(i * WRITE_MAX_CHUNK_SIZE, WRITE_MAX_CHUNK_SIZE));
246+
}
247+
this._startWrite();
248+
}
249+
250+
private _startWrite(): void {
251+
// Don't write if it's already queued of is there is nothing to write
252+
if (this._writeTimeout !== undefined || this._writeQueue.length === 0) {
253+
return;
254+
}
255+
256+
this._doWrite();
257+
258+
// Don't queue more writes if the queue is empty
259+
if (this._writeQueue.length === 0) {
260+
this._writeTimeout = undefined;
261+
return;
262+
}
263+
264+
// Queue the next write
265+
this._writeTimeout = setTimeout(() => {
266+
this._writeTimeout = undefined;
267+
this._startWrite();
268+
}, WRITE_INTERVAL_MS);
269+
}
270+
271+
private _doWrite(): void {
272+
const data = this._writeQueue.shift()!;
235273
this._logService.trace('IPty#write', `${data.length} characters`);
236-
this._ptyProcess.write(data);
274+
this._ptyProcess!.write(data);
237275
}
238276

239277
public resize(cols: number, rows: number): void {

0 commit comments

Comments
 (0)