Skip to content

Avoid IndexOutOfRangeException in command-line parsing#7648

Merged
Youssef1313 merged 2 commits intomicrosoft:mainfrom
Youssef1313:dev/ygerges/exception
Apr 1, 2026
Merged

Avoid IndexOutOfRangeException in command-line parsing#7648
Youssef1313 merged 2 commits intomicrosoft:mainfrom
Youssef1313:dev/ygerges/exception

Conversation

@Youssef1313
Copy link
Copy Markdown
Member

Fixes #7646

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a regression test and hardens command-line parsing to prevent IndexOutOfRangeException when an empty argument is encountered (fixing #7646).

Changes:

  • Add a unit test covering parsing/validation with an empty argument.
  • Guard access to currentArg[0] by checking currentArg.Length > 0 in the parser.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
test/UnitTests/Microsoft.Testing.Platform.UnitTests/CommandLine/ArgumentArityTests.cs Adds a regression test ensuring empty arguments don’t crash parsing/validation and produce an invalid result with an error message.
src/Platform/Microsoft.Testing.Platform/CommandLine/Parser.cs Prevents out-of-range indexing when the first argument is an empty string.

…e/ArgumentArityTests.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings April 1, 2026 10:19
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

@AraHaan
Copy link
Copy Markdown

AraHaan commented Apr 1, 2026

I feel like the code that splits the args up by " " could also use the overload with the option to remove empty the strings from the resulting array as well.

@Youssef1313
Copy link
Copy Markdown
Member Author

We don't split anything. We receive string[] from the entry point. If it contains an empty string, it looks like it shouldn't be ignored.

@Youssef1313 Youssef1313 merged commit a8d6ffe into microsoft:main Apr 1, 2026
14 checks passed
@Youssef1313 Youssef1313 deleted the dev/ygerges/exception branch April 1, 2026 14:34
Copy link
Copy Markdown
Member

@Evangelink Evangelink left a comment

Choose a reason for hiding this comment

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

The production fix is correct, minimal, and well-targeted — nice work. The only unguarded currentArg[0] access in the parser is properly fixed.

A couple of suggestions on the test:

  1. Assertion style: Consider using FluentAssertions (Should().BeFalse(), Should().Contain(...)) per repo conventions.
  2. Brittleness: An exact multi-line match (with pragma suppression for the embedded tab) is fragile. A Contain("Unexpected argument") check validates the regression equally well and is more maintainable.

Both are minor — the fix itself is solid.

// If it's the first argument and it doesn't start with - then it's the tool name
// TODO: This won't work correctly if the first argument provided is a response file that contains the tool name.
if (isFirstRealArgument && currentArg[0] != '-')
if (isFirstRealArgument && currentArg.Length > 0 && currentArg[0] != '-')
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The production fix is correct and minimal — this was the only unguarded indexing on currentArg in the method. The StartsWith('@') above is safe on empty strings, and the length checks on lines 68-69 (Length > 1, Length > 2) already had proper guards. 👍

Comment on lines +34 to +44
ValidationResult result = await CommandLineOptionsValidator.ValidateAsync(parseResult, _systemCommandLineOptionsProviders,
_extensionCommandLineOptionsProviders, new Mock<ICommandLineOptions>().Object);

// Assert
Assert.IsFalse(result.IsValid);
#pragma warning disable SA1027 // Use tabs correctly
Assert.AreEqual(
"""
Invalid command line arguments:
- Unexpected argument
""", result.ErrorMessage, StringComparer.Ordinal);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Per repo conventions in .github/copilot-instructions.md:

"All assertions must be written using FluentAssertions style of assertion."

The new test uses Assert.IsFalse and Assert.AreEqual. Consider switching to:

result.IsValid.Should().BeFalse();
result.ErrorMessage.Should().Contain("Unexpected argument");

Using Should().Contain(...) instead of exact multi-line match would also avoid the #pragma disable SA1027 and make the test more resilient to harmless formatting changes in the error message (indentation, newlines, trailing space).

(The existing tests in the same file also use Assert.* — that's a pre-existing inconsistency, but a new test is a good opportunity to follow the stated convention.)

Comment on lines +38 to +39
Assert.IsFalse(result.IsValid);
#pragma warning disable SA1027 // Use tabs correctly
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Disabling SA1027 to embed a literal tab in the raw string is a bit of code smell in a test. If you do keep the exact-match assertion, you can avoid the pragma by constructing the expected string with "\t":

var expected = string.Join(
    Environment.NewLine,
    "Invalid command line arguments:",
    "\t- Unexpected argument ",
    string.Empty);
result.ErrorMessage.Should().Be(expected);

Though as noted above, a Should().Contain("Unexpected argument") assertion would sidestep this entirely and still validate the regression.

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.

IndexOutOfRangeException in the command line parsor when run from GitHub Actions.

5 participants