Use for..of Object.keys instead of for..in (#9518)

In https://github.com/babel/babel/issues/9511 (and #9495 is another symptom), @PavelKastornyy reported a node crash becaue the JavaScript heap run out of memory. The problem was that their code was adding enumerable properties to `Object.prototype`: it is something that shouldn't be done, but Babel shouldn't make node crash if someone adds them.
I reduced down the problem to `for...in` loops in `@babel/traverse` that grew the memory consumption exponentially because of that unexpected properties.
This commit is contained in:
Nicolò Ribaudo
2019-02-26 20:09:02 +01:00
committed by GitHub
parent f1ab6120d2
commit 0345c1bc1d
24 changed files with 60 additions and 55 deletions

View File

@@ -153,8 +153,7 @@ function convertBlockScopedToVar(
// Move bindings from current block scope to function scope.
if (moveBindingsToParent) {
const parentScope = scope.getFunctionParent() || scope.getProgramParent();
const ids = path.getBindingIdentifiers();
for (const name in ids) {
for (const name of Object.keys(path.getBindingIdentifiers())) {
const binding = scope.getOwnBinding(name);
if (binding) binding.kind = "var";
scope.moveBindingTo(name, parentScope);
@@ -245,8 +244,7 @@ const loopLabelVisitor = {
const continuationVisitor = {
enter(path, state) {
if (path.isAssignmentExpression() || path.isUpdateExpression()) {
const bindings = path.getBindingIdentifiers();
for (const name in bindings) {
for (const name of Object.keys(path.getBindingIdentifiers())) {
if (
state.outsideReferences[name] !==
path.scope.getBindingIdentifier(name)
@@ -410,7 +408,7 @@ class BlockScoping {
const scope = this.scope;
const state = this.state;
for (const name in scope.bindings) {
for (const name of Object.keys(scope.bindings)) {
const binding = scope.bindings[name];
if (binding.kind !== "const") continue;
@@ -444,7 +442,7 @@ class BlockScoping {
const parentScope = scope.getFunctionParent() || scope.getProgramParent();
const letRefs = this.letReferences;
for (const key in letRefs) {
for (const key of Object.keys(letRefs)) {
const ref = letRefs[key];
const binding = scope.getBinding(ref.name);
if (!binding) continue;
@@ -471,7 +469,7 @@ class BlockScoping {
// those in upper scopes and then if they do, generate a uid
// for them and replace all references with it
for (const key in letRefs) {
for (const key of Object.keys(letRefs)) {
// just an Identifier node we collected in `getLetReferences`
// this is the defining identifier of a declaration
const ref = letRefs[key];
@@ -491,7 +489,7 @@ class BlockScoping {
}
}
for (const key in outsideLetRefs) {
for (const key of Object.keys(outsideLetRefs)) {
const ref = letRefs[key];
// check for collisions with a for loop's init variable and the enclosing scope's bindings
// https://github.com/babel/babel/issues/8498
@@ -514,7 +512,7 @@ class BlockScoping {
// remap loop heads with colliding variables
if (this.loop) {
for (const name in outsideRefs) {
for (const name of Object.keys(outsideRefs)) {
const id = outsideRefs[name];
if (
@@ -814,7 +812,7 @@ class BlockScoping {
pushDeclar(node: { type: "VariableDeclaration" }): Array<Object> {
const declars = [];
const names = t.getBindingIdentifiers(node);
for (const name in names) {
for (const name of Object.keys(names)) {
declars.push(t.variableDeclarator(names[name]));
}
@@ -852,7 +850,7 @@ class BlockScoping {
}
if (has.hasBreakContinue) {
for (const key in has.map) {
for (const key of Object.keys(has.map)) {
cases.push(t.switchCase(t.stringLiteral(key), [has.map[key]]));
}

View File

@@ -83,7 +83,7 @@ export const visitor = {
const nodes = [];
const ids = path.getBindingIdentifiers();
for (const name in ids) {
for (const name of Object.keys(ids)) {
const id = ids[name];
if (isReference(id, path.scope, state)) {