Skip to content

Conversation

GrabYourPitchforks
Copy link
Member

Summary

Significantly fleshes out the docs for Unsafe, including:

  • Using more accurate terminology, such as using "managed pointer" instead of "reference" in APIs which are performing pointer manipulation. With this change I'm trying to reserve the word "reference" for APIs which are reading & writing values rather than performing pointer manipulation.
  • Writing the API's assumptions in the Remarks section, alongside ECMA sections we expect callers to be familiar with.

The changes for MemoryMarshal are a bit tamer by comparison:

  • Adding missing "this API can throw OverflowException" lines.
  • Removing incorrect references to "T can't contain pointers."
  • Removing incorrect references to "this method ensures type safety."

@GrabYourPitchforks
Copy link
Member Author

/cc @dotnet/area-system-runtime-compilerservices for comments on the Unsafe docs changes.

@opbld34

This comment was marked as resolved.

@GrabYourPitchforks
Copy link
Member Author

BTW, I'm totally open to suggestions on how we might flesh out the Unsafe documentation to call out when you'd actually want to use it. If nothing else I can add a "here's how you reverse a span with no bounds checks" sample, which would show GetReference, Add, Subtract, and IsAddressLessThan. But something with a bit more oomph might be better.

@opbld31
Copy link

opbld31 commented May 24, 2022

Docs Build status updates of commit d48b85b:

⚠️ Validation status: warnings

File Status Preview URL Details
xml/System.Runtime.CompilerServices/Unsafe.xml ⚠️Warning View Details
xml/System.Runtime.InteropServices/MemoryMarshal.xml ✅Succeeded View

xml/System.Runtime.CompilerServices/Unsafe.xml

  • Line 0, Column 0: [Warning: ECMA2Yaml_MemberNameAndSignature_NotUnique] Member InitBlockUnaligned's name and signature is not unique

For more details, please refer to the build report.

If you see build warnings/errors with permission issues, it might be due to single sign-on (SSO) enabled on Microsoft's GitHub organizations. Please follow instructions here to re-authorize your GitHub account to Docs Build.

Note: Broken links written as relative paths are included in the above build report. For broken links written as absolute paths or external URLs, see the broken link report.

Note: Your PR may contain errors or warnings unrelated to the files you changed. This happens when external dependencies like GitHub alias, Microsoft alias, cross repo links are updated. Please use these instructions to resolve them.

For any questions, please:

Copy link
Contributor

@gewarren gewarren left a comment

Choose a reason for hiding this comment

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

Should we add a link for the references to ECMA 335? https://www.ecma-international.org/publications-and-standards/standards/ecma-335/

<returns>A new reference that reflects the addition of offset to pointer.</returns>
<remarks>To be added.</remarks>
<summary>Adds an element offset to the given managed pointer.</summary>
<returns>A new managed pointer that reflects the addition of offset to the source pointer.</returns>
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
<returns>A new managed pointer that reflects the addition of offset to the source pointer.</returns>
<returns>A new managed pointer that reflects the addition of the specified offset to the source pointer.</returns>

Copy link
Member

Choose a reason for hiding this comment

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

The return here is a ref, so interior pointer? Unsure the language to use to differentiate the ref T and T.

Copy link
Member Author

Choose a reason for hiding this comment

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

The pattern I've tried to follow throughout the doc is that I reserve reference for instances where the API shape involves T* or T& and where the operation involves reading or writing a full T at that address. You'll see this in APIs like Copy.

For APIs that perform arithmetic or comparisons against the pointer value rather than dereference it, I use [un]managed pointer, as this terminology matches the ECMA sections listed in the type's Summary section.

For APIs like ReadUnaligned, I take a little bit of license here. Nominally the overloads would've been ReadUnaligned<T>(void*) and ReadUnaligned<T>(void&), which .NET fully supports but which C# disallows. In both of those cases they're taking void pointers, but they're not dereferencing a void. They're instead performing a read or write of some differently-sized data at that address. Since they're not dereferencing a void I opted to use the terminology [un]managed pointer here rather than reference, since IMO it's more accurate.

## Remarks
The returned span does not include the `null` terminator, nor does it validate the well-formedness of the UTF8 data.
This method is typically used with narrow character strings, such as ANSI or UTF-8 strings. The returned span does not include the `null` terminator, nor does it validate the well-formedness of the narrow character data.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
This method is typically used with narrow character strings, such as ANSI or UTF-8 strings. The returned span does not include the `null` terminator, nor does it validate the well-formedness of the narrow character data.
This method is typically used with narrow character strings, such as ANSI or UTF-8 strings. The returned span does not include the `null` terminator, nor does it validate whether the narrow character data is well-formed.

