From da5c31925d6ac310256ea177b12c6a0bd240fa23 Mon Sep 17 00:00:00 2001 From: Phillip Carter Date: Wed, 19 Aug 2015 15:44:24 -0700 Subject: [PATCH 1/7] Completing the primer section on unsafe * Added a code sample taken from CoreFx * Linked to the folder where the source file sits * Reworded blurb to emphasize that it should be discouraged unless necessary, not simply discouraged --- docs/concepts/primer.rst | 64 +++++++++++++++++++++++++++++++++++----- 1 file changed, 57 insertions(+), 7 deletions(-) diff --git a/docs/concepts/primer.rst b/docs/concepts/primer.rst index a397c85375b1f..c6a47b3d84d20 100644 --- a/docs/concepts/primer.rst +++ b/docs/concepts/primer.rst @@ -258,14 +258,64 @@ Unsafe Code ~~~~~~~~~~~ The CLR enables the ability to acccess native memory and do pointer -arithmetic. These operations are needed for some algortithms and for -calling some native APIs. The use of these capabilities is discouraged, -since you no longer get the benefit of verifiability, nor will your code -be allowed to run in all environments. The best practice is to confine -unsafe code as much as possible and that the vast majority of code is -type-safe. +arithmetic via ``unsafe`` code. These operations are needed for certain algorithms and system interoperability. Although powerful, use of unsafe code is discouraged unless it is necessary to interop with system APIs or implement the most efficient algorithm. Unsafe code is not guaranteed to run in all environments, and also loses the benefits of a garbage collector and type safety. It's recommended to confine +unsafe code as much as possible, and test that code extremely thoroughly. -TODO: Examples. +Taken from the `.NET CoreFx Linux Interop Source `_: + +.. code-block:: c# + + // Copyright (c) Microsoft. All rights reserved. + // Licensed under the MIT license. See LICENSE file in the project root for full license information. + + using System; + using System.Runtime.InteropServices; + + using ino_t = System.IntPtr; + using off_t = System.Int64; // Assuming either 64-bit machine or _FILE_OFFSET_BITS == 64 + + internal static partial class Interop + { + internal static partial class libc + { + [DllImport(Libraries.Libc, SetLastError = true)] + internal static extern IntPtr readdir(SafeDirHandle dirp); + + internal static unsafe DType GetDirEntType(IntPtr dirEnt) + { + return ((dirent*)dirEnt)->d_type; + } + + internal static unsafe string GetDirEntName(IntPtr dirEnt) + { + return Marshal.PtrToStringAnsi((IntPtr)((dirent*)dirEnt)->d_name); + } + + internal enum DType : byte + { + DT_UNKNOWN = 0, + DT_FIFO = 1, + DT_CHR = 2, + DT_DIR = 4, + DT_BLK = 6, + DT_REG = 8, + DT_LNK = 10, + DT_SOCK = 12, + DT_WHT = 14 + } + + #pragma warning disable 0649 // fields are assigned by P/Invoke call + private unsafe struct dirent + { + internal ino_t d_ino; + internal off_t d_off; + internal short d_reclen; + internal DType d_type; + internal fixed byte d_name[256]; + } + #pragma warning restore 0649 + } + } Notes ----- From dde2886395ed6f643790eece79099a72028c5c31 Mon Sep 17 00:00:00 2001 From: Phillip Carter Date: Wed, 19 Aug 2015 16:02:24 -0700 Subject: [PATCH 2/7] Adding in-document link to Unsafe Code section --- docs/concepts/primer.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/concepts/primer.rst b/docs/concepts/primer.rst index c6a47b3d84d20..70752d8cf4d56 100644 --- a/docs/concepts/primer.rst +++ b/docs/concepts/primer.rst @@ -47,6 +47,7 @@ As any mature and advanced application development framework, .NET has many powe * Dynamic language features * Code contracts * Native interoperability +* `Unsafe Code`_ Automatic memory management From 0b4ffdf5a3d5e8b6b56d17861ef8b2fe7a285d75 Mon Sep 17 00:00:00 2001 From: cartermp Date: Thu, 3 Sep 2015 11:01:57 -0700 Subject: [PATCH 3/7] Changing example from Linux Interop to StringBuilder The rationale here is that people will want to see the use of unsafe code from an algorithmic standpoint more than a systems interop standpoint. --- docs/concepts/primer.rst | 92 +++++++++++++++++----------------------- 1 file changed, 40 insertions(+), 52 deletions(-) diff --git a/docs/concepts/primer.rst b/docs/concepts/primer.rst index 70752d8cf4d56..665a4208532a9 100644 --- a/docs/concepts/primer.rst +++ b/docs/concepts/primer.rst @@ -262,61 +262,49 @@ The CLR enables the ability to acccess native memory and do pointer arithmetic via ``unsafe`` code. These operations are needed for certain algorithms and system interoperability. Although powerful, use of unsafe code is discouraged unless it is necessary to interop with system APIs or implement the most efficient algorithm. Unsafe code is not guaranteed to run in all environments, and also loses the benefits of a garbage collector and type safety. It's recommended to confine unsafe code as much as possible, and test that code extremely thoroughly. -Taken from the `.NET CoreFx Linux Interop Source `_: +Taken from the `StringBuilder class in the .NET BCL reference source `_: .. code-block:: c# - - // Copyright (c) Microsoft. All rights reserved. - // Licensed under the MIT license. See LICENSE file in the project root for full license information. - - using System; - using System.Runtime.InteropServices; - - using ino_t = System.IntPtr; - using off_t = System.Int64; // Assuming either 64-bit machine or _FILE_OFFSET_BITS == 64 - - internal static partial class Interop - { - internal static partial class libc - { - [DllImport(Libraries.Libc, SetLastError = true)] - internal static extern IntPtr readdir(SafeDirHandle dirp); - internal static unsafe DType GetDirEntType(IntPtr dirEnt) - { - return ((dirent*)dirEnt)->d_type; - } - - internal static unsafe string GetDirEntName(IntPtr dirEnt) - { - return Marshal.PtrToStringAnsi((IntPtr)((dirent*)dirEnt)->d_name); - } - - internal enum DType : byte - { - DT_UNKNOWN = 0, - DT_FIFO = 1, - DT_CHR = 2, - DT_DIR = 4, - DT_BLK = 6, - DT_REG = 8, - DT_LNK = 10, - DT_SOCK = 12, - DT_WHT = 14 - } - - #pragma warning disable 0649 // fields are assigned by P/Invoke call - private unsafe struct dirent - { - internal ino_t d_ino; - internal off_t d_off; - internal short d_reclen; - internal DType d_type; - internal fixed byte d_name[256]; - } - #pragma warning restore 0649 - } - } + public override String ToString() { + Contract.Ensures(Contract.Result() != null); + + VerifyClassInvariant(); + + if (Length == 0) + return String.Empty; + + string ret = string.FastAllocateString(Length); + StringBuilder chunk = this; + unsafe { + fixed (char* destinationPtr = ret) + { + do + { + if (chunk.m_ChunkLength > 0) + { + // Copy these into local variables so that they are stable even in the presence of ----s (hackers might do this) + char[] sourceArray = chunk.m_ChunkChars; + int chunkOffset = chunk.m_ChunkOffset; + int chunkLength = chunk.m_ChunkLength; + + // Check that we will not overrun our boundaries. + if ((uint)(chunkLength + chunkOffset) <= ret.Length && (uint)chunkLength <= (uint)sourceArray.Length) + { + fixed (char* sourcePtr = sourceArray) + string.wstrcpy(destinationPtr + chunkOffset, sourcePtr, chunkLength); + } + else + { + throw new ArgumentOutOfRangeException("chunkLength", Environment.GetResourceString("ArgumentOutOfRange_Index")); + } + } + chunk = chunk.m_ChunkPrevious; + } while (chunk != null); + } + } + return ret; + } Notes ----- From a3f1bf5b77ecd55203bda11e4d7033cc090b3e26 Mon Sep 17 00:00:00 2001 From: cartermp Date: Mon, 28 Sep 2015 13:07:14 -0700 Subject: [PATCH 4/7] Change link to github source, not reference source --- docs/concepts/primer.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/concepts/primer.rst b/docs/concepts/primer.rst index 665a4208532a9..827f38d57ed1d 100644 --- a/docs/concepts/primer.rst +++ b/docs/concepts/primer.rst @@ -262,7 +262,7 @@ The CLR enables the ability to acccess native memory and do pointer arithmetic via ``unsafe`` code. These operations are needed for certain algorithms and system interoperability. Although powerful, use of unsafe code is discouraged unless it is necessary to interop with system APIs or implement the most efficient algorithm. Unsafe code is not guaranteed to run in all environments, and also loses the benefits of a garbage collector and type safety. It's recommended to confine unsafe code as much as possible, and test that code extremely thoroughly. -Taken from the `StringBuilder class in the .NET BCL reference source `_: +Taken from the `StringBuilder class in the .NET BCL source `_: .. code-block:: c# From 0ba5eff6723e0c4476b8002404863150f14c6e62 Mon Sep 17 00:00:00 2001 From: Phillip Carter Date: Mon, 12 Oct 2015 15:36:54 -0700 Subject: [PATCH 5/7] Addressing richlander comments --- docs/concepts/primer.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/concepts/primer.rst b/docs/concepts/primer.rst index 827f38d57ed1d..2538727dfc009 100644 --- a/docs/concepts/primer.rst +++ b/docs/concepts/primer.rst @@ -258,22 +258,22 @@ Mono are fundamentally the same. Unsafe Code ~~~~~~~~~~~ -The CLR enables the ability to acccess native memory and do pointer -arithmetic via ``unsafe`` code. These operations are needed for certain algorithms and system interoperability. Although powerful, use of unsafe code is discouraged unless it is necessary to interop with system APIs or implement the most efficient algorithm. Unsafe code is not guaranteed to run in all environments, and also loses the benefits of a garbage collector and type safety. It's recommended to confine +The CLR enables the ability to access native memory and do pointer +arithmetic via ``unsafe`` code. These operations are needed for certain algorithms and system interoperability. Although powerful, use of unsafe code is discouraged unless it is necessary to interop with system APIs or implement the most efficient algorithm. Unsafe code may not predictably run in all environments, and also loses the benefits of a garbage collector and type safety. It's recommended to confine unsafe code as much as possible, and test that code extremely thoroughly. -Taken from the `StringBuilder class in the .NET BCL source `_: +The ``ToString()`` method from the `StringBuilder class `_. illustrates how using ``unsafe`` code can efficiently implement an algorithm by moving around chunks of memory directly: .. code-block:: c# - + public override String ToString() { Contract.Ensures(Contract.Result() != null); - + VerifyClassInvariant(); - + if (Length == 0) return String.Empty; - + string ret = string.FastAllocateString(Length); StringBuilder chunk = this; unsafe { @@ -287,8 +287,8 @@ Taken from the `StringBuilder class in the .NET BCL source Date: Tue, 13 Oct 2015 16:19:26 -0700 Subject: [PATCH 6/7] Merge in updates --- docs/concepts/primer.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/concepts/primer.rst b/docs/concepts/primer.rst index fc4048563f72e..72ccc3433e1f7 100644 --- a/docs/concepts/primer.rst +++ b/docs/concepts/primer.rst @@ -258,8 +258,7 @@ Unsafe Code ^^^^^^^^^^^ The CLR enables the ability to access native memory and do pointer -arithmetic via ``unsafe`` code. These operations are needed for certain algorithms and system interoperability. Although powerful, use of unsafe code is discouraged unless it is necessary to interop with system APIs or implement the most efficient algorithm. Unsafe code may not predictably run in all environments, and also loses the benefits of a garbage collector and type safety. It's recommended to confine -unsafe code as much as possible, and test that code thoroughly. +arithmetic via ``unsafe`` code. These operations are needed for certain algorithms and system interoperability. Although powerful, use of unsafe code is discouraged unless it is necessary to interop with system APIs or implement the most efficient algorithm. Unsafe code may not predictably run in all environments, and also loses the benefits of a garbage collector and type safety. It's recommended to confine unsafe code as much as possible, and test that code thoroughly. The ``ToString()`` method from the `StringBuilder class `_. illustrates how using ``unsafe`` code can efficiently implement an algorithm by moving around chunks of memory directly: From 943cd39ee72796a12c0641c21cf4710f74a26be1 Mon Sep 17 00:00:00 2001 From: Phillip Carter Date: Wed, 14 Oct 2015 17:10:10 -0700 Subject: [PATCH 7/7] Clear up what "reliably" meant in terms of execution of unsafe code --- docs/concepts/primer.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/concepts/primer.rst b/docs/concepts/primer.rst index 72ccc3433e1f7..985afed21ac0c 100644 --- a/docs/concepts/primer.rst +++ b/docs/concepts/primer.rst @@ -258,7 +258,7 @@ Unsafe Code ^^^^^^^^^^^ The CLR enables the ability to access native memory and do pointer -arithmetic via ``unsafe`` code. These operations are needed for certain algorithms and system interoperability. Although powerful, use of unsafe code is discouraged unless it is necessary to interop with system APIs or implement the most efficient algorithm. Unsafe code may not predictably run in all environments, and also loses the benefits of a garbage collector and type safety. It's recommended to confine unsafe code as much as possible, and test that code thoroughly. +arithmetic via ``unsafe`` code. These operations are needed for certain algorithms and system interoperability. Although powerful, use of unsafe code is discouraged unless it is necessary to interop with system APIs or implement the most efficient algorithm. Unsafe code may not execute the same way in different environments, and also loses the benefits of a garbage collector and type safety. It's recommended to confine and centralize unsafe code as much as possible, and test that code thoroughly. The ``ToString()`` method from the `StringBuilder class `_. illustrates how using ``unsafe`` code can efficiently implement an algorithm by moving around chunks of memory directly: