fs: do not crash when using a closed fs event watcher · nodejs/node@c09bfd8
@@ -100,7 +100,11 @@ function FSWatcher() {
100100// after the handle is closed, and to fire both UV_RENAME and UV_CHANGE
101101// if they are set by libuv at the same time.
102102if (status < 0) {
103-this._handle.close();
103+if (this._handle !== null) {
104+// We don't use this.close() here to avoid firing the close event.
105+this._handle.close();
106+this._handle = null; // make the handle garbage collectable
107+}
104108const error = errors.uvException({
105109errno: status,
106110syscall: 'watch',
@@ -120,13 +124,17 @@ util.inherits(FSWatcher, EventEmitter);
120124// 1. Throw an Error if it's the first time .start() is called
121125// 2. Return silently if .start() has already been called
122126// on a valid filename and the wrap has been initialized
127+// 3. Return silently if the watcher has already been closed
123128// This method is a noop if the watcher has already been started.
124129FSWatcher.prototype.start = function(filename,
125130persistent,
126131recursive,
127132encoding) {
133+if (this._handle === null) { // closed
134+return;
135+}
128136assert(this._handle instanceof FSEvent, 'handle must be a FSEvent');
129-if (this._handle.initialized) {
137+if (this._handle.initialized) { // already started
130138return;
131139}
132140@@ -148,13 +156,18 @@ FSWatcher.prototype.start = function(filename,
148156}
149157};
150158151-// This method is a noop if the watcher has not been started.
159+// This method is a noop if the watcher has not been started or
160+// has already been closed.
152161FSWatcher.prototype.close = function() {
162+if (this._handle === null) { // closed
163+return;
164+}
153165assert(this._handle instanceof FSEvent, 'handle must be a FSEvent');
154-if (!this._handle.initialized) {
166+if (!this._handle.initialized) { // not started
155167return;
156168}
157169this._handle.close();
170+this._handle = null; // make the handle garbage collectable
158171process.nextTick(emitCloseNT, this);
159172};
160173