< Summary

Line coverage
0%
Covered lines: 0
Uncovered lines: 335
Coverable lines: 335
Total lines: 770
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 62
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

File(s)

D:\runner\runtime\src\libraries\Common\tests\TestUtilities\System\Buffers\BoundedMemory.Creation.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System.Runtime.InteropServices;
 5
 6namespace System.Buffers
 7{
 8    /// <summary>
 9    /// Contains factory methods to create <see cref="BoundedMemory{T}"/> instances.
 10    /// </summary>
 11    public static partial class BoundedMemory
 12    {
 013        public static bool UnixBoundsEnabled { get; set; }
 014        private static readonly int SystemPageSize = Environment.SystemPageSize;
 15
 16        /// <summary>
 17        /// Allocates a new <see cref="BoundedMemory{T}"/> region which is immediately preceded by
 18        /// or immediately followed by a poison (MEM_NOACCESS) page. If <paramref name="placement"/>
 19        /// is <see cref="PoisonPagePlacement.Before"/>, then attempting to read the memory
 20        /// immediately before the returned <see cref="BoundedMemory{T}"/> will result in an AV.
 21        /// If <paramref name="placement"/> is <see cref="PoisonPagePlacement.After"/>, then
 22        /// attempting to read the memory immediately after the returned <see cref="BoundedMemory{T}"/>
 23        /// will result in AV.
 24        /// </summary>
 25        /// <remarks>
 26        /// The newly-allocated memory will be populated with random data.
 27        /// </remarks>
 28        public static BoundedMemory<T> Allocate<T>(int elementCount, PoisonPagePlacement placement = PoisonPagePlacement
 029        {
 030            if (elementCount < 0)
 031            {
 032                throw new ArgumentOutOfRangeException(nameof(elementCount));
 33            }
 034            if (placement != PoisonPagePlacement.Before && placement != PoisonPagePlacement.After)
 035            {
 036                throw new ArgumentOutOfRangeException(nameof(placement));
 37            }
 38
 039            BoundedMemory<T> retVal = AllocateWithoutDataPopulation<T>(elementCount, placement);
 040            FillRandom(MemoryMarshal.AsBytes(retVal.Span));
 041            return retVal;
 042        }
 43
 44        /// <summary>
 45        /// Similar to <see cref="Allocate(int, PoisonPagePlacement)"/>, but populates the allocated
 46        /// native memory block from existing data rather than using random data.
 47        /// </summary>
 48        public static BoundedMemory<T> AllocateFromExistingData<T>(ReadOnlySpan<T> data, PoisonPagePlacement placement =
 049        {
 050            if (placement != PoisonPagePlacement.Before && placement != PoisonPagePlacement.After)
 051            {
 052                throw new ArgumentOutOfRangeException(nameof(placement));
 53            }
 54
 055            BoundedMemory<T> retVal = AllocateWithoutDataPopulation<T>(data.Length, placement);
 056            data.CopyTo(retVal.Span);
 057            return retVal;
 058        }
 59
 60        /// <summary>
 61        /// Similar to <see cref="Allocate(int, PoisonPagePlacement)"/>, but populates the allocated
 62        /// native memory block from existing data rather than using random data.
 63        /// </summary>
 64        public static BoundedMemory<T> AllocateFromExistingData<T>(T[] data, PoisonPagePlacement placement = PoisonPageP
 065        {
 066            return AllocateFromExistingData(new ReadOnlySpan<T>(data), placement);
 067        }
 68
 69        private static void FillRandom(Span<byte> buffer)
 070        {
 71            // Loop over a Random instance manually since Random.NextBytes(Span<byte>) doesn't
 72            // exist on all platforms we target.
 73
 074            Random random = new Random(); // doesn't need to be cryptographically strong
 75
 076            for (int i = 0; i < buffer.Length; i++)
 077            {
 078                buffer[i] = (byte)random.Next();
 079            }
 080        }
 81
 82        private static BoundedMemory<T> AllocateWithoutDataPopulation<T>(int elementCount, PoisonPagePlacement placement
 083        {
 084            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
 085            {
 086                return AllocateWithoutDataPopulationWindows<T>(elementCount, placement);
 87            }
 88#if NETFRAMEWORK
 89            return AllocateWithoutDataPopulationDefault<T>(elementCount, placement);
 90#else
 091            else if (OperatingSystem.IsBrowser() || OperatingSystem.IsWasi())
 092            {
 093                return AllocateWithoutDataPopulationDefault<T>(elementCount, placement);
 94            }
 095            return AllocateWithoutDataPopulationUnix<T>(elementCount, placement);
 96#endif
 097        }
 98    }
 99}

D:\runner\runtime\src\libraries\Common\tests\TestUtilities\System\Buffers\BoundedMemory.Default.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System.Runtime.InteropServices;
 5
 6namespace System.Buffers
 7{
 8    public static unsafe partial class BoundedMemory
 9    {
 10        private static DefaultImplementation<T> AllocateWithoutDataPopulationDefault<T>(int elementCount, PoisonPagePlac
 011        {
 12            // On non-Windows platforms, we don't yet have support for changing the permissions of individual pages.
 13            // We'll instead use AllocHGlobal / FreeHGlobal to carve out a r+w section of unmanaged memory.
 14
 015            return new DefaultImplementation<T>(elementCount);
 016        }
 17
 18        private sealed class DefaultImplementation<T> : BoundedMemory<T> where T : unmanaged
 19        {
 20            private readonly AllocHGlobalHandle _handle;
 21            private readonly int _elementCount;
 22            private readonly BoundedMemoryManager _memoryManager;
 23
 024            public DefaultImplementation(int elementCount)
 025            {
 026                _handle = AllocHGlobalHandle.Allocate(checked(elementCount * (nint)sizeof(T)));
 027                _elementCount = elementCount;
 028                _memoryManager = new BoundedMemoryManager(this);
 029            }
 30
 031            public override bool IsReadonly => false;
 32
 033            public override int Length => _elementCount;
 34
 035            public override Memory<T> Memory => _memoryManager.Memory;
 36
 37            public override Span<T> Span
 38            {
 39                get
 040                {
 041                    bool refAdded = false;
 42                    try
 043                    {
 044                        _handle.DangerousAddRef(ref refAdded);
 045                        return new Span<T>((void*)_handle.DangerousGetHandle(), _elementCount);
 46                    }
 47                    finally
 048                    {
 049                        if (refAdded)
 050                        {
 051                            _handle.DangerousRelease();
 052                        }
 053                    }
 054                }
 55            }
 56
 57            public override void Dispose()
 058            {
 059                _handle.Dispose();
 060            }
 61
 62            public override void MakeReadonly()
 063            {
 64                // no-op
 065            }
 66
 67            public override void MakeWriteable()
 068            {
 69                // no-op
 070            }
 71
 72            private sealed class BoundedMemoryManager : MemoryManager<T>
 73            {
 74                private readonly DefaultImplementation<T> _impl;
 75
 076                public BoundedMemoryManager(DefaultImplementation<T> impl)
 077                {
 078                    _impl = impl;
 079                }
 80
 081                public override Memory<T> Memory => CreateMemory(_impl._elementCount);
 82
 83                protected override void Dispose(bool disposing)
 084                {
 85                    // no-op; the handle will be disposed separately
 086                }
 87
 088                public override Span<T> GetSpan() => _impl.Span;
 89
 90                public override MemoryHandle Pin(int elementIndex)
 091                {
 092                    if ((uint)elementIndex > (uint)_impl._elementCount)
 093                    {
 094                        throw new ArgumentOutOfRangeException(paramName: nameof(elementIndex));
 95                    }
 96
 097                    bool refAdded = false;
 98                    try
 099                    {
 0100                        _impl._handle.DangerousAddRef(ref refAdded);
 0101                        return new MemoryHandle((T*)_impl._handle.DangerousGetHandle() + elementIndex);
 102                    }
 103                    finally
 0104                    {
 0105                        if (refAdded)
 0106                        {
 0107                            _impl._handle.DangerousRelease();
 0108                        }
 0109                    }
 0110                }
 111
 112                public override void Unpin()
 0113                {
 114                    // no-op - we don't unpin native memory
 0115                }
 116            }
 117        }
 118
 119        private sealed class AllocHGlobalHandle : SafeHandle
 120        {
 121            // Called by P/Invoke when returning SafeHandles
 122            private AllocHGlobalHandle()
 0123                : base(IntPtr.Zero, ownsHandle: true)
 0124            {
 0125            }
 126
 127            internal static AllocHGlobalHandle Allocate(nint byteLength)
 0128            {
 0129                AllocHGlobalHandle retVal = new AllocHGlobalHandle();
 0130                retVal.SetHandle(Marshal.AllocHGlobal(byteLength)); // this is for unit testing; don't bother setting up
 0131                return retVal;
 0132            }
 133
 134            // Do not provide a finalizer - SafeHandle's critical finalizer will
 135            // call ReleaseHandle for you.
 136
 0137            public override bool IsInvalid => (handle == IntPtr.Zero);
 138
 139            protected override bool ReleaseHandle()
 0140            {
 0141                Marshal.FreeHGlobal(handle);
 0142                return true;
 0143            }
 144        }
 145    }
 146}

D:\runner\runtime\src\libraries\Common\tests\TestUtilities\System\Buffers\BoundedMemory.Unix.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using Microsoft.Win32.SafeHandles;
 5using System.IO.MemoryMappedFiles;
 6using System.Runtime.InteropServices;
 7
 8namespace System.Buffers
 9{
 10#if !NETFRAMEWORK
 11    public static unsafe partial class BoundedMemory
 12    {
 13        private static UnixImplementation<T> AllocateWithoutDataPopulationUnix<T>(int elementCount, PoisonPagePlacement 
 014        {
 015            return new UnixImplementation<T>(elementCount, placement);
 016        }
 17
 18        private sealed class UnixImplementation<T> : BoundedMemory<T> where T : unmanaged
 19        {
 20            private readonly MMapHandle _handle;
 21            private readonly int _elementCount;
 22            private readonly BoundedMemoryManager _memoryManager;
 23
 024            public UnixImplementation(int elementCount, PoisonPagePlacement placement)
 025            {
 026                _handle = MMapHandle.Allocate(checked(elementCount * (nint)sizeof(T)), placement);
 027                _elementCount = elementCount;
 028                _memoryManager = new BoundedMemoryManager(this);
 029            }
 30
 031            public override bool IsReadonly => false;
 32
 033            public override int Length => _elementCount;
 34
 035            public override Memory<T> Memory => _memoryManager.Memory;
 36
 37            public override Span<T> Span
 38            {
 39                get
 040                {
 041                    bool refAdded = false;
 42                    try
 043                    {
 044                        _handle.DangerousAddRef(ref refAdded);
 045                        return new Span<T>((void*)_handle.DangerousGetHandle(), _elementCount);
 46                    }
 47                    finally
 048                    {
 049                        if (refAdded)
 050                        {
 051                            _handle.DangerousRelease();
 052                        }
 053                    }
 054                }
 55            }
 56
 57            public override void Dispose()
 058            {
 059                _handle.Dispose();
 060            }
 61
 62            public override void MakeReadonly()
 063            {
 64                // no-op
 065            }
 66
 67            public override void MakeWriteable()
 068            {
 69                // no-op
 070            }
 71
 72            private sealed class BoundedMemoryManager : MemoryManager<T>
 73            {
 74                private readonly UnixImplementation<T> _impl;
 75
 076                public BoundedMemoryManager(UnixImplementation<T> impl)
 077                {
 078                    _impl = impl;
 079                }
 80
 081                public override Memory<T> Memory => CreateMemory(_impl._elementCount);
 82
 83                protected override void Dispose(bool disposing)
 084                {
 85                    // no-op; the handle will be disposed separately
 086                }
 87
 088                public override Span<T> GetSpan() => _impl.Span;
 89
 90                public override MemoryHandle Pin(int elementIndex)
 091                {
 092                    if ((uint)elementIndex > (uint)_impl._elementCount)
 093                    {
 094                        throw new ArgumentOutOfRangeException(paramName: nameof(elementIndex));
 95                    }
 96
 097                    bool refAdded = false;
 98                    try
 099                    {
 0100                        _impl._handle.DangerousAddRef(ref refAdded);
 0101                        return new MemoryHandle((T*)_impl._handle.DangerousGetHandle() + elementIndex);
 102                    }
 103                    finally
 0104                    {
 0105                        if (refAdded)
 0106                        {
 0107                            _impl._handle.DangerousRelease();
 0108                        }
 0109                    }
 0110                }
 111
 112                public override void Unpin()
 0113                {
 114                    // no-op - we don't unpin native memory
 0115                }
 116            }
 117        }
 118
 119        private sealed class MMapHandle : SafeHandle
 120        {
 121            private IntPtr buffer;
 122            private ulong allocationSize;
 123
 124            // Called by P/Invoke when returning SafeHandles
 125            private MMapHandle(IntPtr buffer, ulong allocationSize)
 0126                : base(IntPtr.Zero, ownsHandle: true)
 0127            {
 0128                this.buffer = buffer;
 0129                this.allocationSize = allocationSize;
 0130            }
 131
 132            internal static MMapHandle Allocate(nint byteLength, PoisonPagePlacement placement)
 0133            {
 134                // Allocate number of pages to incorporate required (byteLength bytes of) memory and an additional page 
 0135                int pageSize = Environment.SystemPageSize;
 0136                int allocationSize = (int)(((byteLength / pageSize) + ((byteLength % pageSize) == 0 ? 0 : 1) + 1) * page
 0137                IntPtr buffer = MMap(0, (ulong)allocationSize, (int)(MemoryMappedProtections.PROT_READ | MemoryMappedPro
 138
 139                // Depending on the PoisonPagePlacement requirement (before/after) initialise the baseAddress and poison
 140                // in the buffer. Here the baseAddress points to the first valid allocation and poisonPageAddress points
 141                // For `PoisonPagePlacement.Before` the first page is made inaccessible using mprotect and baseAddress p
 142                // The allocation and protection is at the granularity of a page. Thus, `PoisonPagePlacement.Before` con
 143                // memory at the end of the page (bytes equivalent to `pageSize - (byteLength % pageSize)`).
 144                // For `PoisonPagePlacement.After`, we adjust the baseAddress so that inaccessible memory is at the `byt
 0145                IntPtr baseAddress = buffer + pageSize;
 0146                IntPtr poisonPageAddress = buffer;
 0147                if (placement == PoisonPagePlacement.After)
 0148                {
 0149                    baseAddress = buffer + (allocationSize - pageSize - byteLength);
 0150                    poisonPageAddress = buffer + (allocationSize - pageSize);
 0151                }
 152
 153                // Protect the page before/after based on the poison page placement.
 0154                if (MProtect(poisonPageAddress, (ulong)pageSize, (int)MemoryMappedProtections.PROT_NONE) == -1)
 0155                {
 0156                    throw new InvalidOperationException($"Failed to mark page as a poison page using mprotect with error
 157                }
 158
 0159                MMapHandle retVal = new MMapHandle(buffer, (ulong)allocationSize);
 0160                retVal.SetHandle(baseAddress); // this base address would be used as the start of Span that is used duri
 0161                return retVal;
 0162            }
 163
 0164            public override bool IsInvalid => (handle == IntPtr.Zero);
 165
 166            protected override bool ReleaseHandle()
 0167            {
 0168                MUnmap(buffer, allocationSize);
 0169                return true;
 0170            }
 171
 172            [Flags]
 173            private enum MemoryMappedProtections
 174            {
 175                PROT_NONE = 0x0,
 176                PROT_READ = 0x1,
 177                PROT_WRITE = 0x2,
 178                PROT_EXEC = 0x4
 179            }
 180
 181            [Flags]
 182            private enum MemoryMappedFlags
 183            {
 184                MAP_SHARED = 0x01,
 185                MAP_PRIVATE = 0x02,
 186                MAP_ANONYMOUS = 0x10,
 187            }
 188
 189            private const string SystemNative = "libSystem.Native";
 190
 191            // NOTE: Shim returns null pointer on failure, not non-null MAP_FAILED sentinel.
 192            [DllImport(SystemNative, EntryPoint = "SystemNative_MMap", SetLastError = true)]
 193            private static extern IntPtr MMap(IntPtr addr, ulong len, int prot, int flags, IntPtr fd, long offset);
 194
 195            [DllImport(SystemNative, EntryPoint = "SystemNative_MProtect", SetLastError = true)]
 196            private static extern int MProtect(IntPtr addr, ulong len, int prot);
 197
 198            [DllImport(SystemNative, EntryPoint = "SystemNative_MUnmap", SetLastError = true)]
 199            internal static extern int MUnmap(IntPtr addr, ulong len);
 200        }
 201    }
 202#endif
 203}

D:\runner\runtime\src\libraries\Common\tests\TestUtilities\System\Buffers\BoundedMemory.Windows.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System.Runtime.InteropServices;
 5
 6namespace System.Buffers
 7{
 8    public static unsafe partial class BoundedMemory
 9    {
 10        private static WindowsImplementation<T> AllocateWithoutDataPopulationWindows<T>(int elementCount, PoisonPagePlac
 011        {
 12            long cb, totalBytesToAllocate;
 13            checked
 014            {
 015                cb = elementCount * sizeof(T);
 016                totalBytesToAllocate = cb;
 17
 18                // We only need to round the count up if it's not an exact multiple
 19                // of the system page size.
 20
 021                long leftoverBytes = totalBytesToAllocate % SystemPageSize;
 022                if (leftoverBytes != 0)
 023                {
 024                    totalBytesToAllocate += SystemPageSize - leftoverBytes;
 025                }
 26
 27                // Finally, account for the poison pages at the front and back.
 28
 029                totalBytesToAllocate += 2 * SystemPageSize;
 030            }
 31
 32            // Reserve and commit the entire range as NOACCESS.
 33            VirtualAllocHandle handle;
 34            checked
 035            {
 036                handle = VirtualAllocHandle.Allocate(
 037                    lpAddress: IntPtr.Zero,
 038                    dwSize: (IntPtr)totalBytesToAllocate /* cast throws OverflowException if out of range */,
 039                    flAllocationType: VirtualAllocAllocationType.MEM_RESERVE | VirtualAllocAllocationType.MEM_COMMIT,
 040                    flProtect: VirtualAllocProtection.PAGE_NOACCESS);
 041            }
 42
 043            if (handle == null || handle.IsInvalid)
 044            {
 045                int lastError = Marshal.GetHRForLastWin32Error();
 046                handle?.Dispose();
 047                Marshal.ThrowExceptionForHR(lastError);
 048                throw new InvalidOperationException("VirtualAlloc failed unexpectedly.");
 49            }
 50
 51            // Done allocating! Now carve out a READWRITE section bookended by the NOACCESS
 52            // pages and return that carved-out section to the caller. Since memory protection
 53            // flags only apply at page-level granularity, we need to "left-align" or "right-
 54            // align" the section we carve out so that it's guaranteed adjacent to one of
 55            // the NOACCESS bookend pages.
 56
 057            return new WindowsImplementation<T>(
 058                handle: handle,
 059                byteOffsetIntoHandle: (placement == PoisonPagePlacement.Before)
 060                    ? SystemPageSize /* just after leading poison page */
 061                    : checked((int)(totalBytesToAllocate - SystemPageSize - cb)) /* just before trailing poison page */,
 062                elementCount: elementCount)
 063            {
 064                Protection = VirtualAllocProtection.PAGE_READWRITE
 065            };
 066        }
 67
 68        private sealed class WindowsImplementation<T> : BoundedMemory<T> where T : unmanaged
 69        {
 70            private readonly VirtualAllocHandle _handle;
 71            private readonly int _byteOffsetIntoHandle;
 72            private readonly int _elementCount;
 73            private readonly BoundedMemoryManager _memoryManager;
 74
 075            internal WindowsImplementation(VirtualAllocHandle handle, int byteOffsetIntoHandle, int elementCount)
 076            {
 077                _handle = handle;
 078                _byteOffsetIntoHandle = byteOffsetIntoHandle;
 079                _elementCount = elementCount;
 080                _memoryManager = new BoundedMemoryManager(this);
 081            }
 82
 083            public override bool IsReadonly => (Protection != VirtualAllocProtection.PAGE_READWRITE);
 84
 085            public override int Length => _elementCount;
 86
 87            internal VirtualAllocProtection Protection
 88            {
 89                get
 090                {
 091                    bool refAdded = false;
 92                    try
 093                    {
 094                        _handle.DangerousAddRef(ref refAdded);
 95                        MEMORY_BASIC_INFORMATION memoryInfo;
 096                        if (UnsafeNativeMethods.VirtualQuery(
 097                            lpAddress: _handle.DangerousGetHandle() + _byteOffsetIntoHandle,
 098                            lpBuffer: &memoryInfo,
 099                            dwLength: (IntPtr)sizeof(MEMORY_BASIC_INFORMATION)) == IntPtr.Zero)
 0100                        {
 0101                            Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
 0102                            throw new InvalidOperationException("VirtualQuery failed unexpectedly.");
 103                        }
 0104                        return memoryInfo.Protect;
 105                    }
 106                    finally
 0107                    {
 0108                        if (refAdded)
 0109                        {
 0110                            _handle.DangerousRelease();
 0111                        }
 0112                    }
 0113                }
 114                set
 0115                {
 0116                    if (_elementCount > 0)
 0117                    {
 0118                        bool refAdded = false;
 119                        try
 0120                        {
 0121                            _handle.DangerousAddRef(ref refAdded);
 122                            VirtualAllocProtection flOldProtect;
 0123                            if (UnsafeNativeMethods.VirtualProtect(
 0124                                lpAddress: _handle.DangerousGetHandle() + _byteOffsetIntoHandle,
 0125                                dwSize: (IntPtr)(&((T*)null)[_elementCount]),
 0126                                flNewProtect: value,
 0127                                lpflOldProtect: &flOldProtect) == 0)
 0128                            {
 0129                                Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
 0130                                throw new InvalidOperationException("VirtualProtect failed unexpectedly.");
 131                            }
 0132                        }
 133                        finally
 0134                        {
 0135                            if (refAdded)
 0136                            {
 0137                                _handle.DangerousRelease();
 0138                            }
 0139                        }
 0140                    }
 0141                }
 142            }
 143
 0144            public override Memory<T> Memory => _memoryManager.Memory;
 145
 146            public override Span<T> Span
 147            {
 148                get
 0149                {
 0150                    bool refAdded = false;
 151                    try
 0152                    {
 0153                        _handle.DangerousAddRef(ref refAdded);
 0154                        return new Span<T>((void*)(_handle.DangerousGetHandle() + _byteOffsetIntoHandle), _elementCount)
 155                    }
 156                    finally
 0157                    {
 0158                        if (refAdded)
 0159                        {
 0160                            _handle.DangerousRelease();
 0161                        }
 0162                    }
 0163                }
 164            }
 165
 166            public override void Dispose()
 0167            {
 0168                _handle.Dispose();
 0169            }
 170
 171            public override void MakeReadonly()
 0172            {
 0173                Protection = VirtualAllocProtection.PAGE_READONLY;
 0174            }
 175
 176            public override void MakeWriteable()
 0177            {
 0178                Protection = VirtualAllocProtection.PAGE_READWRITE;
 0179            }
 180
 181            private sealed class BoundedMemoryManager : MemoryManager<T>
 182            {
 183                private readonly WindowsImplementation<T> _impl;
 184
 0185                public BoundedMemoryManager(WindowsImplementation<T> impl)
 0186                {
 0187                    _impl = impl;
 0188                }
 189
 0190                public override Memory<T> Memory => CreateMemory(_impl._elementCount);
 191
 192                protected override void Dispose(bool disposing)
 0193                {
 194                    // no-op; the handle will be disposed separately
 0195                }
 196
 0197                public override Span<T> GetSpan() => _impl.Span;
 198
 199                public override MemoryHandle Pin(int elementIndex)
 0200                {
 0201                    if ((uint)elementIndex > (uint)_impl._elementCount)
 0202                    {
 0203                        throw new ArgumentOutOfRangeException(paramName: nameof(elementIndex));
 204                    }
 205
 0206                    bool refAdded = false;
 207                    try
 0208                    {
 0209                        _impl._handle.DangerousAddRef(ref refAdded);
 0210                        return new MemoryHandle((T*)(_impl._handle.DangerousGetHandle() + _impl._byteOffsetIntoHandle) +
 211                    }
 212                    finally
 0213                    {
 0214                        if (refAdded)
 0215                        {
 0216                            _impl._handle.DangerousRelease();
 0217                        }
 0218                    }
 0219                }
 220
 221                public override void Unpin()
 0222                {
 223                    // no-op - we don't unpin native memory
 0224                }
 225            }
 226        }
 227
 228        // from winnt.h
 229        [Flags]
 230        private enum VirtualAllocAllocationType : uint
 231        {
 232            MEM_COMMIT = 0x1000,
 233            MEM_RESERVE = 0x2000,
 234            MEM_DECOMMIT = 0x4000,
 235            MEM_RELEASE = 0x8000,
 236            MEM_FREE = 0x10000,
 237            MEM_PRIVATE = 0x20000,
 238            MEM_MAPPED = 0x40000,
 239            MEM_RESET = 0x80000,
 240            MEM_TOP_DOWN = 0x100000,
 241            MEM_WRITE_WATCH = 0x200000,
 242            MEM_PHYSICAL = 0x400000,
 243            MEM_ROTATE = 0x800000,
 244            MEM_LARGE_PAGES = 0x20000000,
 245            MEM_4MB_PAGES = 0x80000000,
 246        }
 247
 248        // from winnt.h
 249        [Flags]
 250        private enum VirtualAllocProtection : uint
 251        {
 252            PAGE_NOACCESS = 0x01,
 253            PAGE_READONLY = 0x02,
 254            PAGE_READWRITE = 0x04,
 255            PAGE_WRITECOPY = 0x08,
 256            PAGE_EXECUTE = 0x10,
 257            PAGE_EXECUTE_READ = 0x20,
 258            PAGE_EXECUTE_READWRITE = 0x40,
 259            PAGE_EXECUTE_WRITECOPY = 0x80,
 260            PAGE_GUARD = 0x100,
 261            PAGE_NOCACHE = 0x200,
 262            PAGE_WRITECOMBINE = 0x400,
 263        }
 264
 265        [StructLayout(LayoutKind.Sequential)]
 266        private struct MEMORY_BASIC_INFORMATION
 267        {
 268            public IntPtr BaseAddress;
 269            public IntPtr AllocationBase;
 270            public VirtualAllocProtection AllocationProtect;
 271            public IntPtr RegionSize;
 272            public VirtualAllocAllocationType State;
 273            public VirtualAllocProtection Protect;
 274            public VirtualAllocAllocationType Type;
 275        };
 276
 277        private sealed class VirtualAllocHandle : SafeHandle
 278        {
 279            // Called by P/Invoke when returning SafeHandles
 280            public VirtualAllocHandle()
 0281                : base(IntPtr.Zero, ownsHandle: true)
 0282            {
 0283            }
 284
 285            internal static VirtualAllocHandle Allocate(IntPtr lpAddress, IntPtr dwSize, VirtualAllocAllocationType flAl
 0286            {
 0287                VirtualAllocHandle retVal = new VirtualAllocHandle();
 0288                retVal.SetHandle(UnsafeNativeMethods.VirtualAlloc(lpAddress, dwSize, flAllocationType, flProtect));
 0289                return retVal;
 0290            }
 291
 292            // Do not provide a finalizer - SafeHandle's critical finalizer will
 293            // call ReleaseHandle for you.
 294
 0295            public override bool IsInvalid => (handle == IntPtr.Zero);
 296
 297            protected override bool ReleaseHandle() =>
 0298                UnsafeNativeMethods.VirtualFree(handle, IntPtr.Zero, VirtualAllocAllocationType.MEM_RELEASE) != 0;
 299        }
 300
 301        private static partial class UnsafeNativeMethods
 302        {
 303            private const string KERNEL32_LIB = "kernel32.dll";
 304
 305            // https://msdn.microsoft.com/en-us/library/windows/desktop/aa366887(v=vs.85).aspx
 306            [DllImport(KERNEL32_LIB, SetLastError = true)]
 307            public static extern IntPtr VirtualAlloc(IntPtr lpAddress, IntPtr dwSize, VirtualAllocAllocationType flAlloc
 308
 309            // https://msdn.microsoft.com/en-us/library/windows/desktop/aa366892(v=vs.85).aspx
 310            [DllImport(KERNEL32_LIB, SetLastError = true)]
 311            public static extern int VirtualFree(IntPtr lpAddress, IntPtr dwSize, VirtualAllocAllocationType dwFreeType)
 312
 313            // https://msdn.microsoft.com/en-us/library/windows/desktop/aa366898(v=vs.85).aspx
 314            [DllImport(KERNEL32_LIB, SetLastError = true)]
 315            public static extern int VirtualProtect(IntPtr lpAddress, IntPtr dwSize, VirtualAllocProtection flNewProtect
 316
 317            // https://msdn.microsoft.com/en-us/library/windows/desktop/aa366902(v=vs.85).aspx
 318            [DllImport(KERNEL32_LIB, SetLastError = true)]
 319            public static extern IntPtr VirtualQuery(IntPtr lpAddress, MEMORY_BASIC_INFORMATION* lpBuffer, IntPtr dwLeng
 320        }
 321    }
 322}

Methods/Properties

UnixBoundsEnabled()
.cctor()
Allocate(System.Int32,System.Buffers.PoisonPagePlacement)
AllocateFromExistingData(System.ReadOnlySpan`1<T>,System.Buffers.PoisonPagePlacement)
AllocateFromExistingData(T[],System.Buffers.PoisonPagePlacement)
FillRandom(System.Span`1<System.Byte>)
AllocateWithoutDataPopulation(System.Int32,System.Buffers.PoisonPagePlacement)
AllocateWithoutDataPopulationDefault(System.Int32,System.Buffers.PoisonPagePlacement)
.ctor(System.Int32)
IsReadonly()
Length()
Memory()
Span()
Dispose()
MakeReadonly()
MakeWriteable()
.ctor(System.Buffers.BoundedMemory/DefaultImplementation`1<T>)
Memory()
Dispose(System.Boolean)
GetSpan()
Pin(System.Int32)
Unpin()
.ctor()
Allocate(System.IntPtr)
IsInvalid()
ReleaseHandle()
AllocateWithoutDataPopulationUnix(System.Int32,System.Buffers.PoisonPagePlacement)
.ctor(System.Int32,System.Buffers.PoisonPagePlacement)
IsReadonly()
Length()
Memory()
Span()
Dispose()
MakeReadonly()
MakeWriteable()
.ctor(System.Buffers.BoundedMemory/UnixImplementation`1<T>)
Memory()
Dispose(System.Boolean)
GetSpan()
Pin(System.Int32)
Unpin()
.ctor(System.IntPtr,System.UInt64)
Allocate(System.IntPtr,System.Buffers.PoisonPagePlacement)
IsInvalid()
ReleaseHandle()
AllocateWithoutDataPopulationWindows(System.Int32,System.Buffers.PoisonPagePlacement)
.ctor(System.Buffers.BoundedMemory/VirtualAllocHandle,System.Int32,System.Int32)
IsReadonly()
Length()
Protection()
Protection(System.Buffers.BoundedMemory/VirtualAllocProtection)
Memory()
Span()
Dispose()
MakeReadonly()
MakeWriteable()
.ctor(System.Buffers.BoundedMemory/WindowsImplementation`1<T>)
Memory()
Dispose(System.Boolean)
GetSpan()
Pin(System.Int32)
Unpin()
.ctor()
Allocate(System.IntPtr,System.IntPtr,System.Buffers.BoundedMemory/VirtualAllocAllocationType,System.Buffers.BoundedMemory/VirtualAllocProtection)
IsInvalid()
ReleaseHandle()