Skip to content

fix: limit recursive merge aliases - #685

Open
pupuking723 wants to merge 5 commits into
eemeli:mainfrom
pupuking723:fix/merge-alias-count-recursion
Open

fix: limit recursive merge aliases#685
pupuking723 wants to merge 5 commits into
eemeli:mainfrom
pupuking723:fix/merge-alias-count-recursion

Conversation

@pupuking723

Copy link
Copy Markdown

Fixes #677.

This makes cyclic merge aliases fail through the existing alias-count guard instead of recursing until the call stack overflows.

The change keeps an existing anchor entry's count when the same node is re-entered during toJS() conversion, while allowing the resolved JS value to be updated. Merge alias handling now also runs alias toJS() before resolving the merge source, so maxAliasCount is applied to aliases reached through << merge handling.

Verification:

  • npm test -- tests/doc/anchors.ts -t "circular reference"
  • npm test -- tests/doc/anchors.ts
  • npm test
  • npm run lint
  • npm run test:types
  • npm run build

@eemeli eemeli left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calling toJS() for the side effect of applying the anchor node count validation is a bit non-intuitive. Is there potentially a solution in adding a method on ToJSContext where we move the code that's now for that in Alias.toJS(), and call it also from elsewhere?

Comment thread src/schema/yaml-1.1/merge.ts Outdated
Comment thread src/schema/yaml-1.1/merge.ts Outdated
@pupuking723

Copy link
Copy Markdown
Author

Updated in 5c8bb6e.

The alias-count validation now lives in ToJSContext.resolveAlias(), and the merge-tag path reuses that helper instead of calling Alias.toJS() for the side effect.

I also added coverage for merge aliases that resolve to sequences so that branch stays exercised directly.

Verification:

  • npm test -- tests/doc/anchors.ts
  • npm test
  • npm run lint -- src/nodes/Alias.ts src/nodes/toJS.ts src/schema/yaml-1.1/merge.ts tests/doc/anchors.ts
  • npm run test:types
  • npm run build

@pupuking723

Copy link
Copy Markdown
Author

The alias-count validation is now centralized in ToJSContext.resolveAlias(), and both Alias.toJS() and YAML 1.1 merge handling use that path. The branch also includes focused coverage for recursive merge aliases. Ready for another look when you have time.

@eemeli eemeli left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, finally got back to this. The fix is starting to look pretty good; see inline for a further simplification that ought to be included.

I merged your branch from main to resolve a conflict from merging another PR.

Comment thread src/nodes/toJS.ts Outdated
resolveAlias(
doc: Document,
source: Node,
getAliasCount: () => number

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no need for getAliasCount to get passed around as a callback. Its definition in src/nodes/Alias.ts should be moved here, as this is the only place it's actually called, and its arguments simplified to drop the anchors argument -- it's always this.anchors from here.

@pupuking723

Copy link
Copy Markdown
Author

Moved the alias counting logic into ToJSContext and removed the callback and anchors plumbing. Both Alias.toJS() and the merge path now call resolveAlias(doc, source) directly. Full tests, types, lint, formatting, and build pass locally.

Comment thread src/nodes/toJS.ts
return data.res
}

private getAliasCount(doc: Document, node: Node | Pair | null): number {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's make this actually private.

Suggested change
private getAliasCount(doc: Document, node: Node | Pair | null): number {
#getAliasCount(doc: Document, node: Node | Pair | null): number {

Comment on lines +100 to +103
if (!source) {
const msg = `Unresolved alias (the anchor must be set before the alias): ${value.source}`
throw new ReferenceError(msg)
}

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, should've caught this earlier: this needs to be tested.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Circular merge aliases may cause RangeError despite maxAliasCount during JS conversion

2 participants