Skip to content
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

StringSegment IndexOf behavior #53727

Closed
hrrrrustic opened this issue Jun 4, 2021 · 7 comments · Fixed by #55501
Closed

StringSegment IndexOf behavior #53727

hrrrrustic opened this issue Jun 4, 2021 · 7 comments · Fixed by #55501

Comments

@hrrrrustic
Copy link
Contributor

hrrrrustic commented Jun 4, 2021

Description

Working on reopening PR for #45021 (first one was closed due to inactivity)
Found a few more strange behaviors

First:
There is no check for the right bound in IndexOf like in the IndexOfAny
IndexOfAny:

if (startIndex < 0 || Offset + startIndex > Buffer.Length)
{
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
}
if (count < 0 || Offset + startIndex + count > Buffer.Length)
{
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.count);
}
index = Buffer.IndexOfAny(anyOf, Offset + startIndex, count);

IndexOf:

if (!HasValue || start < 0 || (uint)offset > (uint)Buffer.Length)
{
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
}
if (count < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.count);
}
int index = AsSpan().Slice(start, count).IndexOf(c);

Anyway, exception will be thrown in Span<T>.Slice method (exception message will be a little different), but I don't think this is by design 😄

Second:
Check for the right bound above (IndexOfAny) is quite weird, it allows to get index from original string
Example:

public static void Main(string[] args)
        {
            StringSegment segment = new StringSegment("12345", 0, 1);
            var index = segment.IndexOfAny(new[] { '5' }, 2, 3);
            Console.WriteLine(index); // Prints 4 
        }

I believe that correct value here should be -1, am I missing something?
UPD: OutOfRangeException should be thrown
So it seems like Buffer.Length have to be replaced with Length property

Regression?

Fixes will be breaking changes, but for the original issue (#45021) it was ok #46432 (comment)

@dotnet-issue-labeler dotnet-issue-labeler bot added the untriaged New issue has not been triaged by the area owner label Jun 4, 2021
@dotnet-issue-labeler
Copy link

I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label.

@hrrrrustic
Copy link
Contributor Author

hrrrrustic commented Jun 4, 2021

@gfoidl @tarekgh @davidfowl (You reviewed/commented PR #46432)
Btw, is it possible to unlock old PR or I have to create new one?

@ghost
Copy link

ghost commented Jun 4, 2021

Tagging subscribers to this area: @eerhardt, @maryamariyan
See info in area-owners.md if you want to be subscribed.

Issue Details

Description

Working on reopening PR for #45021 (first one was closed due to inactivity)
Found a few more strange behaviors

First:
There is no check for the right bound in IndexOf like in the IndexOfAny
IndexOfAny:

if (startIndex < 0 || Offset + startIndex > Buffer.Length)
{
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
}
if (count < 0 || Offset + startIndex + count > Buffer.Length)
{
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.count);
}
index = Buffer.IndexOfAny(anyOf, Offset + startIndex, count);

IndexOf:

if (!HasValue || start < 0 || (uint)offset > (uint)Buffer.Length)
{
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
}
if (count < 0)
{
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.count);
}
int index = AsSpan().Slice(start, count).IndexOf(c);

Anyway, exception will be thrown in Span<T>.Slice method (exception message will be a little different), but I don't think this is by design 😄

Second:
Check for the right bound above (IndexOfAny) is quite weird, it allows to get index from original string
Example:

public static void Main(string[] args)
        {
            StringSegment segment = new StringSegment("12345", 0, 1);
            var index = segment.IndexOfAny(new[] { '5' }, 2, 3);
            Console.WriteLine(index); // Prints 4 
        }

I believe that correct value here should be -1, am I missing something?
So it seems like Buffer.Length have to be replaced with Length property

Regression?

Fixes will be breaking changes, but for the original issue (#45021) it was ok #46432 (comment)

Author: hrrrrustic
Assignees: -
Labels:

area-Extensions-Primitives, untriaged

Milestone: -

@gfoidl
Copy link
Member

gfoidl commented Jun 4, 2021

exception will be thrown in Span.Slice method (exception message will be a little different), but I don't think this is by design

You are right. In #53463 (comment) it was similar, and the argument validation was kept (to throw the correct exception with the right paramName).

@tarekgh
Copy link
Member

tarekgh commented Jun 14, 2021

CC @GrabYourPitchforks

@tarekgh
Copy link
Member

tarekgh commented Jun 14, 2021

@hrrrrustic

Btw, is it possible to unlock old PR or I have to create new one?

Could you please open a new PR if it is handy? Thanks!

@tarekgh tarekgh added bug and removed untriaged New issue has not been triaged by the area owner labels Jun 14, 2021
@tarekgh tarekgh added this to the 6.0.0 milestone Jun 14, 2021
@villarst
Copy link

villarst commented Jul 8, 2021

Very weird. I tried testing with var index1 = segment.IndexOfAny(new[] { '5' }, 0, 5); and var index2 = segment.IndexOfAny(new[] { '5' }); which resulted in 4 and -1 respectively. The only way you will get 4 as an output while having '5' as your char argument is if you have the index of '5' be included in the two int arguments for IndexOfAny (char[] anyOf, int startIndex, int count);. Essentially you have to let it be hit or passed for a 4 to be outputted.

My guess for why var index1 = segment.IndexOfAny(new[] { '5' }, 0, 5); is outputting a 4 is because when the IndexOfAny method is being called it is referring to the original string that is being passed in when we call StringSegment segment = new StringSegment("12345", 0, 1);

I also tested var index3 = segment.IndexOfAny(new[] { '4' }, 1, 3); to see if maybe it was because the '5' was at the end of the string but I was still able to get a number other than -1 which was 3.

@ghost ghost added the in-pr There is an active PR which will close this issue when it is merged label Jul 12, 2021
@ghost ghost removed the in-pr There is an active PR which will close this issue when it is merged label Jul 15, 2021
@ghost ghost locked as resolved and limited conversation to collaborators Aug 14, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants