Merge pull request #11414 from Adityaperiwal/bugfix/maximumCallStack

fix bug for maxCallStack in ContextModuleFactory
This commit is contained in:
Tobias Koppers 2020-09-27 10:52:48 +02:00 committed by GitHub
commit 58fca1369c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 90 additions and 3 deletions

View File

@ -276,7 +276,26 @@ module.exports = class ContextModuleFactory extends ModuleFactory {
} = options;
if (!regExp || !resource) return callback(null, []);
const addDirectory = (directory, callback) => {
const addDirectoryChecked = (directory, visited, callback) => {
fs.realpath(directory, (err, realPath) => {
if (err) return callback(err);
if (visited.has(realPath)) return callback(null, []);
let recursionStack;
addDirectory(
directory,
(dir, callback) => {
if (recursionStack === undefined) {
recursionStack = new Set(visited);
recursionStack.add(realPath);
}
addDirectoryChecked(dir, recursionStack, callback);
},
callback
);
});
};
const addDirectory = (directory, addSubDirectory, callback) => {
fs.readdir(directory, (err, files) => {
if (err) return callback(err);
files = files.map(file => file.normalize("NFC"));
@ -301,7 +320,7 @@ module.exports = class ContextModuleFactory extends ModuleFactory {
if (stat.isDirectory()) {
if (!recursive) return callback();
addDirectory.call(this, subResource, callback);
addSubDirectory(subResource, callback);
} else if (
stat.isFile() &&
(!include || subResource.match(include))
@ -358,6 +377,12 @@ module.exports = class ContextModuleFactory extends ModuleFactory {
});
};
addDirectory(resource, callback);
if (typeof fs.realpath === "function") {
addDirectoryChecked(resource, new Set(), callback);
} else {
const addSubDirectory = (dir, callback) =>
addDirectory(dir, addSubDirectory, callback);
addDirectory(resource, addSubDirectory, callback);
}
}
};

View File

@ -57,5 +57,67 @@ describe("ContextModuleFactory", () => {
}
);
});
it("should return callback with [] if circular symlinks exist", done => {
let statDirStatus = 0;
memfs.readdir = (dir, callback) => {
statDirStatus++;
setTimeout(() => callback(null, ["/A"]));
};
memfs.stat = (file, callback) => {
const resolvedValue = {
isDirectory: () => statDirStatus === 1,
isFile: () => statDirStatus !== 1
};
setTimeout(() => callback(null, resolvedValue));
};
memfs.realpath = (dir, callback) => {
const realPath = dir.split("/");
setTimeout(() => callback(null, realPath[realPath.length - 1]));
};
factory.resolveDependencies(
memfs,
{
resource: "/A",
recursive: true,
regExp: /.*/
},
(err, res) => {
expect(res).toStrictEqual([]);
done();
}
);
});
it("should not return callback with [] if there are no circular symlinks", done => {
let statDirStatus = 0;
memfs.readdir = (dir, callback) => {
statDirStatus++;
setTimeout(() => callback(null, ["/B"]));
};
memfs.stat = (file, callback) => {
const resolvedValue = {
isDirectory: () => statDirStatus === 1,
isFile: () => statDirStatus !== 1
};
setTimeout(() => callback(null, resolvedValue));
};
memfs.realpath = (dir, callback) => {
const realPath = dir.split("/");
setTimeout(() => callback(null, realPath[realPath.length - 1]));
};
factory.resolveDependencies(
memfs,
{
resource: "/A",
recursive: true,
regExp: /.*/
},
(err, res) => {
expect(res).not.toStrictEqual([]);
expect(Array.isArray(res)).toBe(true);
expect(res.length).toBe(1);
done();
}
);
});
});
});