-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Replace signed comparisons with unsigned comparisons in bounds checking ImmutableArray<T>.Builder
#120877
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
base: main
Are you sure you want to change the base?
Conversation
…ng ImmutableArray<T>.Builder indexer and ItemRef method.
Any specific pattern you're trying to improve? can you provide before/after asm for it? Although, your change kind of makes sense to me, It looks like it's mostly a regression, see MihuBot/runtime-utils#1584 (comment) |
What is the motivation for the change, is it a correctness issue? |
@EgorBo Thanks for the feedback. With the current implementation, negative indices pass the bounds check ( However, I understand that this change leads to a significant performance regression as shown in MihuBot/runtime-utils#1584. Considering performance regression, would you prefer that I close this PR? |
Ah, I see. Looks like in both cases exactly the same exception is thrown - too big index:
negative index:
|
The stack trace differs only because |
I don't think we have a rule to slap that attribute on the throw helpers. in Release, stack-traces get cut due to inlining and tail-calls heavily, so we'd better not hide frames which may help identify the actual source of the exception |
|
Yes, I'm aware that we already have it |
Upon closer inspection, the regressions shown in MihuBot/runtime-utils#1584 (comment) appear to be caused by the indexer used in This is a bit different from the main proposal, but what if we made
public IEnumerator<T> GetEnumerator()
{
for (int i = 0; i < this.Count; i++)
{
yield return this[i];
}
}
public IEnumerator<T> GetEnumerator()
{
return new Enumerator(this);
}
private struct Enumerator : IEnumerator<T>, IEnumerator
{
private readonly Builder _builder;
private int _index;
private T? _current;
internal Enumerator(Builder builder)
{
_builder = builder;
}
public void Dispose()
{ }
public bool MoveNext()
{
Builder builder = _builder;
if ((uint)_index < (uint)builder._count)
{
_current = builder._elements[_index];
_index++;
return true;
}
_current = default;
_index = -1;
return false;
}
public T Current => _current!;
object? IEnumerator.Current => this.Current;
void IEnumerator.Reset()
{
_index = 0;
_current = default;
}
} |
This PR replaces signed comparisons with unsigned comparisons in bounds checking for
ImmutableArray<T>.Builder
indexer andItemRef
method. Change bounds check fromif (index >= this.Count)
toif ((uint)index >= (uint)this.Count)
.