mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-06-21 15:58:24 -05:00
Fix infinite loop: module.exports alias detection (#31436)
* Fix infinite loop: module.exports alias detection Previously, module.exports alias detection in the binder could enter an infinite recursion. Now it does not. Notably, there are *two* safeguards: a counter limiter that I set at 100, and an already-seen set. I actually prefer the counter limiter code because it's foolproof and uses less memory. But it takes 100 iterations to escape from loops. * fix space lint * Remove already-seen map
This commit is contained in:
committed by
GitHub
parent
f4b83ef8d3
commit
eeba30afc8
@@ -2581,7 +2581,7 @@ namespace ts {
|
||||
// Fix up parent pointers since we're going to use these nodes before we bind into them
|
||||
node.left.parent = node;
|
||||
node.right.parent = node;
|
||||
if (isIdentifier(lhs.expression) && container === file && isNameOfExportsOrModuleExportsAliasDeclaration(file, lhs.expression)) {
|
||||
if (isIdentifier(lhs.expression) && container === file && isExportsOrModuleExportsOrAlias(file, lhs.expression)) {
|
||||
// This can be an alias for the 'exports' or 'module.exports' names, e.g.
|
||||
// var util = module.exports;
|
||||
// util.property = function ...
|
||||
@@ -2975,21 +2975,27 @@ namespace ts {
|
||||
}
|
||||
|
||||
export function isExportsOrModuleExportsOrAlias(sourceFile: SourceFile, node: Expression): boolean {
|
||||
return isExportsIdentifier(node) ||
|
||||
isModuleExportsPropertyAccessExpression(node) ||
|
||||
isIdentifier(node) && isNameOfExportsOrModuleExportsAliasDeclaration(sourceFile, node);
|
||||
}
|
||||
|
||||
function isNameOfExportsOrModuleExportsAliasDeclaration(sourceFile: SourceFile, node: Identifier): boolean {
|
||||
const symbol = lookupSymbolForNameWorker(sourceFile, node.escapedText);
|
||||
return !!symbol && !!symbol.valueDeclaration && isVariableDeclaration(symbol.valueDeclaration) &&
|
||||
!!symbol.valueDeclaration.initializer && isExportsOrModuleExportsOrAliasOrAssignment(sourceFile, symbol.valueDeclaration.initializer);
|
||||
}
|
||||
|
||||
function isExportsOrModuleExportsOrAliasOrAssignment(sourceFile: SourceFile, node: Expression): boolean {
|
||||
return isExportsOrModuleExportsOrAlias(sourceFile, node) ||
|
||||
(isAssignmentExpression(node, /*excludeCompoundAssignment*/ true) && (
|
||||
isExportsOrModuleExportsOrAliasOrAssignment(sourceFile, node.left) || isExportsOrModuleExportsOrAliasOrAssignment(sourceFile, node.right)));
|
||||
let i = 0;
|
||||
const q = [node];
|
||||
while (q.length && i < 100) {
|
||||
i++;
|
||||
node = q.shift()!;
|
||||
if (isExportsIdentifier(node) || isModuleExportsPropertyAccessExpression(node)) {
|
||||
return true;
|
||||
}
|
||||
else if (isIdentifier(node)) {
|
||||
const symbol = lookupSymbolForNameWorker(sourceFile, node.escapedText);
|
||||
if (!!symbol && !!symbol.valueDeclaration && isVariableDeclaration(symbol.valueDeclaration) && !!symbol.valueDeclaration.initializer) {
|
||||
const init = symbol.valueDeclaration.initializer;
|
||||
q.push(init);
|
||||
if (isAssignmentExpression(init, /*excludeCompoundAssignment*/ true)) {
|
||||
q.push(init.left);
|
||||
q.push(init.right);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function lookupSymbolForNameWorker(container: Node, name: __String): Symbol | undefined {
|
||||
|
||||
Reference in New Issue
Block a user