Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Jan 4, 2026

Description

TagList.CopyTo(array, arrayIndex) throws ArgumentOutOfRangeException when the TagList is empty and an empty array is passed. This is inconsistent with ActivityTagsCollection.CopyTo and standard collection semantics.

let emptyArray: KeyValuePair<string,obj> array = [||]
TagList().CopyTo(emptyArray, 0)  // Throws: arrayIndex ('0') must be less than '0'
TagList() |> Seq.toArray          // Also throws (uses CopyTo internally)

Fix: Allow arrayIndex == array.Length when the TagList is empty (since nothing will be copied), while still validating that arrayIndex is within valid bounds (non-negative and not greater than array length) regardless of whether the TagList is empty.

Also fixed a typo in the XML documentation ("greater that" → "greater than") in both TagList.netcore.cs and TagList.netfx.cs.

Customer Impact

Users cannot safely call CopyTo or use LINQ's ToArray() on empty TagList instances without catching exceptions.

Regression

No.

Testing

  • Added TestEmptyTagListCopyTo test covering empty TagList with CopyTo(array, index), CopyTo(span), and ToArray() for both empty and non-empty destination arrays
  • Added tests verifying that invalid arrayIndex values (negative or exceeding array length) still throw ArgumentOutOfRangeException even when the TagList is empty
  • Extended TestCopyTo to exercise ICollection<T>.CopyTo for all sizes including 0
  • All tests in System.Diagnostics.DiagnosticSource.Tests pass

Risk

Low. The change only affects the empty case and aligns behavior with existing collection types. The fix is applied consistently to both TagList.netcore.cs and TagList.netfx.cs.

Package authoring no longer needed in .NET 9

IMPORTANT: Starting with .NET 9, you no longer need to edit a NuGet package's csproj to enable building and bump the version.
Keep in mind that we still need package authoring in .NET 8 and older versions.

Original prompt

This section details on the original issue you should resolve

<issue_title>Diagnostics.TagList does not support IEnumerable or CopyTo when Empty</issue_title>
<issue_description>### Description

TagList throws exception when empty and consuming as in IEnumerable or when coping to an array. This is not the case with ActivityTagsCollection.

