Skip to content

Commit bb853d3

Browse files
committed
fix infinite loop in ast walk by applying modifications after walk completes
1 parent 47b6bf2 commit bb853d3

1 file changed

Lines changed: 34 additions & 21 deletions

File tree

client/modules/Preview/jsPreprocess.js

Lines changed: 34 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,8 @@ function makeCheckStatement(varName, line) {
107107
};
108108
}
109109

110-
function protectLoops(ast, shaderNames) {
111-
let loopCount = 0;
110+
function collectLoopsToProtect(ast, shaderNames) {
111+
const loops = [];
112112

113113
function visitNode(node, ancestors) {
114114
const isInsideShader = ancestors.some((ancestor, idx) => {
@@ -142,30 +142,19 @@ function protectLoops(ast, shaderNames) {
142142

143143
if (isInsideShader) return;
144144

145-
const varName = `_LP${loopCount++}`;
146-
const { line } = node.loc.start;
147-
const check = makeCheckStatement(varName, line);
148-
149-
if (node.body.type === 'BlockStatement') {
150-
node.body.body.unshift(check);
151-
} else {
152-
node.body = { type: 'BlockStatement', body: [check, node.body] };
153-
}
154-
155-
const varDecl = makeVarDecl(varName);
145+
let parentBlock = null;
156146
for (let i = ancestors.length - 1; i >= 0; i--) {
157147
const ancestor = ancestors[i];
158148
if (
159149
ancestor !== node &&
160150
(ancestor.type === 'BlockStatement' || ancestor.type === 'Program')
161151
) {
162-
const nodeIdx = ancestor.body.indexOf(node);
163-
if (nodeIdx !== -1) {
164-
ancestor.body.splice(nodeIdx, 0, varDecl);
165-
break;
166-
}
152+
parentBlock = ancestor;
153+
break;
167154
}
168155
}
156+
157+
loops.push({ loop: node, parentBlock });
169158
}
170159

171160
walk.ancestor(ast, {
@@ -174,7 +163,29 @@ function protectLoops(ast, shaderNames) {
174163
DoWhileStatement: visitNode
175164
});
176165

177-
return loopCount;
166+
return loops;
167+
}
168+
169+
function injectProtection(loops) {
170+
loops.forEach(({ loop, parentBlock }, idx) => {
171+
const varName = `_LP${idx}`;
172+
const { line } = loop.loc.start;
173+
const check = makeCheckStatement(varName, line);
174+
175+
if (loop.body.type === 'BlockStatement') {
176+
loop.body.body.unshift(check);
177+
} else {
178+
loop.body = { type: 'BlockStatement', body: [check, loop.body] };
179+
}
180+
181+
if (parentBlock) {
182+
const varDecl = makeVarDecl(varName);
183+
const nodeIdx = parentBlock.body.indexOf(loop);
184+
if (nodeIdx !== -1) {
185+
parentBlock.body.splice(nodeIdx, 0, varDecl);
186+
}
187+
}
188+
});
178189
}
179190

180191
function parseJs(jsText) {
@@ -199,9 +210,11 @@ export function jsPreprocess(jsText) {
199210
if (!ast) return jsText;
200211

201212
const shaderNames = collectShaderFunctionNames(ast);
202-
const loopCount = protectLoops(ast, shaderNames);
213+
const loops = collectLoopsToProtect(ast, shaderNames);
214+
215+
if (loops.length === 0) return jsText;
203216

204-
if (loopCount === 0) return jsText;
217+
injectProtection(loops);
205218

206219
return escodegen.generate(ast);
207220
}

0 commit comments

Comments
 (0)