From c8663074aed8ae27ab9c222b67e289f80995fda0 Mon Sep 17 00:00:00 2001 From: Levi Broderick Date: Mon, 23 May 2022 16:24:23 -0700 Subject: [PATCH 1/9] Update Unsafe and MemoryMarshal docs --- .../Unsafe.xml | 715 ++++++++++++++---- .../MemoryMarshal.xml | 94 ++- 2 files changed, 616 insertions(+), 193 deletions(-) diff --git a/xml/System.Runtime.CompilerServices/Unsafe.xml b/xml/System.Runtime.CompilerServices/Unsafe.xml index f7f5505fccf..53e8075ccb3 100644 --- a/xml/System.Runtime.CompilerServices/Unsafe.xml +++ b/xml/System.Runtime.CompilerServices/Unsafe.xml @@ -25,8 +25,19 @@ - Contains generic, low-level functionality for manipulating pointers. - To be added. + Contains generic, low-level functionality for manipulating managed and unmanaged pointers. + + [!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. + +]]> + @@ -60,12 +71,22 @@ - The type of void pointer. - The void pointer to add the offset to. + The type whose width will be used as a scale factor for `elementOffset`. + The unmanaged pointer to add the offset to. The offset to add. - Adds an element offset to the given void pointer. - A new void pointer that reflects the addition of offset to the specified pointer. - To be added. + Adds an element offset to the given unmanaged pointer. + A new unmanaged pointer that reflects the addition of offset to the source pointer. + + (ptr, 20)` will return a new pointer whose address points 80 bytes (= 20 elements \* 4 bytes per element) beyond _ptr_. + +If `elementOffset` is a calculated value rather than a hardcoded literal, callers should consider the possibility of integer overflow and should take appropriate precautions. + +]]> + @@ -101,12 +122,22 @@ - The type of reference. - The reference to add the offset to. + The elemental type of the managed pointer. + The managed pointer to add the offset to. The offset to add. - Adds an element offset to the given reference. - A new reference that reflects the addition of offset to pointer. - To be added. + Adds an offset to the given managed pointer. + A new managed pointer that reflects the addition of offset to the source pointer. + + (ref ptr, 20)` will return a new pointer whose address points 80 bytes (= 20 elements \* 4 bytes per element) beyond _ptr_. + +If `elementOffset` is a calculated value rather than a hardcoded literal, callers should consider the possibility of integer overflow and should take appropriate precautions. + +]]> + @@ -141,12 +172,22 @@ - The type of reference. - The reference to add the offset to. + The elemental type of the managed pointer. + The managed pointer to add the offset to. The offset to add. - Adds an element offset to the given reference. - A new reference that reflects the addition of offset to pointer. - To be added. + Adds an element offset to the given managed pointer. + A new managed pointer that reflects the addition of offset to the source pointer. + + (ref ptr, (nint)20)` will return a new pointer whose address points 80 bytes (= 20 elements \* 4 bytes per element) beyond _ptr_. + +If `elementOffset` is a calculated value rather than a hardcoded literal, callers should consider the possibility of integer overflow and should take appropriate precautions. + +]]> + @@ -183,12 +224,22 @@ - The type of reference. - The reference to add the offset to. + The elemental type of the managed pointer. + The managed pointer to add the offset to. The offset to add. - Adds an element offset to the given reference. - A new reference that reflects the addition of offset to pointer. - To be added. + Adds an element offset to the given managed pointer. + A new managed pointer that reflects the addition of offset to the source pointer. + + (ref ptr, (nuint)20)` will return a new pointer whose address points 20 bytes (= 10 elements \* 4 bytes per element) beyond _ptr_. + +If `elementOffset` is a calculated value rather than a hardcoded literal, callers should consider the possibility of integer overflow and should take appropriate precautions. + +]]> + @@ -223,12 +274,22 @@ - The type of reference. - The reference to add the offset to. + The elemental type of the managed pointer. + The managed pointer to add the offset to. The offset to add. - Adds a byte offset to the given reference. - A new reference that reflects the addition of byte offset to pointer. - To be added. + Adds a byte offset to the given managed pointer. + A new managed pointer that reflects the addition of byte offset to the source pointer. + + (ref ptr, 20)` will return a new pointer whose address points 20 bytes beyond _ptr_. + +If `elementOffset` is a calculated value rather than a hardcoded literal, callers should consider the possibility of integer overflow and should take appropriate precautions. + +]]> + @@ -265,12 +326,22 @@ - The type of reference. - The reference to add the offset to. + The elemental type of the managed pointer. + The managed pointer to add the offset to. The offset to add. - Adds a byte offset to the given reference. - A new reference that reflects the addition of byte offset to pointer. - To be added. + Adds a byte offset to the given managed pointer. + A new managed pointer that reflects the addition of byte offset to the source pointer. + + (ref ptr, (nuint)20)` will return a new pointer whose address points 20 bytes beyond _ptr_. + +If `elementOffset` is a calculated value rather than a hardcoded literal, callers should consider the possibility of integer overflow and should take appropriate precautions. + +]]> + @@ -320,10 +391,10 @@ - The type of reference. - The first reference to compare. - The second reference to compare. - Determines whether the specified references point to the same location. + The elemental type of the managed pointers. + The first managed pointer to compare. + The second managed pointer to compare. + Determines whether the specified managed pointers point to the same location. if and point to the same location; otherwise, . To be added. @@ -370,8 +441,18 @@ The type which the object will be cast to. The object to cast. Casts the given object to the specified type. - The original object, casted to the given type. - To be added. + The original object, cast to the given type. + + (o)` is only well-defined if the typical "safe" casting operation `(T)o` would have succeeded. Use of this API to circumvent casts that would otherwise have failed is unsupported and could result in runtime instability. + +]]> + @@ -407,12 +488,33 @@ - The type of reference to reinterpret. - The desired type of the reference. - The reference to reinterpret. - Reinterprets the given reference as a reference to a value of type . - A reference to a value of type . - To be added. + The type of managed pointer to reinterpret. + The desired type of the managed pointer. + The managed pointer to reinterpret. + Reinterprets the given managed pointer as a new managed pointer to a value of type . + A managed pointer to a value of type . + + `. It is the caller's responsibility to ensure that the cast is legal. No runtime check will be performed. + +Only the managed pointer is reinterpreted. The referenced value itself will remain unchanged. Consider the example below. + +```cs +int[] intArray = new int[] { 0x12345678 }; // a 1-element array +ref int refToInt32 = ref intArray[0]; // managed pointer to first Int32 in array +ref short refToInt16 = ref Unsafe.As(ref refToInt32); // reinterpret as managed pointer to Int16 +Console.WriteLine(refToInt16); +``` + +The output of this program depends on the endianness of the current machine. On big-endian architectures this will output `0x1234`, and on little-endian architectures this will output `0x5678`. + +When casting a managed pointer from a narrower type to a wider type, the caller must ensure that dereferencing the pointer will not incur an out-of-bounds access. The caller is also responsible for ensuring that the resulting pointer is properly aligned for the referenced type. + + ]]> + @@ -447,11 +549,21 @@ - The type of object. - The object whose pointer is obtained. - Returns a pointer to the given by-ref parameter. - A pointer to the given value. - To be added. + The elemental type of the managed pointer. + The managed pointer to convert. + Converts a managed pointer into an unmanaged pointer. + An unmanaged pointer corresponding to the original source pointer. + + + @@ -486,10 +598,10 @@ - The type of the interpreted location. - The location of the value to reference. - Reinterprets the given location as a reference to a value of type . - A reference to a value of type . + The elemental type of the managed pointer. + The unmanaged pointer to convert. + Converts an unmanaged pointer into a managed pointer to a value of type . + A managed pointer to a value of type . To be added. @@ -531,10 +643,10 @@ - The type of reference. + The underlying type of the reference. The read-only reference to reinterpret. - Reinterprets the given read-only reference as a reference. - A reference to a value of type . + Reinterprets the given read-only reference as a mutable reference. + A mutable reference to a value of type . To be added. @@ -584,12 +696,22 @@ - The type of reference. - The reference to origin. - The reference to target. - Determines the byte offset from origin to target from the given references. + The elemental type of the managed pointers. + The managed pointer to origin. + The managed pointer to target. + Determines the byte offset from origin to target from the given managed pointers. Byte offset from origin to target i.e. - . - To be added. + + + @@ -629,7 +751,25 @@ The location to copy to. A reference to the value to copy. Copies a value of type to the given location. - To be added. + + (void* destination, ref T source) +{ + T data = source; // dereference source + *(T*)destination = data; +} +``` + + ]]> + @@ -669,7 +809,25 @@ The location to copy to. A pointer to the value to copy. Copies a value of type to the given location. - To be added. + + (ref T destination, void* source) +{ + T data = *(T*)source; // cast source to T* and dereference + destination = data; +} +``` + + ]]> + @@ -702,11 +860,21 @@ - The destination address to copy to. - The source address to copy from. + The managed pointer corresponding to the destination address to copy to. + The managed pointer corresponding to the source address to copy from. The number of bytes to copy. Copies bytes from the source address to the destination address. - To be added. + + + @@ -740,11 +908,21 @@ - The destination address to copy to. - The source address to copy from. + The unmanaged pointer corresponding to the destination address to copy to. + The unmanaged pointer corresponding to the source address to copy from. The number of bytes to copy. Copies bytes from the source address to the destination address. - To be added. + + + @@ -777,11 +955,21 @@ - The destination address to copy to. - The source address to copy from. + The managed pointer corresponding to the destination address to copy to. + The managed pointer corresponding to the source address to copy from. The number of bytes to copy. Copies bytes from the source address to the destination address without assuming architecture dependent alignment of the addresses. - To be added. + + + @@ -813,11 +1001,21 @@ - The destination address to copy to. - The source address to copy from. + The unmanaged pointer corresponding to the destination address to copy to. + The unmanaged pointer corresponding to the source address to copy from. The number of bytes to copy. Copies bytes from the source address to the destination address without assuming architecture dependent alignment of the addresses. - To be added. + + + @@ -850,11 +1048,21 @@ - The address of the start of the memory block to initialize. - The value to initialize the block to. + The managed pointer referencing the start of the memory block to initialize. + The value to initialize all bytes of the memory block to. The number of bytes to initialize. Initializes a block of memory at the given location with a given initial value. - To be added. + + + @@ -888,11 +1096,21 @@ - The address of the start of the memory block to initialize. - The value to initialize the block to. + The unmanaged pointer referencing the start of the memory block to initialize. + The value to initialize all bytes of the memory block to. The number of bytes to initialize. Initializes a block of memory at the given location with a given initial value. - To be added. + + + @@ -925,11 +1143,21 @@ - The address of the start of the memory block to initialize. - The value to initialize the block to. + The managed pointer referencing the start of the memory block to initialize. + The value to initialize all bytes of the memory block to. The number of bytes to initialize. Initializes a block of memory at the given location with a given initial value without assuming architecture dependent alignment of the address. - To be added. + + + @@ -956,16 +1184,21 @@ System.Void - - - - - - The address of the start of the memory block to initialize. - The value to initialize the block to. + The unmanaged pointer referencing the start of the memory block to initialize. + The value to initialize all bytes of the memory block to. The number of bytes to initialize. Initializes a block of memory at the given location with a given initial value without assuming architecture dependent alignment of the address. - To be added. + + + @@ -1014,10 +1247,10 @@ - The type of the reference. - The first value to compare. - The second value to compare. - Returns a value that indicates whether a specified reference is greater than another specified reference. + The elemental type of the managed pointer. + The first managed pointer to compare. + The second managed pointer to compare. + Returns a value that indicates whether a specified managed pointer is greater than another specified managed pointer. if is greater than ; otherwise, . @@ -1027,6 +1260,10 @@ This check is conceptually similar to `(void*)(&left) > (void*)(&right)`. +The return value of this method is a moment-in-time result. If `left` and `right` each reference different objects in GC-managed address space, the GC could relocate items between calls, causing the result of this method to change. + +The return value is guaranteed stable if `left` and `right` point to the same managed object. + ]]> @@ -1077,10 +1314,10 @@ This check is conceptually similar to `(void*)(&left) > (void*)(&right)`. - The type of the reference. - The first value to compare. - The second value to compare. - Returns a value that indicates whether a specified reference is less than another specified reference. + The elemental type of the managed pointer. + The first managed pointer to compare. + The second managed pointer to compare. + Returns a value that indicates whether a specified managed pointer is less than another specified managed pointer. if is less than ; otherwise, . @@ -1090,6 +1327,10 @@ This check is conceptually similar to `(void*)(&left) > (void*)(&right)`. This check is conceptually similar to `(void*)(&left) < (void*)(&right)`. +The return value of this method is a moment-in-time result. If `left` and `right` each reference different objects in GC-managed address space, the GC could relocate items between calls, causing the result of this method to change. + +The return value is guaranteed stable if `left` and `right` point to the same managed object. + ]]> @@ -1121,9 +1362,9 @@ This check is conceptually similar to `(void*)(&left) < (void*)(&right)`. - The type of the reference. - The reference to check. - Determines if a given reference to a value of type is a null reference. + The elemental type of the managed pointer. + The managed pointer to check. + Determines if a given managed pointer to a value of type is a null reference. if is a null reference; otherwise, . This check is conceptually similar to (void*)(&source) == nullptr. @@ -1154,10 +1395,10 @@ This check is conceptually similar to `(void*)(&left) < (void*)(&right)`. - The type of the reference. - Returns a reference to a value of type that is a null reference. - A reference to a value of type that is a null reference. - To be added. + The elemental type of the managed pointer. + Returns a null managed pointer to a value of type . + A null managed pointer to a value of type . + The return value is conceptually similar to ref *((T*)nullptr). @@ -1192,12 +1433,20 @@ This check is conceptually similar to `(void*)(&left) < (void*)(&right)`. - The type to read. + The type of the value to read. The location to read from. Reads a value of type from the given location. - An object of type read from the given location. - To be added. + A value of type read from the given location. + + + @@ -1231,10 +1480,10 @@ This check is conceptually similar to `(void*)(&left) < (void*)(&right)`. - The type to read. - The location to read from. - Reads a value of type from the given location without assuming architecture dependent alignment of the addresses. - An object of type read from the given location. + The type of the value to read. + A managed pointer containing the address to read from. + Reads a value of type from the given address without assuming architecture dependent alignment of the source address. + A value of type read from the given address. To be added. @@ -1268,10 +1517,10 @@ This check is conceptually similar to `(void*)(&left) < (void*)(&right)`. - The type to read. + The type of the value to read. The location to read from. - Reads a value of type from the given location without assuming architecture dependent alignment of the addresses. - An object of type read from the given location. + Reads a value of type from the given location without assuming architecture dependent alignment of the source address. + A value of type read from the given location. To be added. @@ -1306,10 +1555,23 @@ This check is conceptually similar to `(void*)(&left) < (void*)(&right)`. - The type of object whose size is retrieved. - Returns the size of an object of the given type parameter. - The size of an object of type . - To be added. + The type whose size is retrieved. + Returns the size of a value of the given type parameter. + The size (in bytes) of a value of type . + + [!CAUTION] +> This API returns the size of the _managed_ view of the type. For the size of the _unmanaged_ view of the type, such as for interop purposes, use . + +This API corresponds to the `sizeof` opcode. + +If `T` is a reference type, the return value is the size of the reference itself, or `IntPtr.Size`. See ECMA-335, Sec. Sec. III.4.25 ("sizeof - load the size, in bytes, of a type") for more information. + + ]]> + @@ -1339,10 +1601,69 @@ This check is conceptually similar to `(void*)(&left) < (void*)(&right)`. - The type of the uninitialized object. - The uninitialized object. - Bypasses definite assignment rules for a given value. - To be added. + The type of the reference. + The reference whose initialization should be skipped. + Bypasses definite assignment rules for a given reference. + + [!WARNING] +> The developer must take care to ensure that the struct has been initialized appropriately, otherwise the struct's fields could contain uninitialized data from the stack. + + ]]> + @@ -1376,12 +1697,22 @@ This check is conceptually similar to `(void*)(&left) < (void*)(&right)`. - The type of the void pointer. - The void pointer to subtract the offset from. + The type whose width will be used as a scale factor for `elementOffset`. + The unmanaged pointer to subtract the offset froms. The offset to subtract. - Subtracts an element offset from the given void pointer. - A new void pointer that reflects the subtraction of offset from the specified pointer. - To be added. + Subtracts an element offset from the given unmanaged pointer. + A new unmanaged pointer that reflects the subtraction of offset from the source pointer. + + (ptr, 10)` will return a new pointer whose address points 40 bytes (= 10 elements \* 4 bytes per element) before _ptr_. + +If `elementOffset` is a calculated value rather than a hardcoded literal, callers should consider the possibility of integer overflow and should take appropriate precautions. + +]]> + @@ -1417,12 +1748,22 @@ This check is conceptually similar to `(void*)(&left) < (void*)(&right)`. - The type of reference. - The reference to subtract the offset from. + The elemental type of the managed pointer. + The managed pointer to subtract the offset from. The offset to subtract. - Subtracts an element offset from the given reference. - A new reference that reflects the subtraction of offset from pointer. - To be added. + Subtracts an offset from the given managed pointer. + A new managed pointer that reflects the subtraction of offset from the source pointer. + + (ref ptr, 20)` will return a new pointer whose address points 80 bytes (= 20 elements \* 4 bytes per element) before _ptr_. + +If `elementOffset` is a calculated value rather than a hardcoded literal, callers should consider the possibility of integer overflow and should take appropriate precautions. + +]]> + @@ -1457,12 +1798,22 @@ This check is conceptually similar to `(void*)(&left) < (void*)(&right)`. - The type of reference. - The reference to subtract the offset from. + The elemental type of the managed pointer. + The managed pointer to subtract the offset from. The offset to subtract. - Subtracts an element offset from the given reference. - A new reference that reflects the subtraction of offset from pointer. - To be added. + Subtracts an element offset from the given managed pointer. + A new managed pointer that reflects the subtraction of offset from the source pointer. + + (ref ptr, (nint)20)` will return a new pointer whose address points 80 bytes (= 20 elements \* 4 bytes per element) before _ptr_. + +If `elementOffset` is a calculated value rather than a hardcoded literal, callers should consider the possibility of integer overflow and should take appropriate precautions. + +]]> + @@ -1499,12 +1850,22 @@ This check is conceptually similar to `(void*)(&left) < (void*)(&right)`. - The type of reference. - The reference to subtract the offset from. + The elemental type of the managed pointer. + The managed pointer to subtract the offset from. The offset to subtract. - Subtracts an element offset from the given reference. - A new reference that reflects the subraction of offset from pointer. - To be added. + Subtracts an element offset from the given managed pointer. + A new managed pointer that reflects the subtraction of offset from the source pointer. + + (ref ptr, (nuint)20)` will return a new pointer whose address points 20 bytes (= 10 elements \* 4 bytes per element) before _ptr_. + +If `elementOffset` is a calculated value rather than a hardcoded literal, callers should consider the possibility of integer overflow and should take appropriate precautions. + +]]> + @@ -1539,12 +1900,22 @@ This check is conceptually similar to `(void*)(&left) < (void*)(&right)`. - The type of reference. - The reference to subtract the offset from. + The elemental type of the managed pointer. + The managed pointer to subtract the offset from. The offset to subtract. - Subtracts a byte offset from the given reference. - A new reference that reflects the subtraction of byte offset from pointer. - To be added. + Subtracts a byte offset from the given managed pointer. + A new managed pointer that reflects the subtraction of byte offset from the source pointer. + + (ref ptr, 20)` will return a new pointer whose address points 20 bytes before _ptr_. + +If `elementOffset` is a calculated value rather than a hardcoded literal, callers should consider the possibility of integer overflow and should take appropriate precautions. + +]]> + @@ -1581,12 +1952,22 @@ This check is conceptually similar to `(void*)(&left) < (void*)(&right)`. - The type of reference. - The reference to subtract the offset from. + The elemental type of the managed pointer. + The managed pointer to subtract the offset from. The offset to subtract. - Subtracts a byte offset from the given reference. - A new reference that reflects the subraction of byte offset from pointer. - To be added. + Subtracts a byte offset from the given managed pointer. + A new managed pointer that reflects the subtraction of byte offset from the source pointer. + + (ref ptr, (nuint)20)` will return a new pointer whose address points 20 bytes before _ptr_. + +If `elementOffset` is a calculated value rather than a hardcoded literal, callers should consider the possibility of integer overflow and should take appropriate precautions. + +]]> + @@ -1695,11 +2076,19 @@ For more information, see sections III.1.8.1.2.2 ("Controlled-muttability manage - The type of value to write. + The type of the value to write. The location to write to. The value to write. Writes a value of type to the given location. - To be added. + + + @@ -1734,10 +2123,10 @@ For more information, see sections III.1.8.1.2.2 ("Controlled-muttability manage - The type of value to write. - The location to write to. + The type of the value to write. + A managed pointer containing the address to write to. The value to write. - Writes a value of type to the given location without assuming architecture dependent alignment of the addresses. + Writes a value of type to the given location without assuming architecture dependent alignment of the destination address. To be added. @@ -1772,10 +2161,10 @@ For more information, see sections III.1.8.1.2.2 ("Controlled-muttability manage - The type of value to write. - The location to write to. + The type of the value to write. + A managed pointer containing the address to write to. The value to write. - Writes a value of type to the given location without assuming architecture dependent alignment of the addresses. + Writes a value of type to the given location without assuming architecture dependent alignment of the destination address. To be added. diff --git a/xml/System.Runtime.InteropServices/MemoryMarshal.xml b/xml/System.Runtime.InteropServices/MemoryMarshal.xml index 72dce2356e0..6639a2c98b7 100644 --- a/xml/System.Runtime.InteropServices/MemoryMarshal.xml +++ b/xml/System.Runtime.InteropServices/MemoryMarshal.xml @@ -78,13 +78,16 @@ ## Remarks -`T` cannot contain pointers or references. `T` is checked at runtime in order to preserve type safety. +`T` cannot contain managed object references. The `AsBytes` method performs this check at runtime and throws `ArgumentException` if the check fails. + +> [!CAUTION] +> This method provides a raw binary projection over the original span, including over any private instance fields and other implementation details of type `T`. Callers should ensure that their code is resilient to changes in the internal layout of `T`. ]]> - contains references or pointers. - The property of the new would exceed + contains managed object references. + The property of the new would exceed . @@ -133,13 +136,16 @@ ## Remarks -`T` cannot contain pointers or references. `T` is checked at runtime in order to preserve type safety. +`T` cannot contain managed object references. The `AsBytes` method performs this check at runtime and throws `ArgumentException` if the check fails. - ]]> +> [!CAUTION] +> This method provides a raw binary projection over the original span, including over any private instance fields and other implementation details of type `T`. Callers should ensure that their code is resilient to changes in the internal layout of `T`. + + ]]> - contains references or pointers. - The property of the new would exceed + contains managed object references. + The property of the new would exceed . @@ -182,7 +188,8 @@ ## Remarks -This method must be used with extreme caution. is used to represent immutable data and other memory that is not meant to be written to. instances created by this method should not be written to. The purpose of this method is to allow variables typed as but only used for reading to store a . +> [!CAUTION] +> This method must be used with extreme caution. is used to represent immutable data and other memory that is not meant to be written to. instances created by this method should not be written to. The purpose of this method is to allow variables typed as but only used for reading to store a . ]]> @@ -238,12 +245,14 @@ This method must be used with extreme caution. ## Remarks -`T` cannot contain pointers or references. It is checked at runtime in order to preserve type safety. +`T` cannot contain managed object references. The `AsRef` method performs this check at runtime and throws `ArgumentException` if the check fails. This method is supported only on platforms that support misaligned memory access or when the memory block is aligned by other means. ]]> + + contains managed object references. @@ -290,12 +299,14 @@ This method is supported only on platforms that support misaligned memory access ## Remarks -`T` cannot contain pointers or references. It is checked at runtime in order to preserve type safety. +`T` cannot contain managed object references. The `AsRef` method performs this check at runtime and throws `ArgumentException` if the check fails. This method is supported only on platforms that support misaligned memory access or when the memory block is aligned by other means. ]]> + + contains managed object references. @@ -352,14 +363,15 @@ This method is supported only on platforms that support misaligned memory access ## Remarks -Neither `TFrom` nor `TTo` can contain pointers or references. `TFrom` and `TTo` are checked at runtime in order to preserve type safety. +Neither `TFrom` nor `TTo` can contain managed object references. The `Cast` method performs this check at runtime and throws `ArgumentException` if the check fails. This method is supported only on platforms that support misaligned memory access or when the memory block is aligned by other means. ]]> - or contains references or pointers. + or contains managed object references. + The property of the new would exceed . @@ -416,7 +428,7 @@ This method is supported only on platforms that support misaligned memory access ## Remarks -Neither `TFrom` nor `TTo` can contain pointers or references. `TFrom` and `TTo` are checked at runtime in order to preserve type safety. +Neither `TFrom` nor `TTo` can contain managed object references. The `Cast` method performs this check at runtime and throws `ArgumentException` if the check fails. If the sizes of the two types are different, the cast combines or splits values, which leads to a change in length. @@ -429,7 +441,8 @@ This method is supported only on platforms that support misaligned memory access ]]> - or contains references or pointers. + or contains managed object references. + The property of the new would exceed . @@ -565,19 +578,19 @@ This method can be useful if part of a managed object represents a fixed array. - The pointer to the null-terminated string of bytes. - Creates a new read-only span for a null-terminated UTF8 string. + The pointer to the null-terminated narrow character string. + Creates a new read-only span for a null-terminated narrow character string. A read-only span representing the specified null-terminated string, or an empty span if the pointer is . - The string is longer than . + The property of the new would exceed . @@ -620,7 +633,7 @@ The returned span does not include the `null` terminator. ]]> - The string is longer than . + The property of the new would exceed . @@ -898,14 +911,17 @@ If the span is empty, this method returns a reference to the location where the ## Remarks -`T` cannot contain pointers or references. It is checked at runtime in order to preserve type safety. +`T` cannot contain managed object references. The `Read` method performs this check at runtime and throws `ArgumentException` if the check fails. + +> [!CAUTION] +> This method initializes an instance of `T`, including private instance fields and other implementation details, from the raw binary contents of the source span. Callers must ensure that the contents of the source span are well-formed with regard to `T`'s internal invariants. ]]> - contains references or pointers. + contains managed object references. - is smaller than . + is smaller than 's length in bytes. @@ -992,7 +1008,16 @@ This method allows a read-only memory buffer to be used in existing APIs that re Tries to get an array segment from the underlying memory buffer. The return value indicates the success of the operation. if the method call succeeds; otherwise. - To be added. + + [!CAUTION] +> is used to represent immutable data. instances returned by this method should not be written to. + + ]]> + @@ -1205,14 +1230,17 @@ This method allows a read-only memory buffer to be used in existing APIs that re [!CAUTION] +> This method initializes an instance of `T`, including private instance fields and other implementation details, from the raw binary contents of the source span. Callers must ensure that the contents of the source span are well-formed with regard to `T`'s internal invariants. ]]> - contains references or pointers. + contains managed object references. @@ -1264,12 +1292,15 @@ This method allows a read-only memory buffer to be used in existing APIs that re ## Remarks -`T` cannot contain pointers or references. It is checked at runtime in order to preserve type safety. +`T` cannot contain managed object references. The `TryWrite` method performs this check at runtime and throws `ArgumentException` if the check fails. + +> [!CAUTION] +> This method copies raw binary data from the original span, including any private instance fields and other implementation details of type `T`. Callers should ensure that their code is resilient to changes in the internal layout of `T`. ]]> - contains references or pointers. + contains managed object references. @@ -1319,12 +1350,15 @@ This method allows a read-only memory buffer to be used in existing APIs that re ## Remarks -`T` cannot contain pointers or references. It is checked at runtime in order to preserve type safety. +`T` cannot contain managed object references. The `Write` method performs this check at runtime and throws `ArgumentException` if the check fails. + +> [!CAUTION] +> This method copies raw binary data from the original span, including any private instance fields and other implementation details of type `T`. Callers should ensure that their code is resilient to changes in the internal layout of `T`. ]]> - contains references or pointers. + contains managed object references. is too small to contain . From d48b85bd7a57fc76724177973f7266dc294a0d68 Mon Sep 17 00:00:00 2001 From: Levi Broderick Date: Mon, 23 May 2022 17:15:28 -0700 Subject: [PATCH 2/9] Readd accidentally deleted XML block --- xml/System.Runtime.CompilerServices/Unsafe.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/xml/System.Runtime.CompilerServices/Unsafe.xml b/xml/System.Runtime.CompilerServices/Unsafe.xml index 53e8075ccb3..69defee2b46 100644 --- a/xml/System.Runtime.CompilerServices/Unsafe.xml +++ b/xml/System.Runtime.CompilerServices/Unsafe.xml @@ -1184,6 +1184,11 @@ No alignment assumptions are made about the `startAddress` pointer. See ECMA-335 System.Void + + + + + The unmanaged pointer referencing the start of the memory block to initialize. The value to initialize all bytes of the memory block to. The number of bytes to initialize. From 5d9e94d0ba84553ff2797f975343ffb51e203be3 Mon Sep 17 00:00:00 2001 From: Levi Broderick Date: Wed, 25 May 2022 15:37:21 -0700 Subject: [PATCH 3/9] PR feedback, improved examples and clarifications --- .../Unsafe.xml | 367 +++++++++++++----- .../MemoryMarshal.xml | 8 +- 2 files changed, 267 insertions(+), 108 deletions(-) diff --git a/xml/System.Runtime.CompilerServices/Unsafe.xml b/xml/System.Runtime.CompilerServices/Unsafe.xml index 69defee2b46..e3f40093590 100644 --- a/xml/System.Runtime.CompilerServices/Unsafe.xml +++ b/xml/System.Runtime.CompilerServices/Unsafe.xml @@ -32,9 +32,51 @@ ## Remarks > [!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). +> This type is intended for advanced pointer manipulation scenarios. Callers are assumed to be familiar with [ECMA-335](https://www.ecma-international.org/publications-and-standards/standards/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. +> Most APIs on this type do not perform any argument checking or validation. Incorrect use of these APIs could corrupt process memory or destabilize the .NET runtime. + +This type is typically used by low-level library authors who want to write high-performance code and are willing to suppress .NET's typical type safety checks to meet their performance goals. Consider the following sample, which reverses all elements in a `Span`. + +```cs +// Safe, verifiable way to reverse a Span. +static void Reverse(Span span) +{ + while (span.Length > 1) + { + T firstElement = span[0]; + T lastElement = span[^1]; + span[0] = lastElement; + span[^1] = firstElement; + span = span[1..^1]; + } +} +``` + +This method is fully type-safe and the .NET runtime may insert bounds checks to help enforce safety. However, low-level library authors may want to suppress .NET's normal safety checks in order to improve the performance of their own code. Such developers would typically rely on static analysis tools or their own code reviews to help enforce correctness. The `Unsafe` APIs allow a developer to rewrite this code using unverifiable constructs, as shown below. + +```cs +// Unverifiable way to reverse a Span. +static void Reverse(Span span) +{ + if (span.Length > 1) + { + ref T refLeft = ref MemoryMarshal.GetReference(span); + ref T refRight = ref Unsafe.Add(ref refLeft, span.Length - 1); + do + { + T leftElement = refLeft; + T rightElement = refRight; + refLeft = rightElement; + refRight = leftElement; + refLeft = ref Unsafe.Add(ref refLeft, 1); + refRight = ref Unsafe.Subtract(ref refRight, 1); + } while (Unsafe.IsAddressLessThan(ref refLeft, ref refRight)); + } +} +``` + +Since the `Unsafe` APIs suppress typical type-safety validation, it is up to callers to ensure that the code they're writing is legal. Misuse of these APIs could cause access violations, create GC holes, produce incorrect codegen, or otherwise induce undefined and destabilizing behaviors within the .NET runtime. ]]> @@ -71,11 +113,11 @@ - The type whose width will be used as a scale factor for `elementOffset`. + The type whose size will be used as a scale factor for . The unmanaged pointer to add the offset to. The offset to add. Adds an element offset to the given unmanaged pointer. - A new unmanaged pointer that reflects the addition of offset to the source pointer. + A new unmanaged pointer that reflects the addition of the specified offset to the source pointer. (ptr, 20)` will return a new pointer whose address points 80 bytes (= 20 elements \* 4 bytes per element) beyond _ptr_. -If `elementOffset` is a calculated value rather than a hardcoded literal, callers should consider the possibility of integer overflow and should take appropriate precautions. +If `elementOffset` is a calculated value rather than a hardcoded literal, callers should consider the possibility of integer overflow. For example, in the call `Unsafe.Add(ptr, a * b)`, the caller must ensure the intermediate value `a * b` does not overflow the bounds of `Int32`. ]]> @@ -126,7 +168,7 @@ If `elementOffset` is a calculated value rather than a hardcoded literal, caller The managed pointer to add the offset to. The offset to add. Adds an offset to the given managed pointer. - A new managed pointer that reflects the addition of offset to the source pointer. + A new managed pointer that reflects the addition of the specified offset to the source pointer. (ref ptr, 20)` will return a new pointer whose address points 80 bytes (= 20 elements \* 4 bytes per element) beyond _ptr_. -If `elementOffset` is a calculated value rather than a hardcoded literal, callers should consider the possibility of integer overflow and should take appropriate precautions. +If `elementOffset` is a calculated value rather than a hardcoded literal, callers should consider the possibility of integer overflow. For example, in the call `Unsafe.Add(ref ptr, a * b)`, the caller must ensure the intermediate value `a * b` does not overflow the bounds of `Int32`. ]]> @@ -176,7 +218,7 @@ If `elementOffset` is a calculated value rather than a hardcoded literal, caller The managed pointer to add the offset to. The offset to add. Adds an element offset to the given managed pointer. - A new managed pointer that reflects the addition of offset to the source pointer. + A new managed pointer that reflects the addition of the specified offset to the source pointer. (ref ptr, (nint)20)` will return a new pointer whose address points 80 bytes (= 20 elements \* 4 bytes per element) beyond _ptr_. -If `elementOffset` is a calculated value rather than a hardcoded literal, callers should consider the possibility of integer overflow and should take appropriate precautions. +If `elementOffset` is a calculated value rather than a hardcoded literal, callers should consider the possibility of integer overflow. For example, in the call `Unsafe.Add(ref ptr, a * b)`, the caller must ensure the intermediate value `a * b` does not overflow the bounds of `IntPtr`. ]]> @@ -228,15 +270,15 @@ If `elementOffset` is a calculated value rather than a hardcoded literal, caller The managed pointer to add the offset to. The offset to add. Adds an element offset to the given managed pointer. - A new managed pointer that reflects the addition of offset to the source pointer. + A new managed pointer that reflects the addition of the specified offset to the source pointer. (ref ptr, (nuint)20)` will return a new pointer whose address points 20 bytes (= 10 elements \* 4 bytes per element) beyond _ptr_. +The `elementOffset` parameter is the number of `T`-sized elements (not bytes) to add to the `source` pointer. For example, given a source pointer _ptr_ of type `ref int`, the call `Unsafe.Add(ref ptr, (nuint)20)` will return a new pointer whose address points 80 bytes (= 20 elements \* 4 bytes per element) beyond _ptr_. -If `elementOffset` is a calculated value rather than a hardcoded literal, callers should consider the possibility of integer overflow and should take appropriate precautions. +If `elementOffset` is a calculated value rather than a hardcoded literal, callers should consider the possibility of integer overflow. For example, in the call `Unsafe.Add(ref ptr, a * b)`, the caller must ensure the intermediate value `a * b` does not overflow the bounds of `UIntPtr`. ]]> @@ -278,7 +320,7 @@ If `elementOffset` is a calculated value rather than a hardcoded literal, caller The managed pointer to add the offset to. The offset to add. Adds a byte offset to the given managed pointer. - A new managed pointer that reflects the addition of byte offset to the source pointer. + A new managed pointer that reflects the addition of the specified byte offset to the source pointer. (ref ptr, 20)` will return a new pointer whose address points 20 bytes beyond _ptr_. -If `elementOffset` is a calculated value rather than a hardcoded literal, callers should consider the possibility of integer overflow and should take appropriate precautions. +If `byteOffset` is a calculated value rather than a hardcoded literal, callers should consider the possibility of integer overflow. For example, in the call `Unsafe.AddByteOffset(ref ptr, a * b)`, the caller must ensure the intermediate value `a * b` does not overflow the bounds of `IntPtr`. ]]> @@ -330,7 +372,7 @@ If `elementOffset` is a calculated value rather than a hardcoded literal, caller The managed pointer to add the offset to. The offset to add. Adds a byte offset to the given managed pointer. - A new managed pointer that reflects the addition of byte offset to the source pointer. + A new managed pointer that reflects the addition of the specified byte offset to the source pointer. (ref ptr, (nuint)20)` will return a new pointer whose address points 20 bytes beyond _ptr_. -If `elementOffset` is a calculated value rather than a hardcoded literal, callers should consider the possibility of integer overflow and should take appropriate precautions. +If `byteOffset` is a calculated value rather than a hardcoded literal, callers should consider the possibility of integer overflow. For example, in the call `Unsafe.AddByteOffset(ref ptr, a * b)`, the caller must ensure the intermediate value `a * b` does not overflow the bounds of `UIntPtr`. ]]> @@ -451,6 +493,39 @@ This API is used to cast an object to the given type, suppressing the runtime's The behavior of `Unsafe.As(o)` is only well-defined if the typical "safe" casting operation `(T)o` would have succeeded. Use of this API to circumvent casts that would otherwise have failed is unsupported and could result in runtime instability. +To help enforce correct usage, developers might consider using a standard cast or a debug-only assert in their code, as shown in the following examples. + +```cs +void ReinterpretCastAndUse_Sample1(object o) +{ + // Assume that we know through some other means that 'o' is a string, + // and we want our library's debug builds to verify this. + // One way to do this is through a standard-style cast. + // A standard-style cast will throw InvalidCastException at runtime if the cast fails. + // n.b. Casts of null objects to reference types will succeed. + +#if DEBUG + string s = (string)o; +#else + string s = Unsafe.As(o); +#endif + + DoSomethingWith(s); +} + +void ReinterpretCastAndUse_Sample2(object o) +{ + // Another way to check this is through a debug-only assert. + // Failed assertions will trigger attached debuggers or terminate the application immediately. + // Calls to Debug.Assert are removed from release builds. + + Debug.Assert(o is null or string, "Unsafe.As call below is illegal!"); + string s = Unsafe.As(s); + + DoSomethingWith(s); +} +``` + ]]> @@ -500,20 +575,20 @@ The behavior of `Unsafe.As(o)` is only well-defined if the typical "safe" cas This API is conceptually similar to C++'s `reinterpret_cast<>`. It is the caller's responsibility to ensure that the cast is legal. No runtime check will be performed. -Only the managed pointer is reinterpreted. The referenced value itself will remain unchanged. Consider the example below. +Only the managed pointer is reinterpreted. The referenced value itself will remain unchanged. Consider the following example. ```cs -int[] intArray = new int[] { 0x12345678 }; // a 1-element array +int[] intArray = new int[] { 0x1234_5678 }; // a 1-element array ref int refToInt32 = ref intArray[0]; // managed pointer to first Int32 in array ref short refToInt16 = ref Unsafe.As(ref refToInt32); // reinterpret as managed pointer to Int16 Console.WriteLine(refToInt16); ``` -The output of this program depends on the endianness of the current machine. On big-endian architectures this will output `0x1234`, and on little-endian architectures this will output `0x5678`. +The output of this program depends on the endianness of the current machine. On big-endian architectures, this code outputs `0x1234`. On little-endian architectures, this code outputs `0x5678`. -When casting a managed pointer from a narrower type to a wider type, the caller must ensure that dereferencing the pointer will not incur an out-of-bounds access. The caller is also responsible for ensuring that the resulting pointer is properly aligned for the referenced type. +When casting a managed pointer from a narrower type to a wider type, the caller must ensure that dereferencing the pointer will not incur an out-of-bounds access. The caller is also responsible for ensuring that the resulting pointer is properly aligned for the referenced type. For more information on alignment assumptions, see [ECMA-335](https://www.ecma-international.org/publications-and-standards/standards/ecma-335/), Sec. I.12.6.2 ("Alignment"). - ]]> +]]> @@ -558,11 +633,9 @@ When casting a managed pointer from a narrower type to a wider type, the caller ## Remarks -Unmanaged pointers are not tracked by the .NET garbage collector. If the original managed pointer points to a GC-managed object, it is the caller's responsibility to ensure that the source object is pinned. - -If the pointers reference memory in GC-owned address space, and if the source object is not pinned, the managed and unmanaged pointer values may eventually diverge due to GC relocation operations. +Unmanaged pointers are not tracked by the .NET garbage collector. If the original managed pointer points within a GC-managed object, the caller must ensure that the source object is pinned. If the source object is not pinned and the GC relocates the object, dereferencing the unmanaged pointer could cause an access violation. - ]]> +]]> @@ -602,7 +675,15 @@ If the pointers reference memory in GC-owned address space, and if the source ob The unmanaged pointer to convert. Converts an unmanaged pointer into a managed pointer to a value of type . A managed pointer to a value of type . - To be added. + + + @@ -647,7 +728,41 @@ If the pointers reference memory in GC-owned address space, and if the source ob The read-only reference to reinterpret. Reinterprets the given read-only reference as a mutable reference. A mutable reference to a value of type . - To be added. + + `. It is the caller's responsibility to ensure that no data is written to the referenced location. The runtime contains internal logic predicated on the assumption that readonly references truly are immutable, and callers who violate this invariant may trigger undefined behavior within the runtime. + +`AsRef` is typically used for passing a readonly reference into methods like , which accept mutable managed pointers as arguments. Consider the following example. + +```cs +int ComputeSumOfElements(ref int refToFirstElement, nint numElements) +{ + int sum = 0; + for (nint i = 0; i < numElements; i++) + { + sum += Unsafe.Add(ref refToFirstElement, i); + } +} +``` + +If the input parameter is `ref readonly int refToFirstElement` instead of `ref int refToFirstElement`, the previous example will not compile, since readonly references cannot be used as arguments to `Add`. Instead, `AsRef` can be used to remove the immutability constraint and allow compilation to succeed, as shown in the following example. + +```cs +int ComputeSumOfElements(ref readonly int refToFirstElement, nint numElements) +{ + int sum = 0; + for (nint i = 0; i < numElements; i++) + { + sum += Unsafe.Add(ref Unsafe.AsRef(ref refToFirstElement), i); + } +} +``` + +]]> + @@ -697,10 +812,10 @@ If the pointers reference memory in GC-owned address space, and if the source ob The elemental type of the managed pointers. - The managed pointer to origin. - The managed pointer to target. + The managed pointer to the origin. + The managed pointer to the target. Determines the byte offset from origin to target from the given managed pointers. - Byte offset from origin to target i.e. - . + The byte offset from origin to target, that is, - . +]]> @@ -756,7 +871,7 @@ The return value is guaranteed stable if `origin` and `target` point to the same ## Remarks -Both `destination` and `source` are assumed to be properly aligned for pointers to data of type `T`. +Both `destination` and `source` are assumed to be properly aligned for pointers to data of type `T`. For more information on alignment assumptions, see [ECMA-335](https://www.ecma-international.org/publications-and-standards/standards/ecma-335/), Sec. I.12.6.2 ("Alignment"). This method is roughly equivalent to the following code. @@ -768,7 +883,7 @@ static void Copy(void* destination, ref T source) } ``` - ]]> +]]> @@ -814,19 +929,19 @@ static void Copy(void* destination, ref T source) ## Remarks -Both `destination` and `source` are assumed to be properly aligned for pointers to data of type `T`. +Both `destination` and `source` are assumed to be properly aligned for pointers to data of type `T`. For more information on alignment assumptions, see [ECMA-335](https://www.ecma-international.org/publications-and-standards/standards/ecma-335/), Sec. I.12.6.2 ("Alignment"). This method is roughly equivalent to the following code. ```cs static void Copy(ref T destination, void* source) { - T data = *(T*)source; // cast source to T* and dereference + T data = *(T*)source; // reinterpret cast source as T* and dereference destination = data; } ``` - ]]> +]]> @@ -869,11 +984,12 @@ static void Copy(ref T destination, void* source) ## Remarks -This API corresponds to the `cpblk` opcode. +This API corresponds to the `cpblk` opcode. Both the `destination` and `source` pointers are assumed to be pointer-aligned. See [ECMA-335](https://www.ecma-international.org/publications-and-standards/standards/ecma-335/), Sec. III.3.30 ("cpblk - copy data from memory to memory") for more information. -Both `destination` and `source` are assumed to be aligned to the machine's natural word size. See ECMA-335, Sec. III.3.30 ("cpblk - copy data from memory to memory") for more information. +> [!CAUTION] +> This API is not intended for copying arbitrary-length runs of memory. Consider instead using or for this scenario. - ]]> +]]> @@ -917,11 +1033,12 @@ Both `destination` and `source` are assumed to be aligned to the machine's natur ## Remarks -This API corresponds to the `cpblk` opcode. +This API corresponds to the `cpblk` opcode. Both the `destination` and `source` pointers are assumed to be pointer-aligned. See [ECMA-335](https://www.ecma-international.org/publications-and-standards/standards/ecma-335/), Sec. III.3.30 ("cpblk - copy data from memory to memory") for more information. -Both `destination` and `source` are assumed to be aligned to the machine's natural word size. See ECMA-335, Sec. III.3.30 ("cpblk - copy data from memory to memory") for more information. +> [!CAUTION] +> This API is not intended for copying arbitrary-length runs of memory. Consider instead using or for this scenario. - ]]> +]]> @@ -964,11 +1081,12 @@ Both `destination` and `source` are assumed to be aligned to the machine's natur ## Remarks -This API corresponds to the `unaligned.1 cpblk` opcode sequence. +This API corresponds to the `unaligned.1 cpblk` opcode sequence. No alignment assumptions are made about the `destination` or `source` pointers. See [ECMA-335](https://www.ecma-international.org/publications-and-standards/standards/ecma-335/), Sec. III.3.30 ("cpblk - copy data from memory to memory") and Sec. III.2.5 ("unaligned. (prefix) - pointer instruction might be unaligned") for more information. -No alignment assumptions are made about the `destination` or `source` pointers. See ECMA-335, Sec. III.3.30 ("cpblk - copy data from memory to memory") and Sec. III.2.5 ("unaligned. (prefix) - pointer instruction might be unaligned") for more information. +> [!CAUTION] +> This API is not intended for copying arbitrary-length runs of memory. Consider instead using or for this scenario. - ]]> +]]> @@ -1010,11 +1128,12 @@ No alignment assumptions are made about the `destination` or `source` pointers. ## Remarks -This API corresponds to the `unaligned.1 cpblk` opcode sequence. +This API corresponds to the `unaligned.1 cpblk` opcode sequence. No alignment assumptions are made about the `destination` or `source` pointers. See [ECMA-335](https://www.ecma-international.org/publications-and-standards/standards/ecma-335/), Sec. III.3.30 ("cpblk - copy data from memory to memory") and Sec. III.2.5 ("unaligned. (prefix) - pointer instruction might be unaligned") for more information. -No alignment assumptions are made about the `destination` or `source` pointers. See ECMA-335, Sec. III.3.30 ("cpblk - copy data from memory to memory") and Sec. III.2.5 ("unaligned. (prefix) - pointer instruction might be unaligned") for more information. +> [!CAUTION] +> This API is not intended for copying arbitrary-length runs of memory. Consider instead using or for this scenario. - ]]> +]]> @@ -1057,11 +1176,12 @@ No alignment assumptions are made about the `destination` or `source` pointers. ## Remarks -This API corresponds to the `initblk` opcode. +This API corresponds to the `initblk` opcode. The `startAddress` pointer is assumed to be pointer-aligned. See [ECMA-335](https://www.ecma-international.org/publications-and-standards/standards/ecma-335/), Sec. III.3.36 ("initblk - initialize a block of memory to a value") for more information. -`startAddress` is assumed to be aligned to the machine's natural word size. See ECMA-335, Sec. III.3.36 ("initblk - initialize a block of memory to a value") for more information. +> [!CAUTION] +> This API is not intended for initializing arbitrary-length runs of memory. Consider instead using for this scenario. - ]]> +]]> @@ -1105,11 +1225,12 @@ This API corresponds to the `initblk` opcode. ## Remarks -This API corresponds to the `initblk` opcode. +This API corresponds to the `initblk` opcode. The `startAddress` pointer is assumed to be pointer-aligned. See [ECMA-335](https://www.ecma-international.org/publications-and-standards/standards/ecma-335/), Sec. III.3.36 ("initblk - initialize a block of memory to a value") for more information. -`startAddress` is assumed to be aligned to the machine's natural word size. See ECMA-335, Sec. III.3.36 ("initblk - initialize a block of memory to a value") for more information. +> [!CAUTION] +> This API is not intended for initializing arbitrary-length runs of memory. Consider instead using for this scenario. - ]]> +]]> @@ -1152,11 +1273,12 @@ This API corresponds to the `initblk` opcode. ## Remarks -This API corresponds to the `unaligned.1 initblk` opcode sequence. +This API corresponds to the `unaligned.1 initblk` opcode sequence. No alignment assumption is made about the `startAddress` pointer. See [ECMA-335](https://www.ecma-international.org/publications-and-standards/standards/ecma-335/), Sec. III.3.36 ("initblk - initialize a block of memory to a value") and Sec. III.2.5 ("unaligned. (prefix) - pointer instruction might be unaligned") for more information. -No alignment assumptions are made about the `startAddress` pointer. See ECMA-335, Sec. Sec. III.3.36 ("initblk - initialize a block of memory to a value") and Sec. III.2.5 ("unaligned. (prefix) - pointer instruction might be unaligned") for more information. +> [!CAUTION] +> This API is not intended for initializing arbitrary-length runs of memory. Consider instead using for this scenario. - ]]> +]]> @@ -1184,7 +1306,7 @@ No alignment assumptions are made about the `startAddress` pointer. See ECMA-335 System.Void - + @@ -1198,11 +1320,12 @@ No alignment assumptions are made about the `startAddress` pointer. See ECMA-335 ## Remarks -This API corresponds to the `unaligned.1 initblk` opcode sequence. +This API corresponds to the `unaligned.1 initblk` opcode sequence. No alignment assumption is made about the `startAddress` pointer. See [ECMA-335](https://www.ecma-international.org/publications-and-standards/standards/ecma-335/), Sec. III.3.36 ("initblk - initialize a block of memory to a value") and Sec. III.2.5 ("unaligned. (prefix) - pointer instruction might be unaligned") for more information. -No alignment assumptions are made about the `startAddress` pointer. See ECMA-335, Sec. Sec. III.3.36 ("initblk - initialize a block of memory to a value") and Sec. III.2.5 ("unaligned. (prefix) - pointer instruction might be unaligned") for more information. +> [!CAUTION] +> This API is not intended for initializing arbitrary-length runs of memory. Consider instead using for this scenario. - ]]> +]]> @@ -1269,7 +1392,7 @@ The return value of this method is a moment-in-time result. If `left` and `right The return value is guaranteed stable if `left` and `right` point to the same managed object. - ]]> +]]> @@ -1336,7 +1459,7 @@ The return value of this method is a moment-in-time result. If `left` and `right The return value is guaranteed stable if `left` and `right` point to the same managed object. - ]]> +]]> @@ -1403,7 +1526,7 @@ The return value is guaranteed stable if `left` and `right` point to the same ma The elemental type of the managed pointer. Returns a null managed pointer to a value of type . A null managed pointer to a value of type . - The return value is conceptually similar to ref *((T*)nullptr). + The return value is conceptually similar to ref *((T*)null). @@ -1439,7 +1562,7 @@ The return value is guaranteed stable if `left` and `right` point to the same ma The type of the value to read. - The location to read from. + An unmanaged pointer containing the address to read from. Reads a value of type from the given location. A value of type read from the given location. @@ -1448,9 +1571,12 @@ The return value is guaranteed stable if `left` and `right` point to the same ma ## Remarks -`source` is assumed to be a properly aligned pointer to a value of type `T`. +> [!CAUTION] +> The caller must ensure that there are `SizeOf()` bytes of readable memory available starting at the location pointed to by `source`. Access violations may occur if this requirement is not met. + +`source` is assumed to be a properly aligned pointer to a value of type `T`. For more information on alignment assumptions, see [ECMA-335](https://www.ecma-international.org/publications-and-standards/standards/ecma-335/), Sec. I.12.6.2 ("Alignment"). - ]]> +]]> @@ -1489,7 +1615,15 @@ The return value is guaranteed stable if `left` and `right` point to the same ma A managed pointer containing the address to read from. Reads a value of type from the given address without assuming architecture dependent alignment of the source address. A value of type read from the given address. - To be added. + + [!CAUTION] +> The caller must ensure that there are `SizeOf()` bytes of readable memory available starting at the location pointed to by `source`. Access violations may occur if this requirement is not met. + +]]> @@ -1523,10 +1657,18 @@ The return value is guaranteed stable if `left` and `right` point to the same ma The type of the value to read. - The location to read from. + An unmanaged pointer containing the address to read from. Reads a value of type from the given location without assuming architecture dependent alignment of the source address. A value of type read from the given location. - To be added. + + [!CAUTION] +> The caller must ensure that there are `SizeOf()` bytes of readable memory available starting at the location pointed to by `source`. Access violations may occur if this requirement is not met. + +]]> @@ -1560,22 +1702,20 @@ The return value is guaranteed stable if `left` and `right` point to the same ma - The type whose size is retrieved. + The type whose size is to be retrieved. Returns the size of a value of the given type parameter. - The size (in bytes) of a value of type . + The size, in bytes, of a value of type . [!CAUTION] -> This API returns the size of the _managed_ view of the type. For the size of the _unmanaged_ view of the type, such as for interop purposes, use . - -This API corresponds to the `sizeof` opcode. +This API corresponds to the `sizeof` opcode. If `T` is a reference type, the return value is the size of the reference itself (equal to `sizeof(void*)`). See [ECMA-335](https://www.ecma-international.org/publications-and-standards/standards/ecma-335/), Sec. III.4.25 ("sizeof - load the size, in bytes, of a type") for more information. -If `T` is a reference type, the return value is the size of the reference itself, or `IntPtr.Size`. See ECMA-335, Sec. Sec. III.4.25 ("sizeof - load the size, in bytes, of a type") for more information. +> [!CAUTION] +> This API returns the size of the _managed_ view of the type. For the size of the _unmanaged_ view of the type, such as needed for interop purposes, use . - ]]> +]]> @@ -1614,7 +1754,7 @@ If `T` is a reference type, the return value is the size of the reference itself ## Remarks -This is typically used to avoid double-assignment when initializing union-type structs. Consider the following example, which produces a C# compiler error. +This method is typically used to avoid double-initialization when initializing union-type structs. Consider the following example, which produces a C# compiler error. ```cs using System; @@ -1639,7 +1779,7 @@ public struct MyUnionStruct This error occurs because the compiler expects _all_ fields of the struct to be initialized before the struct is used or returned to the caller. -One way to avoid this compiler error is to ensure the entire struct is zero-inited before individual fields are set, as shown in the below example. +One way to avoid this compiler error is to ensure the entire struct is zero-initialized before individual fields are set, as shown in the following example. ```cs // This sample compiles successfully. @@ -1650,7 +1790,7 @@ public static MyUnionStruct MyMethod() { } ``` -For developers who don't want to avoid the initial zero-init assignment, the `SkipInit` method can be used to suppress the compiler warning. +If you want to avoid the initial zero-initialization, you can call the `SkipInit` method can be used to suppress the compiler warning. ```cs using System.Runtime.CompilerServices; @@ -1665,9 +1805,9 @@ public static MyUnionStruct MyMethod() { ``` > [!WARNING] -> The developer must take care to ensure that the struct has been initialized appropriately, otherwise the struct's fields could contain uninitialized data from the stack. +> Take care to ensure that the struct has been initialized appropriately, otherwise the struct's fields could contain uninitialized data from the stack. - ]]> +]]> @@ -1702,19 +1842,19 @@ public static MyUnionStruct MyMethod() { - The type whose width will be used as a scale factor for `elementOffset`. - The unmanaged pointer to subtract the offset froms. + The type whose size will be used as a scale factor for . + The unmanaged pointer to subtract the offset from. The offset to subtract. Subtracts an element offset from the given unmanaged pointer. - A new unmanaged pointer that reflects the subtraction of offset from the source pointer. + A new unmanaged pointer that reflects the subtraction of the specified offset from the source pointer. (ptr, 10)` will return a new pointer whose address points 40 bytes (= 10 elements \* 4 bytes per element) before _ptr_. +The `elementOffset` parameter is the number of `T`-sized elements (not bytes) to remove from the `source` pointer. For example, given a source pointer _ptr_, the call `Unsafe.Subtract(ptr, 20)` will return a new pointer whose address points 80 bytes (= 20 elements \* 4 bytes per element) before _ptr_. -If `elementOffset` is a calculated value rather than a hardcoded literal, callers should consider the possibility of integer overflow and should take appropriate precautions. +If `elementOffset` is a calculated value rather than a hardcoded literal, callers should consider the possibility of integer overflow. For example, in the call `Unsafe.Subtract(ptr, a * b)`, the caller must ensure the intermediate value `a * b` does not overflow the bounds of `Int32`. ]]> @@ -1757,7 +1897,7 @@ If `elementOffset` is a calculated value rather than a hardcoded literal, caller The managed pointer to subtract the offset from. The offset to subtract. Subtracts an offset from the given managed pointer. - A new managed pointer that reflects the subtraction of offset from the source pointer. + A new managed pointer that reflects the subtraction of the specified offset from the source pointer. (ref ptr, 20)` will return a new pointer whose address points 80 bytes (= 20 elements \* 4 bytes per element) before _ptr_. -If `elementOffset` is a calculated value rather than a hardcoded literal, callers should consider the possibility of integer overflow and should take appropriate precautions. +If `elementOffset` is a calculated value rather than a hardcoded literal, callers should consider the possibility of integer overflow. For example, in the call `Unsafe.Subtract(ref ptr, a * b)`, the caller must ensure the intermediate value `a * b` does not overflow the bounds of `Int32`. ]]> @@ -1807,7 +1947,7 @@ If `elementOffset` is a calculated value rather than a hardcoded literal, caller The managed pointer to subtract the offset from. The offset to subtract. Subtracts an element offset from the given managed pointer. - A new managed pointer that reflects the subtraction of offset from the source pointer. + A new managed pointer that reflects the subtraction of the specified offset from the source pointer. (ref ptr, (nint)20)` will return a new pointer whose address points 80 bytes (= 20 elements \* 4 bytes per element) before _ptr_. -If `elementOffset` is a calculated value rather than a hardcoded literal, callers should consider the possibility of integer overflow and should take appropriate precautions. +If `elementOffset` is a calculated value rather than a hardcoded literal, callers should consider the possibility of integer overflow. For example, in the call `Unsafe.Subtract(ref ptr, a * b)`, the caller must ensure the intermediate value `a * b` does not overflow the bounds of `IntPtr`. ]]> @@ -1859,15 +1999,15 @@ If `elementOffset` is a calculated value rather than a hardcoded literal, caller The managed pointer to subtract the offset from. The offset to subtract. Subtracts an element offset from the given managed pointer. - A new managed pointer that reflects the subtraction of offset from the source pointer. + A new managed pointer that reflects the subtraction of the specified offset from the source pointer. (ref ptr, (nuint)20)` will return a new pointer whose address points 20 bytes (= 10 elements \* 4 bytes per element) before _ptr_. +The `elementOffset` parameter is the number of `T`-sized elements (not bytes) to subtract from the `source` pointer. For example, given a source pointer _ptr_ of type `ref int`, the call `Unsafe.Subtract(ref ptr, (nuint)20)` will return a new pointer whose address points 80 bytes (= 20 elements \* 4 bytes per element) before _ptr_. -If `elementOffset` is a calculated value rather than a hardcoded literal, callers should consider the possibility of integer overflow and should take appropriate precautions. +If `elementOffset` is a calculated value rather than a hardcoded literal, callers should consider the possibility of integer overflow. For example, in the call `Unsafe.Subtract(ref ptr, a * b)`, the caller must ensure the intermediate value `a * b` does not overflow the bounds of `UIntPtr`. ]]> @@ -1909,7 +2049,7 @@ If `elementOffset` is a calculated value rather than a hardcoded literal, caller The managed pointer to subtract the offset from. The offset to subtract. Subtracts a byte offset from the given managed pointer. - A new managed pointer that reflects the subtraction of byte offset from the source pointer. + A new managed pointer that reflects the subtraction of the specified byte offset from the source pointer. (ref ptr, 20)` will return a new pointer whose address points 20 bytes before _ptr_. -If `elementOffset` is a calculated value rather than a hardcoded literal, callers should consider the possibility of integer overflow and should take appropriate precautions. +If `byteOffset` is a calculated value rather than a hardcoded literal, callers should consider the possibility of integer overflow. For example, in the call `Unsafe.SubtractByteOffset(ref ptr, a * b)`, the caller must ensure the intermediate value `a * b` does not overflow the bounds of `IntPtr`. ]]> @@ -1961,7 +2101,7 @@ If `elementOffset` is a calculated value rather than a hardcoded literal, caller The managed pointer to subtract the offset from. The offset to subtract. Subtracts a byte offset from the given managed pointer. - A new managed pointer that reflects the subtraction of byte offset from the source pointer. + A new managed pointer that reflects the subtraction of the specified byte offset from the source pointer. (ref ptr, (nuint)20)` will return a new pointer whose address points 20 bytes before _ptr_. -If `elementOffset` is a calculated value rather than a hardcoded literal, callers should consider the possibility of integer overflow and should take appropriate precautions. +If `byteOffset` is a calculated value rather than a hardcoded literal, callers should consider the possibility of integer overflow. For example, in the call `Unsafe.SubtractByteOffset(ref ptr, a * b)`, the caller must ensure the intermediate value `a * b` does not overflow the bounds of `UIntPtr`. ]]> @@ -2033,7 +2173,7 @@ Unsafe.Unbox(obj).X = 50; For more information, see sections III.1.8.1.2.2 ("Controlled-muttability managed pointers") and III.4.32 ("unbox -- convert boxed value type to its raw form") in [ECMA-335: Common Language Infrastructure (CLI)](https://www.ecma-international.org/publications-and-standards/standards/ecma-335/). - ]]> +]]> is , and is a non-nullable value type. @@ -2090,9 +2230,12 @@ For more information, see sections III.1.8.1.2.2 ("Controlled-muttability manage ## Remarks -`destination` is assumed to be a properly aligned pointer to a value of type `T`. +> [!CAUTION] +> The caller must ensure that there are `SizeOf()` bytes of writable memory available starting at the location pointed to by `destination`. Access violations may occur if this requirement is not met. + +`destination` is assumed to be a properly aligned pointer to a value of type `T`. For more information on alignment assumptions, see [ECMA-335](https://www.ecma-international.org/publications-and-standards/standards/ecma-335/), Sec. I.12.6.2 ("Alignment"). - ]]> +]]> @@ -2132,7 +2275,15 @@ For more information, see sections III.1.8.1.2.2 ("Controlled-muttability manage A managed pointer containing the address to write to. The value to write. Writes a value of type to the given location without assuming architecture dependent alignment of the destination address. - To be added. + + [!CAUTION] +> The caller must ensure that there are `SizeOf()` bytes of writable memory available starting at the location pointed to by `destination`. Access violations may occur if this requirement is not met. + +]]> @@ -2170,7 +2321,15 @@ For more information, see sections III.1.8.1.2.2 ("Controlled-muttability manage A managed pointer containing the address to write to. The value to write. Writes a value of type to the given location without assuming architecture dependent alignment of the destination address. - To be added. + + [!CAUTION] +> The caller must ensure that there are `SizeOf()` bytes of writable memory available starting at the location pointed to by `destination`. Access violations may occur if this requirement is not met. + +]]> diff --git a/xml/System.Runtime.InteropServices/MemoryMarshal.xml b/xml/System.Runtime.InteropServices/MemoryMarshal.xml index 6639a2c98b7..57746017e17 100644 --- a/xml/System.Runtime.InteropServices/MemoryMarshal.xml +++ b/xml/System.Runtime.InteropServices/MemoryMarshal.xml @@ -578,15 +578,15 @@ This method can be useful if part of a managed object represents a fixed array. - The pointer to the null-terminated narrow character string. - Creates a new read-only span for a null-terminated narrow character string. + The pointer to the null-terminated sequence of bytes. + Creates a new read-only span for a null-terminated sequence of bytes. A read-only span representing the specified null-terminated string, or an empty span if the pointer is . @@ -1014,7 +1014,7 @@ This method allows a read-only memory buffer to be used in existing APIs that re ## Remarks > [!CAUTION] -> is used to represent immutable data. instances returned by this method should not be written to. +> is used to represent immutable data. instances returned by this method should not be written to, and the wrapped array instance should only be passed to methods which treat the array contents as read-only. ]]> From 58250eb2ed6a9c91c22e652db39639a99b2488b0 Mon Sep 17 00:00:00 2001 From: Levi Broderick Date: Wed, 25 May 2022 15:48:30 -0700 Subject: [PATCH 4/9] Fix broken XML --- xml/System.Runtime.CompilerServices/Unsafe.xml | 1 + xml/System.Runtime.InteropServices/MemoryMarshal.xml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/xml/System.Runtime.CompilerServices/Unsafe.xml b/xml/System.Runtime.CompilerServices/Unsafe.xml index e3f40093590..3f91ff93e1d 100644 --- a/xml/System.Runtime.CompilerServices/Unsafe.xml +++ b/xml/System.Runtime.CompilerServices/Unsafe.xml @@ -1624,6 +1624,7 @@ The return value is guaranteed stable if `left` and `right` point to the same ma > The caller must ensure that there are `SizeOf()` bytes of readable memory available starting at the location pointed to by `source`. Access violations may occur if this requirement is not met. ]]> + diff --git a/xml/System.Runtime.InteropServices/MemoryMarshal.xml b/xml/System.Runtime.InteropServices/MemoryMarshal.xml index 57746017e17..7e806f42e25 100644 --- a/xml/System.Runtime.InteropServices/MemoryMarshal.xml +++ b/xml/System.Runtime.InteropServices/MemoryMarshal.xml @@ -580,7 +580,7 @@ This method can be useful if part of a managed object represents a fixed array. The pointer to the null-terminated sequence of bytes. Creates a new read-only span for a null-terminated sequence of bytes. - A read-only span representing the specified null-terminated string, or an empty span if the pointer is . + A read-only span representing the specified sequence of bytes, or an empty span if the pointer is . Date: Thu, 26 May 2022 14:57:16 -0700 Subject: [PATCH 5/9] Fix broken XML --- xml/System.Runtime.CompilerServices/Unsafe.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/xml/System.Runtime.CompilerServices/Unsafe.xml b/xml/System.Runtime.CompilerServices/Unsafe.xml index 3f91ff93e1d..ed1e02a1712 100644 --- a/xml/System.Runtime.CompilerServices/Unsafe.xml +++ b/xml/System.Runtime.CompilerServices/Unsafe.xml @@ -1670,6 +1670,7 @@ The return value is guaranteed stable if `left` and `right` point to the same ma > The caller must ensure that there are `SizeOf()` bytes of readable memory available starting at the location pointed to by `source`. Access violations may occur if this requirement is not met. ]]> + From 4e50f50850c6991e76b8c5081b7b4de739d0de17 Mon Sep 17 00:00:00 2001 From: Levi Broderick Date: Thu, 26 May 2022 15:07:18 -0700 Subject: [PATCH 6/9] Add some remarks regarding the Reverse sample --- xml/System.Runtime.CompilerServices/Unsafe.xml | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/xml/System.Runtime.CompilerServices/Unsafe.xml b/xml/System.Runtime.CompilerServices/Unsafe.xml index ed1e02a1712..4ee05c48ef6 100644 --- a/xml/System.Runtime.CompilerServices/Unsafe.xml +++ b/xml/System.Runtime.CompilerServices/Unsafe.xml @@ -36,10 +36,15 @@ > > Most APIs on this type do not perform any argument checking or validation. Incorrect use of these APIs could corrupt process memory or destabilize the .NET runtime. -This type is typically used by low-level library authors who want to write high-performance code and are willing to suppress .NET's typical type safety checks to meet their performance goals. Consider the following sample, which reverses all elements in a `Span`. +This type is typically used by low-level library authors who want to write high-performance code and are willing to suppress .NET's typical type safety checks to meet their performance goals. + +Consider the following example, which reverses the elements within a `Span`. + +> [!NOTE] +> These examples exist simply for demonstration purposes. In real-world applications, developers should instead use helper functions like , which are better optimized than even these examples. ```cs -// Safe, verifiable way to reverse a Span. +// A safe, verifiable way to reverse a Span. static void Reverse(Span span) { while (span.Length > 1) @@ -53,10 +58,10 @@ static void Reverse(Span span) } ``` -This method is fully type-safe and the .NET runtime may insert bounds checks to help enforce safety. However, low-level library authors may want to suppress .NET's normal safety checks in order to improve the performance of their own code. Such developers would typically rely on static analysis tools or their own code reviews to help enforce correctness. The `Unsafe` APIs allow a developer to rewrite this code using unverifiable constructs, as shown below. +This method is fully type-safe and the .NET runtime may insert bounds checks to help enforce safety. However, low-level library authors may want to suppress .NET's normal safety checks in order to improve the performance of their own code. Such developers would typically rely on static analysis tools or their own code reviews to help enforce correctness. The `Unsafe` APIs allow a developer to rewrite this code using unverifiable constructs, as the following example shows. ```cs -// Unverifiable way to reverse a Span. +// A correct but unverifiable way to reverse a Span. static void Reverse(Span span) { if (span.Length > 1) From 542a0239c2bed171ccf949ae9508d5b912253882 Mon Sep 17 00:00:00 2001 From: Levi Broderick Date: Thu, 26 May 2022 15:11:40 -0700 Subject: [PATCH 7/9] Fix reinterpret_cast output sample --- xml/System.Runtime.CompilerServices/Unsafe.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xml/System.Runtime.CompilerServices/Unsafe.xml b/xml/System.Runtime.CompilerServices/Unsafe.xml index 4ee05c48ef6..8473c223811 100644 --- a/xml/System.Runtime.CompilerServices/Unsafe.xml +++ b/xml/System.Runtime.CompilerServices/Unsafe.xml @@ -586,7 +586,7 @@ Only the managed pointer is reinterpreted. The referenced value itself will rema int[] intArray = new int[] { 0x1234_5678 }; // a 1-element array ref int refToInt32 = ref intArray[0]; // managed pointer to first Int32 in array ref short refToInt16 = ref Unsafe.As(ref refToInt32); // reinterpret as managed pointer to Int16 -Console.WriteLine(refToInt16); +Console.WriteLine($"0x{refToInt16:x4}"); ``` The output of this program depends on the endianness of the current machine. On big-endian architectures, this code outputs `0x1234`. On little-endian architectures, this code outputs `0x5678`. From 28630d1d245ff6661b6a3ac1aa242266094ffd59 Mon Sep 17 00:00:00 2001 From: Levi Broderick Date: Thu, 26 May 2022 15:17:31 -0700 Subject: [PATCH 8/9] Fix bad XML --- xml/System.Runtime.CompilerServices/Unsafe.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/xml/System.Runtime.CompilerServices/Unsafe.xml b/xml/System.Runtime.CompilerServices/Unsafe.xml index 8473c223811..1ffb3d6347b 100644 --- a/xml/System.Runtime.CompilerServices/Unsafe.xml +++ b/xml/System.Runtime.CompilerServices/Unsafe.xml @@ -2291,6 +2291,7 @@ For more information, see sections III.1.8.1.2.2 ("Controlled-muttability manage > The caller must ensure that there are `SizeOf()` bytes of writable memory available starting at the location pointed to by `destination`. Access violations may occur if this requirement is not met. ]]> + @@ -2337,6 +2338,7 @@ For more information, see sections III.1.8.1.2.2 ("Controlled-muttability manage > The caller must ensure that there are `SizeOf()` bytes of writable memory available starting at the location pointed to by `destination`. Access violations may occur if this requirement is not met. ]]> + From 94a22a177ae78259ed0cb7b749a6f79fb3d94024 Mon Sep 17 00:00:00 2001 From: Levi Broderick Date: Fri, 27 May 2022 13:15:44 -0700 Subject: [PATCH 9/9] Fix xrefs for MemoryCopy --- xml/System.Runtime.CompilerServices/Unsafe.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/xml/System.Runtime.CompilerServices/Unsafe.xml b/xml/System.Runtime.CompilerServices/Unsafe.xml index 1ffb3d6347b..64cd64feed5 100644 --- a/xml/System.Runtime.CompilerServices/Unsafe.xml +++ b/xml/System.Runtime.CompilerServices/Unsafe.xml @@ -992,7 +992,7 @@ static void Copy(ref T destination, void* source) This API corresponds to the `cpblk` opcode. Both the `destination` and `source` pointers are assumed to be pointer-aligned. See [ECMA-335](https://www.ecma-international.org/publications-and-standards/standards/ecma-335/), Sec. III.3.30 ("cpblk - copy data from memory to memory") for more information. > [!CAUTION] -> This API is not intended for copying arbitrary-length runs of memory. Consider instead using or for this scenario. +> This API is not intended for copying arbitrary-length runs of memory. Consider instead using or for this scenario. ]]> @@ -1041,7 +1041,7 @@ This API corresponds to the `cpblk` opcode. Both the `destination` and `source` This API corresponds to the `cpblk` opcode. Both the `destination` and `source` pointers are assumed to be pointer-aligned. See [ECMA-335](https://www.ecma-international.org/publications-and-standards/standards/ecma-335/), Sec. III.3.30 ("cpblk - copy data from memory to memory") for more information. > [!CAUTION] -> This API is not intended for copying arbitrary-length runs of memory. Consider instead using or for this scenario. +> This API is not intended for copying arbitrary-length runs of memory. Consider instead using or for this scenario. ]]> @@ -1089,7 +1089,7 @@ This API corresponds to the `cpblk` opcode. Both the `destination` and `source` This API corresponds to the `unaligned.1 cpblk` opcode sequence. No alignment assumptions are made about the `destination` or `source` pointers. See [ECMA-335](https://www.ecma-international.org/publications-and-standards/standards/ecma-335/), Sec. III.3.30 ("cpblk - copy data from memory to memory") and Sec. III.2.5 ("unaligned. (prefix) - pointer instruction might be unaligned") for more information. > [!CAUTION] -> This API is not intended for copying arbitrary-length runs of memory. Consider instead using or for this scenario. +> This API is not intended for copying arbitrary-length runs of memory. Consider instead using or for this scenario. ]]> @@ -1136,7 +1136,7 @@ This API corresponds to the `unaligned.1 cpblk` opcode sequence. No alignment as This API corresponds to the `unaligned.1 cpblk` opcode sequence. No alignment assumptions are made about the `destination` or `source` pointers. See [ECMA-335](https://www.ecma-international.org/publications-and-standards/standards/ecma-335/), Sec. III.3.30 ("cpblk - copy data from memory to memory") and Sec. III.2.5 ("unaligned. (prefix) - pointer instruction might be unaligned") for more information. > [!CAUTION] -> This API is not intended for copying arbitrary-length runs of memory. Consider instead using or for this scenario. +> This API is not intended for copying arbitrary-length runs of memory. Consider instead using or for this scenario. ]]>