-
Notifications
You must be signed in to change notification settings - Fork 5k
Added missing clearing of pooled arrays #114545
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
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
#if NET || NETSTANDARD2_1_OR_GREATER | ||
if (RuntimeHelpers.IsReferenceOrContainsReferences<T>()) | ||
#else | ||
if (!typeof(T).IsPrimitive) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The fallback check using !typeof(T).IsPrimitive may not accurately determine if T contains references for value types. Please add a clarifying comment that explains this assumption, given that in current usages T is always a primitive unmanaged type.
Copilot uses AI. Check for mistakes.
#if NET || NETSTANDARD2_1_OR_GREATER | ||
if (RuntimeHelpers.IsReferenceOrContainsReferences<T>()) | ||
#else | ||
if (!typeof(T).IsPrimitive) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar to the Dispose method, the Grow method uses the !typeof(T).IsPrimitive check as a fallback. Consider adding a comment here to clarify that this condition is acceptable because T is ensured to be a primitive unmanaged type in all current contexts.
Copilot uses AI. Check for mistakes.
@dotnet-policy-service agree |
@@ -145,6 +145,8 @@ public Measurement(T value, in TagList tags) | |||
result = new KeyValuePair<string, object?>[count]; | |||
array.AsSpan().Slice(0, count).CopyTo(result.AsSpan()); | |||
|
|||
Array.Clear(array, 0, count); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tarekgh, the comment on this method says:
"Private helper to copy IEnumerable to array. We have it to avoid adding dependencies on System.Linq"
Why don't we want to just use LINQ's ToArray here? We're concerned about loading System.Linq.dll?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, IIRC long ago some partners were developing micro services and worked hard to reduce any new dependencies. We initially added this dependency on Linq and then later removed it because of that.
Cc @noahfalk
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we know if that's still relevant? If you're in this part of the code, you're dealing with an IEnumerable that's not a collection. I'd be a bit surprised if such consuming code was part of an application that wasn't already using System.Linq.dll somewhere. (It's also not a separate dependency requiring distribution with the app, as it's part of any .NET that would be targeted.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can try to change it and look if we see any complaints again.
@noahfalk let us know if you have more context or concern depending on Linq.
Should we rather be ensuring that This seems more like a general issue with potentially keeping objects alive and not something that should be handled per callsite prior to the return. |
It doesn't know how much to clear; it would have to clear the whole thing, which is what it does in Return when the clearArray parameter is true. |
Right, but it seems like that's better/cheaper than potentially holding onto other references for an unknown amount of time. It really seems like there should be an analyzer and/or some overload of For example, some |
It seems to me @tannergooding suggestion is a better solution here to avoid the callers of the |
Additionally, @hendriklhf if you interested to apply the change having System.Diagnostics.DiagnosticSource take dependency on Linq and then remove the code of CC @noahfalk |
Done 👍
Yes, added the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Thanks!
Now that I think about it, it might make more sense to swap which public override void Return(T[] array, bool clearArray = false)
{
ArgumentNullException.ThrowIfNull(array);
Return(array, clearArray ? array.Length : 0);
}
internal override void Return(T[] array, int lengthToClear)
{
...
} |
@hendriklhf Instead of introducing a new internal method |
I am merging this PR. We can consider moving |
I found a few places where arrays were returned to the pool but not cleared, which would undesirably keep remaining objects in the array alive.
The check for
typeof(T).IsPrimitive
is of course not 100% correct, but, if I'm not mistaken,T
is never a non-primitive unmanaged type in all current usages.