mirror of
https://github.com/angular/angular
synced 2026-05-24 09:28:37 +00:00
fix(compiler): avoid errors with extremely long instruction chains (#45574)
Our logic for generating code from an AST uses recursion which limits the number of expressions we can nest before we reach the call stack limit. These changes add a limit in order to avoid errors in some cases where the chains become extremely long. Fixes #45564. PR Close #45574
This commit is contained in:
parent
7bf1cf4bf5
commit
598b759d33
1 changed files with 11 additions and 1 deletions
|
|
@ -50,6 +50,13 @@ export const NON_BINDABLE_ATTR = 'ngNonBindable';
|
|||
/** Name for the variable keeping track of the context returned by `ɵɵrestoreView`. */
|
||||
export const RESTORED_VIEW_CONTEXT_NAME = 'restoredCtx';
|
||||
|
||||
/**
|
||||
* Maximum length of a single instruction chain. Because our output AST uses recursion, we're
|
||||
* limited in how many expressions we can nest before we reach the call stack limit. This
|
||||
* length is set very conservatively in order to reduce the chance of problems.
|
||||
*/
|
||||
const MAX_CHAIN_LENGTH = 500;
|
||||
|
||||
/** Instructions that support chaining. */
|
||||
const CHAINABLE_INSTRUCTIONS = new Set([
|
||||
R3.element,
|
||||
|
|
@ -309,6 +316,7 @@ export function getInstructionStatements(instructions: Instruction[]): o.Stateme
|
|||
const statements: o.Statement[] = [];
|
||||
let pendingExpression: o.Expression|null = null;
|
||||
let pendingExpressionType: o.ExternalReference|null = null;
|
||||
let chainLength = 0;
|
||||
|
||||
for (const current of instructions) {
|
||||
const resolvedParams =
|
||||
|
|
@ -318,16 +326,18 @@ export function getInstructionStatements(instructions: Instruction[]): o.Stateme
|
|||
|
||||
// If the current instruction is the same as the previous one
|
||||
// and it can be chained, add another call to the chain.
|
||||
if (pendingExpressionType === current.reference &&
|
||||
if (chainLength < MAX_CHAIN_LENGTH && pendingExpressionType === current.reference &&
|
||||
CHAINABLE_INSTRUCTIONS.has(pendingExpressionType)) {
|
||||
// We'll always have a pending expression when there's a pending expression type.
|
||||
pendingExpression = pendingExpression!.callFn(params, pendingExpression!.sourceSpan);
|
||||
chainLength++;
|
||||
} else {
|
||||
if (pendingExpression !== null) {
|
||||
statements.push(pendingExpression.toStmt());
|
||||
}
|
||||
pendingExpression = invokeInstruction(current.span, current.reference, params);
|
||||
pendingExpressionType = current.reference;
|
||||
chainLength = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue