1 //------------------------------------------------------------------------------
2 // <copyright file="PinnedArraySegment.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //------------------------------------------------------------------------------
7 namespace System.Web.Util {
9 using System.Diagnostics.CodeAnalysis;
10 using System.Runtime.InteropServices;
11 using System.Security.Permissions;
13 // Utility class for pinning an ArraySegment<T> so that it can be passed to unmanaged code.
15 // This type is not thread safe.
17 [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)]
18 internal sealed class PinnedArraySegment<T> : IDisposable {
21 private GCHandle _gcHandle;
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;
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);
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;
46 public IntPtr Pointer {
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;
62 private void ThrowIfDisposed() {
63 if (_pointer == IntPtr.Zero) {
64 throw new ObjectDisposedException(GetType().FullName);