(Example in dotnet fsi using F#):

open System.Collections.Generic;;
open System.Diagnostics;;

let myArray: KeyValuePair<string,obj> array = [||]

// ActivityTagsCollection.CopyTo works as expected when empty
ActivityTagsCollection().CopyTo(myArray, 0);;

// TagList.CopyTo throws exception when empty
System.Diagnostics.TagList().CopyTo(myArray, 0);;
// System.ArgumentOutOfRangeException: arrayIndex ('0') must be less than '0'. (Parameter 'arrayIndex')
// Actual value was 0.
//    at System.ArgumentOutOfRangeException.ThrowGreaterEqual[T](T value, T other, String paramName)
//    at System.ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual[T](T value, T other, String paramName)
//    at System.Diagnostics.TagList.CopyTo(KeyValuePair`2[] array, Int32 arrayIndex)
// Stopped due to error


// Converting an empty ActivityTagsCollection IEnumerable to an array works
System.Diagnostics.ActivityTagsCollection() |> Seq.toArray;;
// KeyValuePair<string,obj> array = [||]

// Converting an empty TagList (as an IEnumerable) to an array throws exception because
// it uses CopyTo internally
TagList() |> Seq.toArray;;
// System.ArgumentOutOfRangeException: arrayIndex ('0') must be less than '0'. (Parameter 'arrayIndex')
// Actual value was 0.
//    at System.ArgumentOutOfRangeException.ThrowGreaterEqual[T](T value, T other, String paramName)
//    at System.ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual[T](T value, T other, String paramName)
//    at System.Diagnostics.TagList.CopyTo(KeyValuePair`2[] array, Int32 arrayIndex)
// Stopped due to error

Reproduction Steps

let arr: KeyValuePair<string,obj> array = [||]
TagList().CopyTo(arr, 0)

Expected behavior

Should do the same as the other CopyTo method. This does not throw an exception:

let arr: KeyValuePair<string,obj> array = [||]
TagList().CopyTo(arr)

Actual behavior

System.ArgumentOutOfRangeException: arrayIndex ('0') must be less than '0'. (Parameter 'arrayIndex')
Actual value was 0.
   at System.ArgumentOutOfRangeException.ThrowGreaterEqual[T](T value, T other, String paramName)
   at System.ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual[T](T value, T other, String paramName)
   at System.Diagnostics.TagList.CopyTo(KeyValuePair`2[] array, Int32 arrayIndex)

Regression?

No response

Known Workarounds

No response

Configuration

No response

Other information

Line where exception is thrown:

ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual((uint)arrayIndex, (uint)array.Length, nameof(arrayIndex));
</issue_description>

<agent_instructions>If the source is empty, the destination index doesn't matter because nothing will be copied.</agent_instructions>

Comments on the Issue (you are @copilot in this section)


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix TagList exception for empty IEnumerable or CopyTo Fix TagList.CopyTo to not throw when TagList is empty Jan 4, 2026
Copilot AI requested a review from stephentoub January 4, 2026 05:04
@stephentoub stephentoub marked this pull request as ready for review January 4, 2026 05:06
Copilot AI review requested due to automatic review settings January 4, 2026 05:06
@dotnet-policy-service
Copy link
Contributor

Tagging subscribers to this area: @dotnet/area-system-diagnostics-activity
See info in area-owners.md if you want to be subscribed.

Copy link
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

This PR fixes a bug where TagList.CopyTo(array, arrayIndex) incorrectly throws an ArgumentOutOfRangeException when called on an empty TagList with an empty array, making it inconsistent with standard collection semantics and with ActivityTagsCollection.CopyTo.

Key Changes:

  • Modified CopyTo(KeyValuePair<string, object?>[] array, int arrayIndex) to skip bounds checking when _tagsCount == 0
  • Added comprehensive test coverage for empty TagList operations including CopyTo variants and ToArray()
  • Extended existing TestCopyTo to exercise ICollection<T>.CopyTo interface method for all sizes

Reviewed changes

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

File Description
src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/TagList.netcore.cs Wraps the arrayIndex bounds check in a conditional that only executes when the TagList is non-empty
src/libraries/System.Diagnostics.DiagnosticSource/tests/TagListTests.cs Adds TestEmptyTagListCopyTo test for empty TagList scenarios and enhances TestCopyTo to test ICollection<T>.CopyTo

@stephentoub
Copy link
Member

@copilot, please address the review feedback

Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Jan 4, 2026

@copilot, please address the review feedback

Addressed in ece9db1:

  • Added ThrowIfGreaterThan check before the empty check to validate arrayIndex is within bounds even when TagList is empty
  • Added tests for empty TagList with invalid arrayIndex (negative and exceeding array length)
  • Fixed the typo in the XML documentation

@tarekgh tarekgh added this to the 11.0.0 milestone Jan 4, 2026
@tarekgh
Copy link
Member

tarekgh commented Jan 4, 2026

@copilot need to apply the change to the file TagList.netfx.cs too.

Co-authored-by: tarekgh <10833894+tarekgh@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Jan 4, 2026

@copilot need to apply the change to the file TagList.netfx.cs too.

Applied the same fix to TagList.netfx.cs in 97b36bd.

Copilot AI requested a review from tarekgh January 4, 2026 19:36
@stephentoub stephentoub enabled auto-merge (squash) January 5, 2026 15:50
@stephentoub
Copy link
Member

/ba-g dead letter

@stephentoub stephentoub merged commit 4c0401c into main Jan 5, 2026
85 of 87 checks passed
@stephentoub stephentoub deleted the copilot/fix-taglist-copyto-exception branch January 5, 2026 20:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Diagnostics.TagList does not support IEnumerable or CopyTo when Empty

3 participants