Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Conversation

@stephentoub
Copy link
Member

This routine was written for parsing strings, which are implicitly null-terminated, and it doesn't factor in string length but instead uses tricks to exit loops when the next character is null. Now that the routine is also used for spans, this is very problematic, as spans need not be null terminated, and generally aren't when they represent slices, and expecting a null termination like this can result in walking off the end of valid memory.

I would like to see all of this code rewritten to use span. In the interim, though, as a short-term fix I've changed all dereferences of the current position to compare against the length of the span (or, rather, a pointer to the end), and pretend that a null terminator was found if we've hit the end.

Contributes to https://github.com/dotnet/corefx/issues/29343
cc: @jkotas, @danmosemsft

This routine was written for parsing strings, which are implicitly null-terminated, and it doesn't factor in string length but instead uses tricks to exit loops when the next character is null.  Now that the routine is also used for spans, this is very problematic, as spans need not be null terminated, and generally aren't when they represent slices, and expecting a null termination like this can result in walking off the end of valid memory.

I would like to see all of this code rewritten to use span.  In the interim, though, as a short-term fix I've changed all dereferences of the current position to compare against the length of the span (or, rather, a pointer to the end), and pretend that a null terminator was found if we've hit the end.
while (true)
{
char cp = p < pEnd ? *p : '\0';
if (cp != *str && (*str != '\u00a0' || cp != '\u0020'))
Copy link
Member

Choose a reason for hiding this comment

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

This is a case where I think !(*str == '\u00a0' && cp == '\u0020') would be much clearer.

Copy link
Member Author

Choose a reason for hiding this comment

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

Ok.

Copy link
Member

@danmoseley danmoseley left a comment

Choose a reason for hiding this comment

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

Ugh...

@danmoseley
Copy link
Member

In general, it is hard to prove the code in this file is safe by reading it. For example NumberBuffer is assumed to be null terminated above. And it seems it always is, but this is from several frames up, where the ReadOnlySpan<char> always originates from a string before it is parsed.

@stephentoub
Copy link
Member Author

In general, it is hard to prove the code in this file is safe by reading it.

Yes, hence my comment about wanting to see all of this rewritten. But that's too big a change to make right now.

@stephentoub stephentoub merged commit d0a55af into dotnet:master Apr 27, 2018
@stephentoub stephentoub deleted the numberparsing branch April 27, 2018 22:37
stephentoub added a commit to stephentoub/coreclr that referenced this pull request Apr 27, 2018
…t#17808)

* Fix Number.ParseNumber to not assume '\0' at the end of a span

This routine was written for parsing strings, which are implicitly null-terminated, and it doesn't factor in string length but instead uses tricks to exit loops when the next character is null.  Now that the routine is also used for spans, this is very problematic, as spans need not be null terminated, and generally aren't when they represent slices, and expecting a null termination like this can result in walking off the end of valid memory.

I would like to see all of this code rewritten to use span.  In the interim, though, as a short-term fix I've changed all dereferences of the current position to compare against the length of the span (or, rather, a pointer to the end), and pretend that a null terminator was found if we've hit the end.

* Address PR feedback
stephentoub added a commit that referenced this pull request Apr 30, 2018
… (#17820)

* Fix Number.ParseNumber to not assume '\0' at the end of a span

This routine was written for parsing strings, which are implicitly null-terminated, and it doesn't factor in string length but instead uses tricks to exit loops when the next character is null.  Now that the routine is also used for spans, this is very problematic, as spans need not be null terminated, and generally aren't when they represent slices, and expecting a null termination like this can result in walking off the end of valid memory.

I would like to see all of this code rewritten to use span.  In the interim, though, as a short-term fix I've changed all dereferences of the current position to compare against the length of the span (or, rather, a pointer to the end), and pretend that a null terminator was found if we've hit the end.

* Address PR feedback
@danmoseley
Copy link
Member

I would like to see all of this code rewritten to use span.

@stephentoub do we need an issue to track this? I can't find one.

@stephentoub
Copy link
Member Author

I don't believe we have one.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants