Search code examples
c#pinvokehandlecer

using constrained execute regions


I have a Visual Studio 2008 C# .NET 3.5 application that P/Invokes a native method that accepts a file handle as a parameter. Originally, I was just using FileStream.SafeFileHandle.DangerousGetHandle() to get the file handle. But, after turning on FX COP, I got a CA2001 warning about that. So, after a little research I discovered "Constrained execute regions". This is new to me and I haven't seen a whole lot of information about it. I was hoping somebody more experienced could take a look and verify that I've done this correctly.

class MyClass
{
    public static bool Write(string filename)
    {
        using (var fs = new System.IO.FileStream(filename, 
            System.IO.FileMode.Create, 
            System.IO.FileAccess.Write, 
            System.IO.FileShare.None))
        {
            bool got_handle;
            bool result;

            System.Runtime.CompilerServices.RuntimeHelpers.PrepareConstrainedRegions();
            try { }
            finally
            {
                fs.SafeFileHandle.DangerousAddRef(ref got_handle);
                result = NativeMethods.Foo(fs.SafeFileHandle.DangerousGetHandle());
                if (got_handle)
                    fs.SafeFileHandle.DangerousRelease();   
            }

            return result;
        }
    }
}

internal sealed class NativeMethods
{
    [DllImport("mylib.dll",
        EntryPoint = "Foo",
        CallingConvention = CallingConvention.StdCall,
        CharSet = CharSet.Unicode,
        ExactSpelling = true, 
        SetLastError = true)]
    public static extern bool Foo(IntPtr hFile);
}

Thanks, PaulH


Solution

  • You are doing several things here.

    1. Execute code in the finally block to prevent ThreadAbortExceptions while your safe code is executing.

    2. Before the try/finally trick you call PrepareConstrainedRegions which does basically nothing except to check that enough thread stack space is present to be sure that at least some method calls can be made so your safe code is not caught off guard by a StackOverFlowException.

    So yes you code looks as safe as it can get. In the official docu about CERs there is stated that the CLR does recognize this try/finally blocks as well and takes additional measures. From what I have seen there is not much difference except that OutOfMemoryExceptions are also delayed after your CER code has run.

    To be really sure that your code meets your expectations you should create tests for these things.

    • Stack Exhaustion
    • Out Of Memory
    • Thread.Abort

    Writing reliable code is really hard and even most of the BCL classes are not hardened against such things as Joe Duffy explains. Even if your code does not fail the BCL code can. You will not get much added benefit until a major part of the BCL code can cope with these extreme conditions in a well defined manner.

    Yours, Alois Kraus