Copy link
Contributor

Choose a reason for hiding this comment

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

Might be better for localization.

Copy link
Member Author

Choose a reason for hiding this comment

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

I reworded this sentence entirely. Hopefully it's more clear now. :)

> [!WARNING]
> This type is intended for advanced pointer manipulation scenarios. Callers are assumed to be familiar with ECMA-335, Sec. II.14.4 and III.1.1.5, and with the [ECMA-335 CLI Specification Addendum](https://github.com/dotnet/runtime/blob/main/docs/design/specs/Ecma-335-Augments.md).
>
> Most APIs on this type do not perform any argument checking or validation. Incorrect use of these APIs could destabilize the .NET runtime.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
> Most APIs on this type do not perform any argument checking or validation. Incorrect use of these APIs could destabilize the .NET runtime.
> Most APIs on this type do not perform any argument checking or validation. Incorrect use of these APIs could lead to access violations, GC holes or destabilize the .NET runtime.

Came into my mind when reading this.
In essence it's similar, but to put some emphasis on the AV, and GC holes.

Copy link
Member Author

Choose a reason for hiding this comment

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

Wanted to keep the Warnings section somewhat understandable by all devs, so I'll move the mention of GC holes later in the remarks section.

Copy link
Member

Choose a reason for hiding this comment

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

I'd argue that if the a dev doesn't understand access violation or gc hole then they shouldn't be using Unsafe.

## Remarks
The `byteOffset` parameter is the number of bytes to add to the `source` pointer. For example, given a source pointer _ptr_ of type `ref int`, the call `Unsafe.AddByteOffset<int>(ref ptr, 20)` will return a new pointer whose address points 20 bytes beyond _ptr_.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
The `byteOffset` parameter is the number of bytes to add to the `source` pointer. For example, given a source pointer _ptr_ of type `ref int`, the call `Unsafe.AddByteOffset<int>(ref ptr, 20)` will return a new pointer whose address points 20 bytes beyond _ptr_.
The `byteOffset` parameter is the number of bytes to add to the managed `source` pointer. For example, given a managed source pointer _ptr_ of type `ref int`, the call `Unsafe.AddByteOffset<int>(ref ptr, 20)` will return a new managed pointer whose address points 20 bytes beyond _ptr_.

Is this overkill to add managed to pointer?
To distinguish between native- / raw-pointers (void*) and managed pointers (ref T) here?
Out of the context it's very clear what is meant, and the APIs are targeting advanced users, so this shouldn't be needed.
But as docs they should be very precise, even for people that don't know these differences and to avoid potential confusion.

This would apply to other places as well.

<returns>A new reference that reflects the addition of offset to pointer.</returns>
<remarks>To be added.</remarks>
<summary>Adds an element offset to the given managed pointer.</summary>
<returns>A new managed pointer that reflects the addition of offset to the source pointer.</returns>
Copy link
Member

Choose a reason for hiding this comment

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

The return here is a ref, so interior pointer? Unsure the language to use to differentiate the ref T and T.

<summary>Adds an element offset to the given void pointer.</summary>
<returns>A new void pointer that reflects the addition of offset to the specified pointer.</returns>
<remarks>To be added.</remarks>
<summary>Adds an element offset to the given unmanaged pointer.</summary>
Copy link
Member

Choose a reason for hiding this comment

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

if we're touching this anyways, can we order this "properly":

<summary></summary>
<typeparam name=""></typeparam>
<param name=""></param>
<returns></returns>
<remarks></remarks>

Copy link
Member

Choose a reason for hiding this comment

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

(Noting "properly" is defined here as the order VS declares these by default when you type /// and matches a good reading order for understanding the method)

Copy link
Member Author

Choose a reason for hiding this comment

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

@gewarren Thoughts on this? I'm looking through a small sample of other .xml files in the repo, and the consistent pattern I see is "typeparam, param, summary, returns, remarks." If we wanted to reorder this to be more proper I wonder if that should be something that's done repo-wide rather than as a one-off inside this file.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, I don't think it's worthwhile to reorder the tags. Also, I have a suspicion that mdoc will just reorder them the next time we update the APIs.

Copy link
Member

Choose a reason for hiding this comment

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

Is it worth a tracking issue for mdoc to be updated? It's definitely much harder to read/review these files because of the difference

Copy link
Contributor

Choose a reason for hiding this comment

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

</remarks>
</Docs>
</Member>
<Member MemberName="Unbox&lt;T&gt;">
Copy link
Member

Choose a reason for hiding this comment

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

not changes to Unbox?

Copy link
Member Author

Choose a reason for hiding this comment

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

We recently updated the Unbox docs and I couldn't think of anything new to say. If you have suggestions I can definitely fold them in to this PR!

@opbld31

This comment was marked as resolved.

@GrabYourPitchforks
Copy link
Member Author

@gewarren Any idea why the validation system is producing this warning?

Member InitBlockUnaligned's name and signature is not unique

Nothing really jumps out at me. It seems to follow the pattern for CopyBlockUnaligned closely, and that method isn't generating warnings.

@gewarren
Copy link
Contributor

@gewarren Any idea why the validation system is producing this warning?

Member InitBlockUnaligned's name and signature is not unique

Nothing really jumps out at me. It seems to follow the pattern for CopyBlockUnaligned closely, and that method isn't generating warnings.

It should go away the next time the build completes. I believe it was due to your copy/paste error - #8097 (comment).

@opbld33

This comment was marked as outdated.

@opbld31

This comment was marked as outdated.

@opbld33

This comment was marked as outdated.

@opbld33
Copy link

opbld33 commented May 26, 2022

Docs Build status updates of commit 28630d1:

⚠️ Validation status: warnings

File Status Preview URL Details
xml/System.Runtime.CompilerServices/Unsafe.xml ⚠️Warning View Details
xml/System.Runtime.InteropServices/MemoryMarshal.xml ✅Succeeded View

xml/System.Runtime.CompilerServices/Unsafe.xml

  • Line 0, Column 0: [Warning: xref-not-found] Cross reference not found: 'System.Buffer.MemoryCopy'.
  • Line 0, Column 0: [Warning: xref-not-found] Cross reference not found: 'System.Buffer.MemoryCopy'.
  • Line 0, Column 0: [Warning: xref-not-found] Cross reference not found: 'System.Buffer.MemoryCopy'.
  • Line 0, Column 0: [Warning: xref-not-found] Cross reference not found: 'System.Buffer.MemoryCopy'.

For more details, please refer to the build report.

If you see build warnings/errors with permission issues, it might be due to single sign-on (SSO) enabled on Microsoft's GitHub organizations. Please follow instructions here to re-authorize your GitHub account to Docs Build.

Note: Broken links written as relative paths are included in the above build report. For broken links written as absolute paths or external URLs, see the broken link report.

Note: Your PR may contain errors or warnings unrelated to the files you changed. This happens when external dependencies like GitHub alias, Microsoft alias, cross repo links are updated. Please use these instructions to resolve them.

For any questions, please:

@GrabYourPitchforks
Copy link
Member Author

@gewarren I think we're almost there! But the docs engine is complaining about the xref in this sentence:

Consider instead using <xref:System.Buffer.MemoryCopy> or <xref:System.Span%601.CopyTo%2A> for this scenario.

I'm trying to link to https://docs.microsoft.com/dotnet/api/system.buffer.memorycopy. Am I using the wrong syntax here?

@gewarren
Copy link
Contributor

@gewarren I think we're almost there! But the docs engine is complaining about the xref in this sentence:

Consider instead using <xref:System.Buffer.MemoryCopy> or <xref:System.Span%601.CopyTo%2A> for this scenario.

I'm trying to link to https://docs.microsoft.com/dotnet/api/system.buffer.memorycopy. Am I using the wrong syntax here?

Yes, since there's more than one overload, you need to add the asterisk, so <xref:System.Buffer.MemoryCopy%2A>.

@opbld30
Copy link

opbld30 commented May 27, 2022

Docs Build status updates of commit 94a22a1:

✅ Validation status: passed

File Status Preview URL Details
xml/System.Runtime.CompilerServices/Unsafe.xml ✅Succeeded View
xml/System.Runtime.InteropServices/MemoryMarshal.xml ✅Succeeded View

For more details, please refer to the build report.

Note: Broken links written as relative paths are included in the above build report. For broken links written as absolute paths or external URLs, see the broken link report.

For any questions, please:

@GrabYourPitchforks
Copy link
Member Author

GrabYourPitchforks commented May 27, 2022

Thanks kindly @gewarren @tannergooding @AaronRobinsonMSFT @gfoidl for your input! 🥳

I'm going to merge this shortly because I think all of the high-priority feedback has been addressed. We can send smaller PRs if we find nits later on.

@GrabYourPitchforks GrabYourPitchforks merged commit 242605d into dotnet:main May 28, 2022
@GrabYourPitchforks GrabYourPitchforks deleted the unsafe_as branch May 28, 2022 00:04
@MSDN-WhiteKnight MSDN-WhiteKnight mentioned this pull request Jun 30, 2022
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.

9 participants