Skip to content

Commit 01a7b5b

Browse files
authored
fix(assertions): stack overflow while parsing template (#26767)
Closes #26766 The function `findCycle` tries to find a cycle by using a depth-first search (DFS). The DFS is implemented recursively in the recurse function. For each node, it tries to find a path that eventually leads back to the start of the path. If such a path is found, a cycle exists, and the nodes forming this cycle are returned. One of the bugs in the current implementation is that it only checks whether the current dependency `dep` is equal to the first node of the current path `path[0]`. This means it will only detect a cycle if the cycle includes the first node of the search, which might not always be the case. To fix this, the function should check whether the current dependency `dep` is already somewhere in the current path `path`. If it is, then a cycle has been found. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent dbe5615 commit 01a7b5b

File tree

2 files changed

+25
-2
lines changed

2 files changed

+25
-2
lines changed

packages/aws-cdk-lib/assertions/lib/private/cyclic.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -167,12 +167,12 @@ function findCycle(deps: ReadonlyMap<string, ReadonlySet<string>>): string[] {
167167

168168
function recurse(node: string, path: string[]): string[] | undefined {
169169
for (const dep of deps.get(node) ?? []) {
170-
if (dep === path[0]) { return [...path, dep]; }
170+
if (path.includes(dep)) { return [...path, dep]; }
171171

172172
const cycle = recurse(dep, [...path, dep]);
173173
if (cycle) { return cycle; }
174174
}
175175

176176
return undefined;
177177
}
178-
}
178+
}

packages/aws-cdk-lib/assertions/test/template.test.ts

+23
Original file line numberDiff line numberDiff line change
@@ -1345,6 +1345,29 @@ describe('Template', () => {
13451345
}).toThrow(/dependency cycle/);
13461346
});
13471347

1348+
test('throws when given a more complex template with cyclic dependencies', () => {
1349+
expect(() => {
1350+
Template.fromJSON({
1351+
Resources: {
1352+
Res1: {
1353+
Type: 'Foo',
1354+
Properties: {
1355+
Thing: { Ref: 'Res2' },
1356+
},
1357+
},
1358+
Res2: {
1359+
Type: 'Foo',
1360+
DependsOn: ['Res3'],
1361+
},
1362+
Res3: {
1363+
Type: 'Foo',
1364+
DependsOn: ['Res2'],
1365+
},
1366+
},
1367+
});
1368+
}).toThrow(/dependency cycle/);
1369+
});
1370+
13481371
test('does not throw when given a template with cyclic dependencies if check is skipped', () => {
13491372
expect(() => {
13501373
Template.fromJSON({

0 commit comments

Comments
 (0)