src: make FSEventWrap/StatWatcher::Start more robust

PR-URL: https://github.com/nodejs/node/pull/17432
Fixes: https://github.com/nodejs/node/issues/17430
Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
Timothy Gu 2017-12-02 18:37:56 -08:00 committed by Anna Henningsen
parent 11ebaff15c
commit cd71fc1545
No known key found for this signature in database
GPG Key ID: 9C63F3A6CD2AD8F9
4 changed files with 35 additions and 23 deletions

View File

@ -111,7 +111,8 @@ void FSEventWrap::Start(const FunctionCallbackInfo<Value>& args) {
FSEventWrap* wrap; FSEventWrap* wrap;
ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
CHECK_EQ(wrap->initialized_, false); if (wrap->initialized_)
return args.GetReturnValue().Set(0);
static const char kErrMsg[] = "filename must be a string or Buffer"; static const char kErrMsg[] = "filename must be a string or Buffer";
if (args.Length() < 1) if (args.Length() < 1)

View File

@ -111,9 +111,15 @@ void StatWatcher::Start(const FunctionCallbackInfo<Value>& args) {
const bool persistent = args[1]->BooleanValue(); const bool persistent = args[1]->BooleanValue();
const uint32_t interval = args[2]->Uint32Value(); const uint32_t interval = args[2]->Uint32Value();
if (!persistent) if (uv_is_active(reinterpret_cast<uv_handle_t*>(wrap->watcher_)))
return;
// Safe, uv_ref/uv_unref are idempotent.
if (persistent)
uv_ref(reinterpret_cast<uv_handle_t*>(wrap->watcher_));
else
uv_unref(reinterpret_cast<uv_handle_t*>(wrap->watcher_)); uv_unref(reinterpret_cast<uv_handle_t*>(wrap->watcher_));
uv_fs_poll_start(wrap->watcher_, Callback, *path, interval); uv_fs_poll_start(wrap->watcher_, Callback, *path, interval);
wrap->ClearWeak(); wrap->ClearWeak();
} }

View File

@ -64,6 +64,8 @@ for (const testCase of cases) {
assert.strictEqual(eventType, 'change'); assert.strictEqual(eventType, 'change');
assert.strictEqual(argFilename, testCase.fileName); assert.strictEqual(argFilename, testCase.fileName);
watcher.start(); // should not crash
// end of test case // end of test case
watcher.close(); watcher.close();
})); }));

View File

@ -52,27 +52,30 @@ common.refreshTmpDir();
// time, the callback should be invoked again with proper values in stat object // time, the callback should be invoked again with proper values in stat object
let fileExists = false; let fileExists = false;
fs.watchFile(enoentFile, { interval: 0 }, common.mustCall(function(curr, prev) { const watcher =
if (!fileExists) { fs.watchFile(enoentFile, { interval: 0 }, common.mustCall((curr, prev) => {
// If the file does not exist, all the fields should be zero and the date if (!fileExists) {
// fields should be UNIX EPOCH time // If the file does not exist, all the fields should be zero and the date
assert.deepStrictEqual(curr, expectedStatObject); // fields should be UNIX EPOCH time
assert.deepStrictEqual(prev, expectedStatObject); assert.deepStrictEqual(curr, expectedStatObject);
// Create the file now, so that the callback will be called back once the assert.deepStrictEqual(prev, expectedStatObject);
// event loop notices it. // Create the file now, so that the callback will be called back once the
fs.closeSync(fs.openSync(enoentFile, 'w')); // event loop notices it.
fileExists = true; fs.closeSync(fs.openSync(enoentFile, 'w'));
} else { fileExists = true;
// If the ino (inode) value is greater than zero, it means that the file is } else {
// present in the filesystem and it has a valid inode number. // If the ino (inode) value is greater than zero, it means that the file
assert(curr.ino > 0); // is present in the filesystem and it has a valid inode number.
// As the file just got created, previous ino value should be lesser than assert(curr.ino > 0);
// or equal to zero (non-existent file). // As the file just got created, previous ino value should be lesser than
assert(prev.ino <= 0); // or equal to zero (non-existent file).
// Stop watching the file assert(prev.ino <= 0);
fs.unwatchFile(enoentFile); // Stop watching the file
} fs.unwatchFile(enoentFile);
}, 2)); }
}, 2));
watcher.start(); // should not crash
// Watch events should callback with a filename on supported systems. // Watch events should callback with a filename on supported systems.
// Omitting AIX. It works but not reliably. // Omitting AIX. It works but not reliably.