Merge pull request #2964 from ludovic-henry/sgen-monocontext
[mono.git] / mcs / class / referencesource / System.Web / Util / PinnedArraySegment.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="PinnedArraySegment.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>                                                                
5 //------------------------------------------------------------------------------
6
7 namespace System.Web.Util {
8     using System;
9     using System.Diagnostics.CodeAnalysis;
10     using System.Runtime.InteropServices;
11     using System.Security.Permissions;
12
13     // Utility class for pinning an ArraySegment<T> so that it can be passed to unmanaged code.
14     //
15     // This type is not thread safe.
16
17     [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
18     internal sealed class PinnedArraySegment<T> : IDisposable {
19
20         private int _count;
21         private GCHandle _gcHandle;
22
23         [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources", Justification = @"This is a memory pointer, not a handle. The handle is in the _gcHandle field, and its lifetime is controlled by the caller.")]
24         private IntPtr _pointer;
25
26         internal unsafe PinnedArraySegment(ArraySegment<T> segment) {
27             // Structs - like ArraySegment<T> - can be "torn" by malicious users trying to take
28             // advantage of race conditions that occur as a result of their copy-by-value semantics.
29             // Since we'll pass the ArraySegment<T> to unmanaged code, we need to perform validation
30             // to make sure that this hasn't happened. The ArraySegment<T> constructor can be used
31             // to perform this validation. (MSRC 10170)
32             segment = new ArraySegment<T>(segment.Array, segment.Offset, segment.Count);
33
34             _gcHandle = GCHandle.Alloc(segment.Array, GCHandleType.Pinned); // pin the array so that unmanaged code can access it
35             _pointer = Marshal.UnsafeAddrOfPinnedArrayElement(segment.Array, segment.Offset);
36             _count = segment.Count;
37         }
38
39         public int Count {
40             get {
41                 ThrowIfDisposed();
42                 return _count;
43             }
44         }
45
46         public IntPtr Pointer {
47             get {
48                 ThrowIfDisposed();
49                 return _pointer;
50             }
51         }
52
53         [SuppressMessage("Microsoft.Usage", "CA2216:DisposableTypesShouldDeclareFinalizer", Justification = @"We don't own native resources.")]
54         public void Dispose() {
55             if (_pointer != IntPtr.Zero) {
56                 // only free the GCHandle once
57                 _pointer = IntPtr.Zero;
58                 _gcHandle.Free();
59             }
60         }
61
62         private void ThrowIfDisposed() {
63             if (_pointer == IntPtr.Zero) {
64                 throw new ObjectDisposedException(GetType().FullName);
65             }
66         }
67
68     }
69 }