8000 Avoid infinite loops in type inference logic (#12390) · babel/babel@4f9ad5c · GitHub
[go: up one dir, main page]

Skip to content

Commit 4f9ad5c

Browse files
Avoid infinite loops in type inference logic (#12390)
1 parent 243d3b2 commit 4f9ad5c

File tree

2 files changed

+37
-6
lines changed

2 files changed

+37
-6
lines changed

packages/babel-traverse/src/path/inference/index.js

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ export function getTypeAnnotation(): Object {
1414
return (this.typeAnnotation = type);
1515
}
1616

17+
// Used to avoid infinite recursion in cases like
18+
// var b, c; if (0) { c = 1; b = c; } c = b;
19+
// It also works with indirect recursion.
20+
const typeAnnotationInferringNodes = new WeakSet();
21+
1722
/**
1823
* todo: split up this method
1924
*/
@@ -47,14 +52,24 @@ export function _getTypeAnnotation(): ?Object {
4752
return node.typeAnnotation;
4853
}
4954

50-
let inferer = inferers[node.type];
51-
if (inferer) {
52-
return inferer.call(this, node);
55+
if (typeAnnotationInferringNodes.has(node)) {
56+
// Bail out from type inference to avoid infinite loops
57+
return;
5358
}
59+
typeAnnotationInferringNodes.add(node);
60+
61+
try {
62+
let inferer = inferers[node.type];
63+
if (inferer) {
64+
return inferer.call(this, node);
65+
}
5466

55-
inferer = inferers[this.parentPath.type];
56-
if (inferer?.validParent) {
57-
return this.parentPath.getTypeAnnotation();
67+
inferer = inferers[this.parentPath.type];
68+
if (inferer?.validParent) {
69+
return this.parentPath.getTypeAnnotation();
70+
}
71+
} finally {
72+
typeAnnotationInferringNodes.delete(node);
5873
}
5974
}
6075

packages/babel-traverse/test/inference.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,5 +289,21 @@ describe("inference", function () {
289289
const type = path.getTypeAnnotation();
290290
expect(t.isAnyTypeAnnotation(type)).toBeTruthy();
291291
});
292+
it("should not cause a stack overflow when two variable depend on eachother", function () {
293+
const path = getPath(`
294+
var b, c;
295+
while (0) {
296+
c = 1;
297+
b = c;
298+
}
299+
c = b;
300+
`).get("body.2.expression");
301+
302+
expect(path.toString()).toBe("c = b");
303+
304+
// Note: this could technically be "number | void", but the cycle detection
305+
// logic just bails out to "any" to avoid infinite loops.
306+
expect(path.getTypeAnnotation()).toEqual({ type: "AnyTypeAnnotation" });
307+
});
292308
});
293309
});

0 commit comments

Comments
 (0)
0