Skip to content

Fix crash where lines appended to end of script file causes out of bounds exception #730

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Aug 28, 2018

Conversation

rjmholt
Copy link
Contributor

@rjmholt rjmholt commented Aug 23, 2018

Fixes PowerShell/vscode-powershell#1283 and fixes PowerShell/vscode-powershell#1492.

Note: I doubt it will affect PowerShell/vscode-powershell#1453; that looks like a separate issue.

It looks like there is a tendency for VSCode to generate a text document change request with an offset that is one beyond the current lines we track under certain conditions. @rkeithhill's repro is the best I've seen.

Anyway, this PR just detects that case and bypasses all the magic insertion logic -- instead we just append the lines to the end.

@rjmholt rjmholt changed the title Fix crash where lines appended to end of script file cause out of bounds Fix crash where lines appended to end of script file causes out of bounds exception Aug 23, 2018
Copy link
Collaborator

@SeeminglyScience SeeminglyScience left a comment

Choose a reason for hiding this comment

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

Looks good, just one request

@@ -309,14 +309,24 @@ public void ValidatePosition(BufferPosition bufferPosition)
/// </summary>
/// <param name="line">The 1-based line to be validated.</param>
/// <param name="column">The 1-based column to be validated.</param>
public void ValidatePosition(int line, int column)
public void ValidatePosition(int line, int column, bool isInsertion = false)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Adding an optional parameter is a breaking change, can you add an overload instead?


/// <summary>
/// Throws ArgumentOutOfRangeException if the given position is outside
/// of the file's buffer extents.
Copy link
Contributor

Choose a reason for hiding this comment

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

Perhaps we should add some explanation here to why column-max-index+1 and line-max-index+1 are allowed.

/// <param name="isInsertion">If true, the position to validate is for an applied change.</param>
public void ValidatePosition(int line, int column, bool isInsertion)
{
int maxLine = isInsertion ? this.FileLines.Count + 1 : this.FileLines.Count;
Copy link
Contributor

Choose a reason for hiding this comment

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

I would add a code comment above this to make sure someone else doesn't think they see an off-by-one error with the this.FileLines.Count + 1 and attempt to fix it. :-)

Copy link
Contributor

@rkeithhill rkeithhill left a comment

Choose a reason for hiding this comment

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

LGTM other than adding a few comments to the code.

/// </summary>
/// <param name="line">The 1-based line to be validated.</param>
/// <param name="column">The 1-based column to be validated.</param>
/// <param name="isInsertion">If true, the position to validate is for an applied change.</param>
public void ValidatePosition(int line, int column, bool isInsertion)
{
// If new content is being added, VSCode sometimes likes to add it a (FileLines.Count + 1),
Copy link
Contributor

@rkeithhill rkeithhill Aug 25, 2018

Choose a reason for hiding this comment

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

Minor nit, should this be "add it at …"?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Are these comments ok @rkeithhill? Want to make sure I've put them where you want and saying enough, etc.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, they LGTM.

{
if (column != 1)
{
throw new ArgumentOutOfRangeException($"Insertion at the end of a file must occur at column 1");
Copy link
Member

Choose a reason for hiding this comment

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

1 indexed columns???!?!?!? omg

Copy link
Collaborator

Choose a reason for hiding this comment

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

@tylerl0706 yep

$sb = [scriptblock]::Create('')
$sb.Ast.Extent.StartColumnNumber
# 1
$sb.Ast.Extent.StartLineNumber
# 1
$sb.Ast.Extent.StartOffset
# 0


// Should we add first or last line fragments?
if (changeIndex == 0)
foreach (string addedLine in changeLines)
Copy link
Member

Choose a reason for hiding this comment

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

Would there be a scenario where there's a changed line AND an added line?

Copy link
Member

Choose a reason for hiding this comment

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

If so, the foreach might also need to handle the "between" logic as well.

Copy link
Member

Choose a reason for hiding this comment

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

I guess a better question is... are the changed lines always consecutive

@@ -127,6 +127,22 @@ public void CanApplyMultiLineDelete()
});
}

[Fact]
Copy link
Member

Choose a reason for hiding this comment

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

😍

if (changeIndex == 0)
{
// Append the first line fragment
finalLine = firstLineFragment + finalLine;
Copy link
Member

Choose a reason for hiding this comment

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

do you think you could add a bit more comment?

Like... "append the first line fragment to the front of the change"
and... "append the last line fragment to the end of the change"

the code says that but the logic here is a tad complex

currentLineNumber++;
}
// Build and insert the new lines
int currentLineNumber = fileChange.Line;
Copy link
Member

Choose a reason for hiding this comment

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

maybe consider doing the -1 here instead of line 431. I think it's a little clearer.

Copy link
Member

@TylerLeonhardt TylerLeonhardt left a comment

Choose a reason for hiding this comment

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

LGTM just a couple questions

@rjmholt rjmholt merged commit d60e96f into PowerShell:master Aug 28, 2018
@rjmholt rjmholt deleted the fix-script-file-offset-crash branch December 12, 2018 06:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
4 participants