Merge pull request #3057 from BrzVlad/fix-major-log3
[mono.git] / mcs / class / referencesource / mscorlib / system / runtime / interopservices / criticalhandle.cs
1 // ==++==
2 // 
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 // 
5 // ==--==
6 /*============================================================
7 **
8 ** Class:  CriticalHandle
9 **
10 **
11 ** A specially designed handle wrapper to ensure we never leak
12 ** an OS handle.  The runtime treats this class specially during
13 ** P/Invoke marshaling and finalization.  Users should write
14 ** subclasses of CriticalHandle for each distinct handle type.
15 ** This class is similar to SafeHandle, but lacks the ref counting
16 ** behavior on marshaling that prevents handle recycling errors
17 ** or security holes. This lowers the overhead of using the handle
18 ** considerably, but leaves the onus on the caller to protect
19 ** themselves from any recycling effects.
20 **
21 ** **** NOTE ****
22 **
23 ** Since there are no ref counts tracking handle usage there is
24 ** no thread safety either. Your application must ensure that
25 ** usages of the handle do not cross with attempts to close the
26 ** handle (or tolerate such crossings). Normal GC mechanics will
27 ** prevent finalization until the handle class isn't used any more,
28 ** but explicit Close or Dispose operations may be initiated at any
29 ** time.
30 **
31 ** Similarly, multiple calls to Close or Dispose on different
32 ** threads at the same time may cause the ReleaseHandle method to be
33 ** called more than once.
34 **
35 ** In general (and as might be inferred from the lack of handle
36 ** recycle protection) you should be very cautious about exposing
37 ** CriticalHandle instances directly or indirectly to untrusted users.
38 ** At a minimum you should restrict their ability to queue multiple
39 ** operations against a single handle at the same time or block their
40 ** access to Close and Dispose unless you are very comfortable with the
41 ** semantics of passing an invalid (or possibly invalidated and
42 ** reallocated) to the unamanged routines you marshal your handle to
43 ** (and the effects of closing such a handle while those calls are in
44 ** progress). The runtime cannot protect you from undefined program
45 ** behvior that might result from such scenarios. You have been warned.
46 **
47 ** 
48 ===========================================================*/
49
50 using System;
51 using System.Reflection;
52 using System.Threading;
53 using System.Security.Permissions;
54 using System.Runtime.CompilerServices;
55 using System.Runtime.Versioning;
56 using System.Runtime.ConstrainedExecution;
57 using System.IO;
58
59 /*
60   Problems addressed by the CriticalHandle class:
61   1) Critical finalization - ensure we never leak OS resources in SQL.  Done
62      without running truly arbitrary & unbounded amounts of managed code.
63   2) Reduced graph promotion - during finalization, keep object graph small
64   3) GC.KeepAlive behavior - P/Invoke vs. finalizer thread ---- (HandleRef)
65   4) Enforcement of the above via the type system - Don't use IntPtr anymore.
66
67   Subclasses of CriticalHandle will implement the ReleaseHandle
68   abstract method used to execute any code required to free the
69   handle. This method will be prepared as a constrained execution
70   region at instance construction time (along with all the methods in
71   its statically determinable call graph). This implies that we won't
72   get any inconvenient jit allocation errors or rude thread abort
73   interrupts while releasing the handle but the user must still write
74   careful code to avoid injecting fault paths of their own (see the
75   CER spec for more details). In particular, any sub-methods you call
76   should be decorated with a reliability contract of the appropriate
77   level. In most cases this should be:
78     ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)
79   Also, any P/Invoke methods should use the
80   SuppressUnmanagedCodeSecurity attribute to avoid a runtime security
81   check that can also inject failures (even if the check is guaranteed
82   to pass).
83
84   Subclasses must also implement the IsInvalid property so that the
85   infrastructure can tell when critical finalization is actually required.
86   Again, this method is prepared ahead of time. It's envisioned that direct
87   subclasses of CriticalHandle will provide an IsInvalid implementation that suits
88   the general type of handle they support (null is invalid, -1 is invalid etc.)
89   and then these classes will be further derived for specific handle types.
90
91   Most classes using CriticalHandle should not provide a finalizer.  If they do
92   need to do so (ie, for flushing out file buffers, needing to write some data
93   back into memory, etc), then they can provide a finalizer that will be 
94   guaranteed to run before the CriticalHandle's critical finalizer.
95
96   Subclasses are expected to be written as follows (note that
97   SuppressUnmanagedCodeSecurity should always be used on any P/Invoke methods
98   invoked as part of ReleaseHandle, in order to switch the security check from
99   runtime to jit time and thus remove a possible failure path from the
100   invocation of the method):
101
102   internal sealed MyCriticalHandleSubclass : CriticalHandle {
103       // Called by P/Invoke when returning CriticalHandles
104       private MyCriticalHandleSubclass() : base(IntPtr.Zero)
105       {
106       }
107
108       // Do not provide a finalizer - CriticalHandle's critical finalizer will
109       // call ReleaseHandle for you.
110
111       public override bool IsInvalid {
112           get { return handle == IntPtr.Zero; }
113       }
114
115       [DllImport(Win32Native.KERNEL32), SuppressUnmanagedCodeSecurity, ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
116       private static extern bool CloseHandle(IntPtr handle);
117
118       override protected bool ReleaseHandle()
119       {
120           return CloseHandle(handle);
121       }
122   }
123
124   Then elsewhere to create one of these CriticalHandles, define a method
125   with the following type of signature (CreateFile follows this model).
126   Note that when returning a CriticalHandle like this, P/Invoke will call your
127   classes default constructor.
128
129       [DllImport(Win32Native.KERNEL32)]
130       private static extern MyCriticalHandleSubclass CreateHandle(int someState);
131
132  */
133
134 namespace System.Runtime.InteropServices
135 {
136
137 // This class should not be serializable - it's a handle.  We require unmanaged
138 // code permission to subclass CriticalHandle to prevent people from writing a 
139 // subclass and suddenly being able to run arbitrary native code with the
140 // same signature as CloseHandle.  This is technically a little redundant, but
141 // we'll do this to ensure we've cut off all attack vectors.  Similarly, all
142 // methods have a link demand to ensure untrusted code cannot directly edit
143 // or alter a handle.
144 [System.Security.SecurityCritical]  // auto-generated_required
145 #if !FEATURE_CORECLR
146 [SecurityPermission(SecurityAction.InheritanceDemand, UnmanagedCode=true)]
147 #endif
148 public abstract class CriticalHandle : CriticalFinalizerObject, IDisposable
149 {
150     // ! Do not add or rearrange fields as the EE depends on this layout.
151     //------------------------------------------------------------------
152 #if DEBUG
153     private String _stackTrace; // Where we allocated this CriticalHandle.
154 #endif
155     protected IntPtr handle;    // This must be protected so derived classes can use out params. 
156     private bool _isClosed;     // Set by SetHandleAsInvalid or Close/Dispose/finalization.
157
158     // Creates a CriticalHandle class.  Users must then set the Handle property or allow P/Invoke marshaling to set it implicitly.
159     [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
160     protected CriticalHandle(IntPtr invalidHandleValue)
161     {
162         handle = invalidHandleValue;
163         _isClosed = false;
164
165 #if DEBUG
166         if (BCLDebug.SafeHandleStackTracesEnabled)
167             _stackTrace = Environment.GetStackTrace(null, false);
168         else
169             _stackTrace = "For a stack trace showing who allocated this CriticalHandle, set SafeHandleStackTraces to 1 and rerun your app.";
170 #endif
171     }
172
173 #if FEATURE_CORECLR
174     // Adding an empty default constructor for annotation purposes
175     private CriticalHandle(){} 
176 #endif
177
178     [System.Security.SecuritySafeCritical]  // auto-generated
179     [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
180     ~CriticalHandle()
181     {
182         Dispose(false);
183     }
184
185     [System.Security.SecurityCritical]  // auto-generated
186     [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
187     private void Cleanup()
188     {
189         if (IsClosed)
190             return;
191         _isClosed = true;
192
193         if (IsInvalid)
194             return;
195
196         // Save last error from P/Invoke in case the implementation of
197         // ReleaseHandle trashes it (important because this ReleaseHandle could
198         // occur implicitly as part of unmarshaling another P/Invoke).
199         int lastError = Marshal.GetLastWin32Error();
200
201         if (!ReleaseHandle())
202             FireCustomerDebugProbe();
203
204         Marshal.SetLastWin32Error(lastError);
205
206         GC.SuppressFinalize(this);
207     }
208
209 #if MONO
210     static void FireCustomerDebugProbe()
211     {
212     }
213 #else
214     [ResourceExposure(ResourceScope.None)]
215     [MethodImplAttribute(MethodImplOptions.InternalCall)]
216     [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
217     private extern void FireCustomerDebugProbe();
218 #endif
219
220     [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
221     protected void SetHandle(IntPtr handle) {
222         this.handle = handle;
223     }
224
225     // Returns whether the handle has been explicitly marked as closed
226     // (Close/Dispose) or invalid (SetHandleAsInvalid).
227     public bool IsClosed {
228         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
229         get { return _isClosed; }
230     }
231
232     // Returns whether the handle looks like an invalid value (i.e. matches one
233     // of the handle's designated illegal values). CriticalHandle itself doesn't
234     // know what an invalid handle looks like, so this method is abstract and
235     // must be provided by a derived type.
236     public abstract bool IsInvalid {
237         [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
238         get;
239     }
240
241     [System.Security.SecurityCritical]  // auto-generated
242     [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
243     public void Close() {
244         Dispose(true);
245     }
246     
247     [System.Security.SecuritySafeCritical]  // auto-generated
248     [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
249     public void Dispose()
250     {
251         Dispose(true);
252     }
253
254     [System.Security.SecurityCritical]  // auto-generated
255     [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
256     protected virtual void Dispose(bool disposing)
257     {
258         Cleanup();
259     }
260
261     // This should only be called for cases when you know for a fact that
262     // your handle is invalid and you want to record that information.
263     // An example is calling a syscall and getting back ERROR_INVALID_HANDLE.
264     // This method will normally leak handles!
265     [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
266     public void SetHandleAsInvalid()
267     {
268         _isClosed = true;
269         GC.SuppressFinalize(this);
270     }
271
272     // Implement this abstract method in your derived class to specify how to
273     // free the handle. Be careful not write any code that's subject to faults
274     // in this method (the runtime will prepare the infrastructure for you so
275     // that no jit allocations etc. will occur, but don't allocate memory unless
276     // you can deal with the failure and still free the handle).
277     // The boolean returned should be true for success and false if a
278     // catastrophic error occured and you wish to trigger a diagnostic for
279     // debugging purposes (the SafeHandleCriticalFailure MDA).
280     [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
281     protected abstract bool ReleaseHandle();
282 }
283
284 }