views:

417

answers:

5

Could anyone create a short sample that breaks, unless the [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] is applied?

I just ran through this sample on MSDN and am unable to get it to break, even if I comment out the ReliabilityContract attribute. Finally seems to always get called.

A: 

While I don't have a concrete example for you, I think you're missing the point of have a try..finally block inside of the methods that guarantee success. The whole point of saying that the method will always succeed means that regards of what (exception) happens during execution, steps will be taken to ensure the data being accessed will be in a valid state when the method returns. Without the try..finally, you wouldn't be ensuring anything, and could mean that only half of the operations you wanted to happen, would happen. Thus, Cer.Success doesn't actually guarantee success, it only states that you as the developer are guaranteeing success.

Check out this page for an explanation of the differences between Success and MayFail states as it pertains to an Array.CopyTo method: http://weblogs.asp.net/justin_rogers/archive/2004/10/05/238275.aspx

Relster
CER is mainly there to protect hosted CLRs from corrupting state during appdomain teardowns and other exceptional conditions. Hosts such as SQL Server may trigger rude aborts, during rude aborts finally clauses may be interrupted.
Sam Saffron
To be slightly more explicit, CERs are there to ALLOW the developer the CAPABILITY of writing code that can protect itself from corrupting it's own state in exceptional conditions. There is nothing inherent about a CER that protects the CLR, it just makes it possible to write code that can protect itself. The dirty secret is in CLR 1.0/1.1 it was IMPOSSIBLE to write code that could successfully deal with certain classes of exceptions.
Peter Oehlert
A: 

CER attributes are means of documentation. They do influence how CLR will execute code in some situations, but I believe they (or lack of them) will never result in error in current versions of .NET.

They are mostly 'reserved for future use'.

ima
Despite negative votes, lack of examples for this question proves my point. CERs do not affect code flow, including finally block. They document code so framework can treat it differently. Basically, it translates to "I won't raise asynch exceptions, you don't interrupt me with asynch exceptions". Removing CER won't ever break code, though it might make it less reliable, statistically. It is also rather obvious that CERs can be used for much more than what is currently implemented by runtime.
ima
CER attributes are NOT only for documentation; when used from within a constrained execution region a method marked with a ReliabilityContract will be prepared before execution by the JIT to be pre-compiled and the memory for the method will be pre-allocated when entering the PrepareConstrainedRegions.
Peter Oehlert
They ARE documentation. That documentation is read and used by CLR, as I also said - no contradiction here. The point is, "a short sample that breaks, unless the [] is applied" is impossible, nothing breaks without CER attributes. Becomes less reliable - yes, but nothing that can be described as "code breaks".
ima
not impossible, see the top voted answer
Sam Saffron
A: 

Are you running the MSDN sample under the debugger? I do not think it is possible for CER to function when you are executing within the debugger, as the debugger itself changes the nature of execution anyway.

If you build and run the app in optimized release mode, you should be able to see it fail.

jrista
+2  A: 

The primary driver for this functionality was to support SQL Servers stringent requirements for integrating the CLR into SQL Server 2005. Probably so that others could use and likely for legal reasons this deep integration was published as a hosting API but the technical requirements were SQL Servers. Remember that in SQL Server, MTBF is measured in months not hours and the process restarting because an unhandled exception happened is completely unacceptable.

This MSDN Magazine artical is probably the best one that I've seen describing the technical requirements the constrained execution environment was built for.

The ReliabilityContract is used to decorate your methods to indicate how they operate in terms of potentially asynchronous exceptions (ThreadAbortException, OutOfMemoryException, StackOverflowException). A constrained execution region is defined as a catch or finally (or fault) section of a try block which is immediately preceded by a call to System.Runtime.CompilerServices.RuntimeServices.PrepareConstrainedRegions().

System.Runtime.CompilerServices.RuntimeServices.PrepareConstrainedRegions();
try 
{
    // this is not constrained
} 
catch (Exception e) 
{
    // this IS a CER
} 
finally 
{
    // this IS ALSO a CER
}

When a ReliabilityContract method is used from within a CER, there are 2 things that happen to it. The method will be pre-prepared by the JIT so that it won't invoke the JIT compiler the first time it's executed which could try to use memory itself and cause it's own exceptions. Also while inside of a CER the runtime promises not to throw a ThreadAbort exception and will wait to throw the exception until after the CER has completed.

So back to your question; I'm still trying to come up with a simple code sample that will directly answer your question. As you may have already guessed though, the simplest sample is going to require quite a lot of code given the asynchronous nature of the problem and will likely be SQLCLR code because that is the environment which will use CERs for the most benefit.

Peter Oehlert
+4  A: 
using System;
using System.Runtime.CompilerServices;
using System.Runtime.ConstrainedExecution;

class Program {
    static bool cerWorked;

    static void Main( string[] args ) {
        try {
            cerWorked = true;
            MyFn();
        }
        catch( OutOfMemoryException ) {
            Console.WriteLine( cerWorked );
        }
        Console.ReadLine();
    }

    unsafe struct Big {
        public fixed byte Bytes[int.MaxValue];
    }

    //results depends on the existance of this attribute
    [ReliabilityContract( Consistency.WillNotCorruptState, Cer.Success )] 
    unsafe static void StackOverflow() {
        Big big;
        big.Bytes[ int.MaxValue - 1 ] = 1;
    }

    static void MyFn() {
        RuntimeHelpers.PrepareConstrainedRegions();
        try {
            cerWorked = false;
        }
        finally {
            StackOverflow();
        }
    }
}

When MyFn is jitted, it tries to create a ConstrainedRegion from the finally block.

  • In the case without the ReliabilityContract, no proper ConstrainedRegion could be formed, so a regular code is emitted. The stack overflow exception is thrown on the call to Stackoverflow (after the try block is executed).

  • In the case with the ReliabilityContract, a ConstrainedRegion could be formed and the stack requirements of methods in the finally block could be lifted into MyFn. The stack overflow exception is now thrown on the call to MyFn (before the try block is ever executed).

jyoung