Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / clr / src / BCL / System / Runtime / InteropServices / SafeBuffer.cs / 1305376 / SafeBuffer.cs
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
/*============================================================
**
** Purpose: Unsafe code that uses pointers should use
** SafePointer to fix subtle lifetime problems with the
** underlying resource.
**
===========================================================*/
// Design points:
// *) Avoid handle-recycling problems (including ones triggered via
// resurrection attacks) for all accesses via pointers. This requires tying
// together the lifetime of the unmanaged resource with the code that reads
// from that resource, in a package that uses synchronization to enforce
// the correct semantics during finalization. We're using SafeHandle's
// ref count as a gate on whether the pointer can be dereferenced because that
// controls the lifetime of the resource.
//
// *) Keep the penalties for using this class small, both in terms of space
// and time. Having multiple threads reading from a memory mapped file
// will already require 2 additional interlocked operations. If we add in
// a "current position" concept, that requires additional space in memory and
// synchronization. Since the position in memory is often (but not always)
// something that can be stored on the stack, we can save some memory by
// excluding it from this object. However, avoiding the need for
// synchronization is a more significant win. This design allows multiple
// threads to read and write memory simultaneously without locks (as long as
// you don't write to a region of memory that overlaps with what another
// thread is accessing).
//
// *) Space-wise, we use the following memory, including SafeHandle's fields:
// Object Header MT* handle int bool bool <2 pad bytes> length
// On 32 bit platforms: 24 bytes. On 64 bit platforms: 40 bytes.
// (We can safe 4 bytes on x86 only by shrinking SafeHandle)
//
// *) Wrapping a SafeHandle would have been a nice solution, but without an
// ordering between critical finalizable objects, it would have required
// changes to each SafeHandle subclass to opt in to being usable from a
// SafeBuffer (or some clever exposure of SafeHandle's state fields and a
// way of forcing ReleaseHandle to run even after the SafeHandle has been
// finalized with a ref count > 1). We can use less memory and create fewer
// objects by simply inserting a SafeBuffer into the class hierarchy.
//
// *) In an ideal world, we could get marshaling support for SafeBuffer that
// would allow us to annotate a P/Invoke declaration, saying this parameter
// specifies the length of the buffer, and the units of that length are X.
// P/Invoke would then pass that size parameter to SafeBuffer.
// [DllImport(...)]
// static extern SafeMemoryHandle AllocCharBuffer(int numChars);
// If we could put an attribute on the SafeMemoryHandle saying numChars is
// the element length, and it must be multiplied by 2 to get to the byte
// length, we can simplify the usage model for SafeBuffer.
//
// *) This class could benefit from a constraint saying T is a value type
// containing no GC references.
// Implementation notes:
// *) The Initialize method must be called before you use any instance of
// a SafeBuffer. To avoid ----s when storing SafeBuffers in statics,
// you either need to take a lock when publishing the SafeBuffer, or you
// need to create a local, initialize the SafeBuffer, then assign to the
// static variable (perhaps using Interlocked.CompareExchange). Of course,
// assignments in a static class constructor are under a lock implicitly.
namespace System.Runtime.InteropServices
{
using System;
using System.Security.Permissions;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using System.Runtime.ConstrainedExecution;
using System.Runtime.Versioning;
using Microsoft.Win32.SafeHandles;
using System.Diagnostics.Contracts;
[System.Security.SecurityCritical]
public abstract unsafe class SafeBuffer : SafeHandleZeroOrMinusOneIsInvalid
{
// Steal UIntPtr.MaxValue as our uninitialized value.
private static readonly UIntPtr Uninitialized = (UIntPtr.Size == 4) ?
((UIntPtr) UInt32.MaxValue) : ((UIntPtr) UInt64.MaxValue);
private UIntPtr _numBytes;
protected SafeBuffer(bool ownsHandle) : base(ownsHandle)
{
_numBytes = Uninitialized;
}
///
/// Specifies the size of the region of memory, in bytes. Must be
/// called before using the SafeBuffer.
///
/// Number of valid bytes in memory.
[CLSCompliant(false)]
public void Initialize(ulong numBytes)
{
if (numBytes < 0)
throw new ArgumentOutOfRangeException("numBytes", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
if (IntPtr.Size == 4 && numBytes > UInt32.MaxValue)
throw new ArgumentOutOfRangeException("numBytes", Environment.GetResourceString("ArgumentOutOfRange_AddressSpace"));
Contract.EndContractBlock();
if (numBytes >= (ulong)Uninitialized)
throw new ArgumentOutOfRangeException("numBytes", Environment.GetResourceString("ArgumentOutOfRange_UIntPtrMax-1"));
_numBytes = (UIntPtr) numBytes;
}
///
/// Specifies the the size of the region in memory, as the number of
/// elements in an array. Must be called before using the SafeBuffer.
///
[CLSCompliant(false)]
public void Initialize(uint numElements, uint sizeOfEachElement)
{
if (numElements < 0)
throw new ArgumentOutOfRangeException("numElements", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
if (sizeOfEachElement < 0)
throw new ArgumentOutOfRangeException("sizeOfEachElement", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
if (IntPtr.Size == 4 && numElements * sizeOfEachElement > UInt32.MaxValue)
throw new ArgumentOutOfRangeException("numBytes", Environment.GetResourceString("ArgumentOutOfRange_AddressSpace"));
Contract.EndContractBlock();
if (numElements * sizeOfEachElement >= (ulong)Uninitialized)
throw new ArgumentOutOfRangeException("numElements", Environment.GetResourceString("ArgumentOutOfRange_UIntPtrMax-1"));
_numBytes = checked((UIntPtr) (numElements * sizeOfEachElement));
}
#if !FEATURE_CORECLR
///
/// Specifies the the size of the region in memory, as the number of
/// elements in an array. Must be called before using the SafeBuffer.
///
[CLSCompliant(false)]
public void Initialize(uint numElements) where T : struct
{
Initialize(numElements, Marshal.AlignedSizeOf());
}
#endif
// Callers should ensure that they check whether the pointer ref param
// is null when AcquirePointer returns. If it is not null, they must
// call ReleasePointer in a CER. This method calls DangerousAddRef
// & exposes the pointer. Unlike Read, it does not alter the "current
// position" of the pointer. Here's how to use it:
//
// byte* pointer = null;
// RuntimeHelpers.PrepareConstrainedRegions();
// try {
// safeBuffer.AcquirePointer(ref pointer);
// // Use pointer here, with your own bounds checking
// }
// finally {
// if (pointer != null)
// safeBuffer.ReleasePointer();
// }
//
// Note: If you cast this byte* to a T*, you have to worry about
// whether your pointer is aligned. Additionally, you must take
// responsibility for all bounds checking with this pointer.
///
/// Obtain the pointer from a SafeBuffer for a block of code,
/// with the express responsibility for bounds checking and calling
/// ReleasePointer later within a CER to ensure the pointer can be
/// freed later. This method either completes successfully or
/// throws an exception and returns with pointer set to null.
///
/// A byte*, passed by reference, to receive
/// the pointer from within the SafeBuffer. You must set
/// pointer to null before calling this method.
[CLSCompliant(false)]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
public void AcquirePointer(ref byte* pointer)
{
if (_numBytes == Uninitialized)
throw NotInitialized();
pointer = null;
RuntimeHelpers.PrepareConstrainedRegions();
try
{
}
finally
{
bool junk = false;
DangerousAddRef(ref junk);
pointer = (byte*)handle;
}
}
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
public void ReleasePointer()
{
if (_numBytes == Uninitialized)
throw NotInitialized();
DangerousRelease();
}
#if !FEATURE_CORECLR
///
/// Read a value type from memory at the given offset. This is
/// equivalent to: return *(T*)(bytePtr + byteOffset);
///
/// The value type to read
/// Where to start reading from memory. You
/// may have to consider alignment.
/// An instance of T read from memory.
[CLSCompliant(false)]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
public T Read(ulong byteOffset) where T : struct {
if (_numBytes == Uninitialized)
throw NotInitialized();
uint sizeofT = Marshal.SizeOf();
byte* ptr = (byte*)handle + byteOffset;
SpaceCheck(ptr, sizeofT);
// return *(T*) (_ptr + byteOffset);
T value;
bool mustCallRelease = false;
RuntimeHelpers.PrepareConstrainedRegions();
try
{
DangerousAddRef(ref mustCallRelease);
GenericPtrToStructure(ptr, out value, sizeofT);
}
finally
{
if (mustCallRelease)
DangerousRelease();
}
return value;
}
[CLSCompliant(false)]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
public void ReadArray(ulong byteOffset, T[] array, int index, int count)
where T : struct
{
if (array == null)
throw new ArgumentNullException("array", Environment.GetResourceString("ArgumentNull_Buffer"));
if (index < 0)
throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
if (count < 0)
throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
if (array.Length - index < count)
throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
Contract.EndContractBlock();
if (_numBytes == Uninitialized)
throw NotInitialized();
uint sizeofT = Marshal.SizeOf();
uint alignedSizeofT = Marshal.AlignedSizeOf();
byte* ptr = (byte*)handle + byteOffset;
SpaceCheck(ptr, checked((ulong)(alignedSizeofT * count)));
bool mustCallRelease = false;
RuntimeHelpers.PrepareConstrainedRegions();
try
{
DangerousAddRef(ref mustCallRelease);
for (int i = 0; i < count; i++)
unsafe { GenericPtrToStructure(ptr + alignedSizeofT * i, out array[i + index], sizeofT); }
}
finally
{
if (mustCallRelease)
DangerousRelease();
}
}
///
/// Write a value type to memory at the given offset. This is
/// equivalent to: *(T*)(bytePtr + byteOffset) = value;
///
/// The type of the value type to write to memory.
/// The location in memory to write to. You
/// may have to consider alignment.
/// The value type to write to memory.
[CLSCompliant(false)]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
public void Write(ulong byteOffset, T value) where T : struct {
if (_numBytes == Uninitialized)
throw NotInitialized();
uint sizeofT = Marshal.SizeOf();
byte* ptr = (byte*)handle + byteOffset;
SpaceCheck(ptr, sizeofT);
// *((T*) (_ptr + byteOffset)) = value;
bool mustCallRelease = false;
RuntimeHelpers.PrepareConstrainedRegions();
try
{
DangerousAddRef(ref mustCallRelease);
GenericStructureToPtr(ref value, ptr, sizeofT);
}
finally
{
if (mustCallRelease)
DangerousRelease();
}
}
[CLSCompliant(false)]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
public void WriteArray(ulong byteOffset, T[] array, int index, int count)
where T : struct
{
if (array == null)
throw new ArgumentNullException("array", Environment.GetResourceString("ArgumentNull_Buffer"));
if (index < 0)
throw new ArgumentOutOfRangeException("index", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
if (count < 0)
throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
if (array.Length - index < count)
throw new ArgumentException(Environment.GetResourceString("Argument_InvalidOffLen"));
Contract.EndContractBlock();
if (_numBytes == Uninitialized)
throw NotInitialized();
uint sizeofT = Marshal.SizeOf();
uint alignedSizeofT = Marshal.AlignedSizeOf();
byte* ptr = (byte*)handle + byteOffset;
SpaceCheck(ptr, checked((ulong)(alignedSizeofT * count)));
bool mustCallRelease = false;
RuntimeHelpers.PrepareConstrainedRegions();
try
{
DangerousAddRef(ref mustCallRelease);
for (int i = 0; i < count; i++)
unsafe { GenericStructureToPtr(ref array[i + index], ptr + alignedSizeofT * i, sizeofT); }
}
finally
{
if (mustCallRelease)
DangerousRelease();
}
}
#endif // !FEATURE_CORECLR
///
/// Returns the number of bytes in the memory region.
///
[CLSCompliant(false)]
public ulong ByteLength {
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
get {
if (_numBytes == Uninitialized)
throw NotInitialized();
return (ulong) _numBytes;
}
}
/* No indexer. The perf would be misleadingly bad. People should use
* AcquirePointer and ReleasePointer instead. */
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
private void SpaceCheck(byte* ptr, ulong sizeInBytes)
{
if ((ulong)_numBytes < sizeInBytes)
NotEnoughRoom();
if ((ulong)(ptr - (byte*) handle) > ((ulong)_numBytes) - sizeInBytes)
NotEnoughRoom();
}
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
private static void NotEnoughRoom()
{
throw new ArgumentException(Environment.GetResourceString("Arg_BufferTooSmall"));
}
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
private static InvalidOperationException NotInitialized()
{
Contract.Assert(false, "Uninitialized SafeBuffer! Someone needs to call Initialize before using this instance!");
return new InvalidOperationException(Environment.GetResourceString("InvalidOperation_MustCallInitialize"));
}
// FCALL limitations mean we can't have generic FCALL methods. However, we can pass
// TypedReferences to FCALL methods.
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
internal static void GenericPtrToStructure(byte* ptr, out T structure, uint sizeofT) where T : struct
{
structure = default(T); // Dummy assignment to silence the compiler
PtrToStructureNative(ptr, __makeref(structure), sizeofT);
}
[MethodImpl(MethodImplOptions.InternalCall)]
[ResourceExposure(ResourceScope.None)]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
private static extern void PtrToStructureNative(byte* ptr, /*out T*/ TypedReference structure, uint sizeofT);
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
internal static void GenericStructureToPtr(ref T structure, byte* ptr, uint sizeofT) where T : struct
{
StructureToPtrNative(__makeref(structure), ptr, sizeofT);
}
[MethodImpl(MethodImplOptions.InternalCall)]
[ResourceExposure(ResourceScope.None)]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
private static extern void StructureToPtrNative(/*ref T*/ TypedReference structure, byte* ptr, uint sizeofT);
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- FlagPanel.cs
- ComponentEditorForm.cs
- IPAddressCollection.cs
- Globals.cs
- EntityModelSchemaGenerator.cs
- Translator.cs
- TraceSection.cs
- WorkflowServiceNamespace.cs
- DataProtection.cs
- FilteredDataSetHelper.cs
- WebPartCancelEventArgs.cs
- control.ime.cs
- PaperSize.cs
- XmlArrayAttribute.cs
- ParseNumbers.cs
- SourceElementsCollection.cs
- SqlDataSourceCache.cs
- DataReceivedEventArgs.cs
- FixedLineResult.cs
- AccessControlEntry.cs
- RowSpanVector.cs
- ButtonDesigner.cs
- PageAdapter.cs
- URLString.cs
- SkipQueryOptionExpression.cs
- ValidatedControlConverter.cs
- GPPOINTF.cs
- TPLETWProvider.cs
- HttpWebRequestElement.cs
- D3DImage.cs
- ReadOnlyCollection.cs
- TriggerCollection.cs
- MessageLoggingFilterTraceRecord.cs
- UnmanagedMemoryStream.cs
- ItemsChangedEventArgs.cs
- PreApplicationStartMethodAttribute.cs
- TableCellCollection.cs
- OrderedDictionary.cs
- SqlDependencyListener.cs
- AsmxEndpointPickerExtension.cs
- ProcessModelInfo.cs
- HttpRuntime.cs
- HttpWrapper.cs
- HttpModuleActionCollection.cs
- CriticalHandle.cs
- GB18030Encoding.cs
- XamlVector3DCollectionSerializer.cs
- XamlStream.cs
- RowUpdatedEventArgs.cs
- CanonicalXml.cs
- WebPageTraceListener.cs
- TriggerCollection.cs
- CheckBoxList.cs
- SchemaElementLookUpTableEnumerator.cs
- EventLogPermission.cs
- ImageListStreamer.cs
- ConstraintManager.cs
- InputMethodStateTypeInfo.cs
- UnsafeNativeMethods.cs
- MachineSettingsSection.cs
- ProviderSettings.cs
- HttpConfigurationSystem.cs
- CreateParams.cs
- storepermission.cs
- PropertyDescriptorGridEntry.cs
- GenericIdentity.cs
- TriState.cs
- NativeMethodsCLR.cs
- UserControl.cs
- XmlAttributeOverrides.cs
- MDIControlStrip.cs
- SpecialTypeDataContract.cs
- View.cs
- SoapCodeExporter.cs
- RegistrySecurity.cs
- RowSpanVector.cs
- DatePickerDateValidationErrorEventArgs.cs
- RowUpdatingEventArgs.cs
- CompilerWrapper.cs
- Config.cs
- MappedMetaModel.cs
- XsltOutput.cs
- WebPartEditorCancelVerb.cs
- PolicyManager.cs
- MatrixAnimationBase.cs
- AssociationSet.cs
- EdmToObjectNamespaceMap.cs
- TableCell.cs
- Propagator.ExtentPlaceholderCreator.cs
- ThaiBuddhistCalendar.cs
- WorkflowRuntimeServiceElement.cs
- TemplateApplicationHelper.cs
- WinEventQueueItem.cs
- EnumerableCollectionView.cs
- ToolStripHighContrastRenderer.cs
- WebControlAdapter.cs
- CommunicationObjectFaultedException.cs
- MetadataArtifactLoaderFile.cs
- Pair.cs
- ObjectDataSourceSelectingEventArgs.cs