stream: fix sync callback leak
This PR currently is mostly a suggestion to discuss related to https://github.com/nodejs/node/pull/31756. It's not properly cleaned up and is mostly to illustrate the problem and possible solution.
Today when working with callbacks and events we need to keep in mind ordering and whether or not a callback is invoked synchronously or asynchronously.
The current pattern for this is something like:
Stream.write = function (chunk) {
state.sync = true;
this._write(chunk, this._onWriteComplete);
state.sync = false;
}
Which mostly works fine. However, as in https://github.com/nodejs/node/pull/31756, if the callback is leaked outside it can still be invoked in the same tick breaking the assumption that when state.sync === false
a tick has elapsed.
i.e.
const s = new Stream();
let cb;
s._write = (chunk, callback) => {
cb = callback();
};
s.write('asd');
cb(); // uhoh! sync but the `Stream` thinks it's async.
s.on('someevent', common.mustCall()); // not called
This PR tries to resolve this by keeping track of which tick we are currently in and making sure that state.sync === false
always is a different tick.
Checklist
-
make -j4 test
(UNIX), orvcbuild test
(Windows) passes -
tests and/or benchmarks are included -
documentation is changed or added -
commit message follows commit guidelines