Skip to content

In getSuggestionForNonexistentSymbol, guard name against undefined#19039

Merged
sandersn merged 5 commits into
masterfrom
guard-name-in-getSuggestionForNonexistentSymbol
Nov 7, 2017
Merged

In getSuggestionForNonexistentSymbol, guard name against undefined#19039
sandersn merged 5 commits into
masterfrom
guard-name-in-getSuggestionForNonexistentSymbol

Conversation

@sandersn
Copy link
Copy Markdown
Member

@sandersn sandersn commented Oct 9, 2017

Fixes #19002 (probably)

This came from an aggregate of crash stacks, and from my reading of the code, it doesn't look like name can ever be null (see below for analysis). So:

  1. I don't know how to repro this, except for a unittest that calls getSuggestionForNonexistentSymbol directly.
  2. I decided to put the guard as close to the crash as possible.

I'll poke around the unit tests to see if there's a good place to write a test.

Analysis

  • The crash happens in unescapeLeadingUnderscores(name), called from getSuggestionForNonexistentSymbol.
  • name is a parameter of an lambda, and is provided by resolveNameHelper.
  • But name is an argument to resolveNameHelper, and is supposed to pass through unchanged.
  • Looking at resolveNameHelper, I see no assignments to name, nothing that shadows name, and that the lambda is always called with name as its argument. So it looks like it does indeed pass through unchanged.
  • The caller of getSuggestionForNonexistentSymbol is fixSpelling.ts:getActionsForCorrectSpelling.
  • The argument for name is getTextOfNode(node).
  • getTextOfNode calls getSourceTextOfNodeFromSourceFile
  • getSourceTextOfNodeFromSourceFile either returns "" if the node is missing or calls String.substring otherwise. So it never returns undefined.

I might be missing some call locations, but they shouldn't matter since the call stack from #19002 follows the path that I laid out above.

@sandersn sandersn requested review from a user and mhegazy October 9, 2017 18:06
@sandersn
Copy link
Copy Markdown
Member Author

sandersn commented Oct 9, 2017

Unfortunately, the public API always calls escapeLeadingUnderscores before getSuggestionForNonexistentSymbol, so passing undefined crashes there first.

Comment thread src/compiler/checker.ts Outdated
const result = resolveNameHelper(location, name, meaning, /*nameNotFoundMessage*/ undefined, name, /*isUse*/ false, (symbols, name, meaning) => {
// `name` from the callback === the outer `name`
// NOTE: `name` from the callback is supposed to === the outer `name`, but is undefined in some cases
if (name === undefined) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

would not it be better to put this in getActionsForCorrectSpelling? i find it hard to see how resolveName can return undefined

@ghost
Copy link
Copy Markdown

ghost commented Oct 10, 2017

That error looks like #18379, which was possibly fixed by #18793. In other words, we have no evidence that this is a bug in master, and some evidence that it isn't.

@mhegazy
Copy link
Copy Markdown
Contributor

mhegazy commented Oct 10, 2017

I agree with @Andy-MS, lets wait on this one and see if we get new reports post 2.6.0

@sandersn
Copy link
Copy Markdown
Member Author

sandersn commented Nov 1, 2017

Looks like @aozgaa found post-2.6 crashes. Should I merge this? I could also ask him how to log so we could figure out how this happens.

@sandersn
Copy link
Copy Markdown
Member Author

sandersn commented Nov 1, 2017

I switched to asserts instead of undefined checks, so we should be able to see whether the undefined is introduced.

@ghost
Copy link
Copy Markdown

ghost commented Nov 7, 2017

The original issue was confirmed fixed #18379 (comment)

@mhegazy
Copy link
Copy Markdown
Contributor

mhegazy commented Nov 7, 2017

@aozgaa still see crash reports for it on 2.6.1

@mhegazy
Copy link
Copy Markdown
Contributor

mhegazy commented Nov 7, 2017

so we might have addressed some but not all cases (not sure how that would happen still though).

Comment thread src/compiler/checker.ts Outdated
// `name` from the callback === the outer `name`
function getSuggestionForNonexistentSymbol(location: Node, outerName: __String, meaning: SymbolFlags): string {
const result = resolveNameHelper(location, outerName, meaning, /*nameNotFoundMessage*/ undefined, outerName, /*isUse*/ false, (symbols, name, meaning) => {
Debug.assert(name !== undefined, "name should always be defined, and equal to " + outerName);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Debug.assertEqual(name, outerName) and at the top Debug.assert(outerName !== undefined)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Good idea.

Comment thread src/compiler/checker.ts
const result = resolveNameHelper(location, name, meaning, /*nameNotFoundMessage*/ undefined, name, /*isUse*/ false, (symbols, name, meaning) => {
// `name` from the callback === the outer `name`
function getSuggestionForNonexistentSymbol(location: Node, outerName: __String, meaning: SymbolFlags): string {
Debug.assert(outerName !== undefined, "outername should always be defined");
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The description is optional -- in this case you're simply repeating what the code says.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Should make the assert less mysterious in logs, etc, though, since Javascript can only print false, not outerName !== undefined, otherwise.

@sandersn sandersn merged commit 9b36e11 into master Nov 7, 2017
@sandersn sandersn deleted the guard-name-in-getSuggestionForNonexistentSymbol branch November 7, 2017 23:03
@microsoft microsoft locked and limited conversation to collaborators Jun 14, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Crash on unexpected undefined when getting suggestions for nonexistent symbol

2 participants