fix callstack overflow of writeSync
This commit is contained in:
@@ -42,31 +42,55 @@ export class WriteBuffer {
|
||||
private _callbacks: ((() => void) | undefined)[] = [];
|
||||
private _pendingData = 0;
|
||||
private _bufferOffset = 0;
|
||||
private _isSyncWriting = false;
|
||||
private _syncCalls = 0;
|
||||
|
||||
constructor(private _action: (data: string | Uint8Array, promiseResult?: boolean) => void | Promise<boolean>) { }
|
||||
|
||||
/**
|
||||
* @deprecated Unreliable, to be removed soon.
|
||||
*/
|
||||
public writeSync(data: string | Uint8Array): void {
|
||||
public writeSync(data: string | Uint8Array, maxSubsequentCalls?: number): void {
|
||||
// stop writeSync recursions with maxSubsequentCalls argument
|
||||
// This is dangerous to use as it will lose the current data chunk
|
||||
// and return immediately.
|
||||
if (maxSubsequentCalls !== undefined && this._syncCalls > maxSubsequentCalls) {
|
||||
// comment next line if a whole loop block should only contain x `writeSync` calls
|
||||
// (total flat vs. deep nested limit)
|
||||
this._syncCalls = 0;
|
||||
return;
|
||||
}
|
||||
// append chunk to buffer
|
||||
this._pendingData += data.length;
|
||||
this._writeBuffer.push(data);
|
||||
this._callbacks.push(undefined);
|
||||
|
||||
// increase recursion counter
|
||||
this._syncCalls++;
|
||||
// exit early if another writeSync loop is active
|
||||
if (this._isSyncWriting) {
|
||||
return;
|
||||
}
|
||||
this._isSyncWriting = true;
|
||||
|
||||
// force sync processing on pending data chunks to avoid in-band data scrambling
|
||||
// does the same as innerWrite but without event loop
|
||||
if (this._writeBuffer.length) {
|
||||
for (let i = this._bufferOffset; i < this._writeBuffer.length; ++i) {
|
||||
const data = this._writeBuffer[i];
|
||||
const cb = this._callbacks[i];
|
||||
this._action(data);
|
||||
if (cb) cb();
|
||||
}
|
||||
// reset all to avoid reprocessing of chunks with scheduled innerWrite call
|
||||
this._writeBuffer = [];
|
||||
this._callbacks = [];
|
||||
this._pendingData = 0;
|
||||
// stop scheduled innerWrite by offset > length condition
|
||||
this._bufferOffset = 0x7FFFFFFF;
|
||||
// we have to do it here as single loop steps to not corrupt loop subject
|
||||
// by another writeSync call triggered from _action
|
||||
let chunk: string | Uint8Array | undefined;
|
||||
while (chunk = this._writeBuffer.shift()) {
|
||||
this._action(chunk);
|
||||
const cb = this._callbacks.shift();
|
||||
if (cb) cb();
|
||||
}
|
||||
// handle current data chunk
|
||||
this._action(data);
|
||||
// reset to avoid reprocessing of chunks with scheduled innerWrite call
|
||||
// stopping scheduled innerWrite by offset > length condition
|
||||
this._pendingData = 0;
|
||||
this._bufferOffset = 0x7FFFFFFF;
|
||||
|
||||
// allow another writeSync to loop
|
||||
this._isSyncWriting = false;
|
||||
this._syncCalls = 0;
|
||||
}
|
||||
|
||||
public write(data: string | Uint8Array, callback?: () => void): void {
|
||||
@@ -191,8 +215,8 @@ export class WriteBuffer {
|
||||
}
|
||||
setTimeout(() => this._innerWrite());
|
||||
} else {
|
||||
this._writeBuffer = [];
|
||||
this._callbacks = [];
|
||||
this._writeBuffer.length = 0;
|
||||
this._callbacks.length = 0;
|
||||
this._pendingData = 0;
|
||||
this._bufferOffset = 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user