Saturday, August 06, 2005

I got to work on a fun DCR with Chris Brumme back around the time we were shipping Whidbey Beta2. (DCR means Design Change Request, essentially an unplanned change to the design of a component.) We went back and forth as to whether or not to release it with Beta2, but given that the implementation would have been right up against our lock down period, the risk was too high. Thus, it'll first appear in our next CTP, RC, or whatever release comes out before Whidbey RTMs.

The Problem

The crux of the problem is this. Lots of code gets written in C# assuming that catch (Exception) is sufficient to backstop any exception a piece of CLR software can generate. It turns out that, while doing so is not CLS compliant, IL can throw just about anything. The throw instruction will happily take a reference on the stack to any managed object--not just those whose type falls into the Exception type hierarchy--and unwind the stack with it in hand.

A typical user (and even some Framework developers) write exception handling code that looks like this (without all the Console.WriteLines of course :P):

try
{
    Console.WriteLine("Inside try...");
    F();
    Console.WriteLine("Exiting try");
}
catch (Exception e)
{
    Console.WriteLine("In catch ({0})", e);
}

Console.WriteLine("Outside try...exiting gracefully");

Now, this will work perfectly fine if F did as follows:

static void F()
{
    // foo...
    throw new InvalidOperationException();
    // bar...
}

InvalidOperationException derives from Exception, so the catch block picks it up. But what if F did this?

static void F()
{
    // foo...
    throw 0;
    // bar...
}

Well, thankfully you can't write that in C#. But you can in verifiable IL:

.method private hidebysig static void  F() cil managed
{
    .maxstack  1
    .locals init (int32 V_0)
    ldc.i4.0
    box [mscorlib]System.Int32
    throw
}

The specific type, int in this case, really doesn't matter. It could be any other reference type that doesn't somehow derive from Exception, a value type, or even a null reference!

You might turn your nose up at the idea of catching all exceptions. I did. But consider if you need to roll back sensitive state that was introduced inside the try block. I've already covered why doing this in the finally block only might not be sufficient. If F() were a virtual method that a user could override and somehow supply an object of their choosing, a malicious user could use this (along with an exception filter) to mount a nasty security attack. Coming from a Java background, I was initially very surprised how real this problem is...The world becomes much more complex when you interop so tightly with the OS. For example, the CLR has to work well with SEH primarily for situations where mixed call stacks make unmanaged-to-managed (and vice versa) transitions. Suffice it to say that the two pass model introduces lots of complexities.

The Solution

Many people think that this is inherently a C# problem. Isn't it C#, not the runtime, that forces people to think in terms of Exception-derived exception hierarchies? Certainly there is precedent that indicates throwing arbitrary objects is a fine thing for a language to do. Just take a look at C++ and Python. And furthermore, C# actually enables you to fix this problem:

try
{
    F();
}
catch
{
    // ...
}

This approach has two problems. First, the catch-all handler doesn't expose to the programmer the exception that was thrown. C# could have changed this (e.g. with TLS data exposed through a static member, e.g. Exception.GetLastThrown, or something like that). That still wouldn't solve the problem that things that aren't exceptions don't accumulate a stack trace as they pass through the stack, making them nearly impossible to debug. But probably worse, the average programmer doesn't even know this is a problem! Including those who are writing code for the Frameworks that Microsoft ships. But they really shouldn't have to know. This problem spans many languages, and it really made sense for the runtime to help them out.

We solved the problem by introducing some new behavior inside the exception subsystem of the CLR. It's mostly transparent to the user. When something gets thrown that is not derived from Exception, we instantiate a new System.Runtime.CompilerServices.RuntimeWrappedException, supply the originally thrown object as an instance field of that puppy, and propagate that instead. It's public; most people will never catch such things directly, but you can if you need to access the thing that got thrown in the first place.

This has some nice benefits. The C# user can continue writing catch (Exception), and--since RuntimeWrappedException derives from Exception--will receive any non-CLS exceptions. The try/catch block we had originally written will just work for free now. And furthermore, we now capture stack trace for everything, meaning that debugging and crash dumps are immediately much more useful. Lastly, there's still a playground for languages that wish to continue participating in throwing exceptions not derived from Exception.

Supporting Naughty Languages

This last point actually complicates the design quite a bit. We queried our language community, and perhaps not-so-surprisingly, there are a lot of compilers that can throw anything. C++/CLI is one of them. So we had to preserve the existing semantics for those languages, while still enabling C# users to get the benefits of this change. Thus was born System.Runtime.CompilerServices.RuntimeCompatibilityAttribute. The C# and VB compilers will auto-decorate any compiled assemblies with this attribute, setting its property WrapNonClsExceptions to true. The runtime keys off of that to determine whether the old or new behavior is desired. The default is that we don't surface the aforementioned wrapping behavior (although as an implementation detail, we still do it). We expect more of these compatibility-preserving changes in the future, which resulted in the somewhat generic attribute naming.

If the attribute is absent, or present and WrapNonClsExceptions is set to false, we still actually wrap the exception internally so we can (1) maintain good stack traces for debugging and (2) to cleanup and optimize some of the exception code paths that had to branch based on the type of the exception. But we unwrap it as we match it against catch handlers. And we unwrap it when we deliver it to catch filters. So these languages don't know anything ever changed.

It's actually gets a bit more complicated than this, however. For cross-language call stacks, we actually do the unwrapping based on whatever the assembly in which the catch clause's assembly wants to do. Say method M in C++/CLI assembly A throws an int; this is called by method N in C# assembly B. At throw time, we construct a new RuntimeWrappedException and use that for propagation. If assembly A catches it, all it sees is the int...It never knows we wrapped it. But if it leaks, and assembly B had wrapped the call in M with a catch (Exception), that handler will actually see a RuntimeWrappedException. Furthermore, consider if there were another C++/CLI assembly C; if N didn't catch the leaked int, it would surface in C as if it never got wrapped. This is what users expect to happen, and it composes very nicely.

Most users won't even know about this change. But hopefully their code gets more secure and robust for free.

8/6/2005 10:55:26 AM (Pacific Daylight Time, UTC-07:00)  #   

 Friday, July 22, 2005

The CLR was designed to work very well in a COM world. This design choice is not at all surprising given the history of programming on Windows, and that the CLR began life as the COM+ 2.0 Runtime (among other temporary names). When it comes to concurrency in this world, however, there's a whole host of crap that can go wrong. Thankfully most of the time it doesn't.

Before moving on, if you have a finite amount of time, I'd recommend reading Chris Brumme's weblog on Apartments and Pumping. It's exponentially more worth your time than this post. I'm going to assume you have been introduced to at least a few of the concepts there. Most mortals on this planet haven't. You'll also want to come to my Programming w/ Concurrency talk at PDC, where I'll discuss such "to the metal" details.

OK. I've hyped it up. But I don't really have that much to say.

Using monitors for critical sections

When somebody accesses a shared piece of memory from multiple units of parallel execution, some form of locking is usually necessary. For a very small class of programmers, avoiding locks and retaining correctness is possible, but it's rocket science. Most people give up quickly if they even think to try in the first place (except for double checked locking, which is often copied from some book or website on the topic). If it's a simple primitive operation, interlocked operations might work. But in other cases, you need a coarser grained critical section-ish lock. For manager programmers, this is Monitor (i.e. 'lock' keyword in C#).

A class that has a private shared static variable, for example, would lock on it before mutating its contents. Imagine we have a class Coords:

class Coords
{
    public int x;
    public int y;
}

Our program decides it needs to maintain the invariant that x == y (don't ask why), and here's the code a developer might write:

class MyComponent : ServicedComponent
{
    private static Coords c = new Coords();
    void DoWork()
    {
        lock (myCoords)
        {
            myCoords.x++;
            DoMoreWork();
            myCoords.y++;
        }
    }
    void DoMoreWork() { /* code that tolerates broken invariants */ }
}

So long as we never leak the myCoords instance (raising the risk somebody accesses it w/out locking), we're safe. Right?

Not quite.

Enter STA

You might not have noticed that MyComponent derives from ServicedComponent. This is a ContextBoundObject that lives by all of the standard COM component rules. If it's instantiated inside an STA (Single Threaded Apartment), all access is serialized, as is the case with ordinary COM components. Now, this might seem a tad esoteric, but consider if you have a class that's called by a user who wrote their own ServicedComponent. It might seem more real, and is equally as problematic.

Chris's article above talks at great length about message pumping. STAs have to pump messages, otherwise queued messages could get starved. For UI applications, this pisses users off. For other applications, it can lead to fairness issues at best and incorrect code at worst. We pump for you so you don't need to worry about it, but we might do it in places you might not expect. This ends up being nearly anywhere you can block.

Let's pretend DoMoreWork above did this:

void DoMoreWork()
{
    Thread.CurrentThread.Join(0);
}

Join waits for the target thread to complete execution or the timeout to expire, whichever comes first. Since we call it on our own thread, it should be clear which occurs first. (You are still awake, right?)

When you pump, code can reenter on top of your existing stack. Let's look at the entire snippet of code:

[ComVisible(true)]
public class MyComponent : ServicedComponent
{
    private static Coords c = new Coords();

    public void DoWork(int n)
    {
        Console.WriteLine("{0}->", n);

        lock (c)
        {
            // Check invariant x==y upon entry
            int x = c.x, y = c.y;
            Console.WriteLine("{0}:{1},{2}", n, x, y);
            Debug.Assert(x == y,
                string.Format("Broken invariant on entry (#{0}, {1}!={2})", n, x, y));

            c.x++;
            DoMoreWork();
            c.y++;

            // Ensure invariant x==y upon exit
            x = c.x; y = c.y;
            Debug.Assert(x == y,
                string.Format("Broken invariant on exit (#{0}, {1}!={2})", n, x, y));
        }

        Console.WriteLine("{0}<-", n);
    }

    private void DoMoreWork()
    {
        Thread.CurrentThread.Join(0);
    }
}

Recap: The call to DoMoreWork from the DoWork function occurs while invariants are broken. And DoMoreWork (or a function that DoMoreWork calls, e.g. some opaque inside the Framework) pumps. This is a recipe for bad things.

I also added some Console.WriteLines and Debug.Asserts in there so you can watch the world fall down.

Breaking monitors with reentrancy

The situation we need to get into in order to show off this neat parlor trick is as follows:

  • A bunch of MyComponents are created inside an STA server;
  • We try to make a load of calls to DoWork on those components from an MTA client;
  • This requires that the MTA code reenter the STA to execute;
  • Our STA thread pumps while invariants are broken, thus reentering another set of work (and enabling it to see us in an inconsistent state).

It's not quite as difficult as it sounds, thanks to the CLR's accomodating interaction with the world of COM.

class Program
{
    const int threadCount = 5;

    [STAThread]
    static void Main()
    {
        // Create our components in our STA server (note the STAThread on Main)
        MyComponent[] components = new MyComponent[threadCount];
        for (int i = 0; i < threadCount; i++)
            components[i] = new MyComponent();

        // Instantiate a bunch of MTA threads to work on the STA component
        List<Thread> threads = new List<Thread>(threadCount);
        for (int i = 0; i < threadCount; i++)
        {
            int v = i;
            Thread t = new Thread(delegate () { components[v].DoWork(v); });
            t.SetApartmentState(ApartmentState.MTA); // default--here for illustration
            threads.Add(t);
        }

        // Let 'em loose
        threads.ForEach(delegate (Thread t) { t.Start(); });

        // If you haven't Aborted by now, wait for completion
        threads.ForEach(delegate (Thread t) { t.Join(); });
    }
}

This glob of code does exactly what my bullets indicate. The whole thing can be downloaded here. Note: ensure you compile this with the DEBUG symbol defined, otherwise your calls to Debug.Assert won't be present and you won't get the desired effect of being bombarded with assert dialogs.

It's quite nice that the CLR goes out of its way to marshal across contexts, moving our code over from the MTA to the thread in the STA, executing it, and marshaling back. And furthermore, the pumping it is doing is in good faith. It's trying to make our application responsive and fair.

Unfortunately, I see the following output when I run the code:

Constructing components in a STA server...
Instantiating 5 MTA threads to operate on our components...
Starting up MTA threads...
Waiting for MTA completion...
3->
3:0,0
3<-
2->
2:1,1
2<-
1->
1:2,2
0->
0:3,2
4->
4:4,2
4<-
0<-
1<-

Notice the "3,2" line. That prints out "x,y"... and does so at a point in the program where they should always be equal. Unfortunately, we've got reentrant code inside our lock, and it now has access to broken invariants! Your mileage may vary based on the inherent race condition. To be fair, this is also a byproduct of our decision to make monitors reentrant. But this decision was made for recursion, not reentrancy. It turns out we don't recognize the difference.

Of course, the above example doesn't demonstrate anything too terrible. But if you happened to apply some sensitive thread wide state that you intended to roll back before enabling other code to run, for example, it means you absolutely want to avoid pumping inside a critical section. That means mostly avoiding opaque method calls, even if you suspect they don't pump. In the future, they could. In practice, this is tough to acheive. And in practice, it usually doesn't matter.

7/22/2005 4:42:37 PM (Pacific Daylight Time, UTC-07:00)  #   

I made a pretty simple mistake just now. I knew the source of the problem immediately when I saw the exception, but it's fairly interesting.

What's wrong with this code?

MyComponent[] myComponents = Create25Components();
for (int i = 0; i < 25; i++) {
    Thread t = new Thread(delegate () {
        // do some stuff
        myComponent[i].DoWork();
        // do some more stuff
    });
    t.Start();
}

Oops! you say? Oops! for sure.

The reference to the induction variable i gets treated like an ordinary variable C# captures inside an anonymous delegate closure. Namely that it just gets captured into a closure class which each thread shares access to. Access to i inside the thread simply dereferences the shared memory location to obtain the value during execution... not when you capture it. So assuming the parent thread is able to spin through the loop quickly, all of your threads will probably see the final result of i, which is 25. It turns out 25 is an invalid index for the array, resulting in an IndexOutOfRangeException or two. If they get a chance to run quickly, they will see some number in between, but probably not the correct one!

One (of many) solutions is to write this instead:

MyComponent[] myComponents = Create25Components();
for (int i = 0; i < 25; i++) {
    MyComponent mc = myComponents[i];
    Thread t = new Thread(delegate () {
        // do some stuff
        mc.DoWork();
        // do some more stuff
    });
    t.Start();
}

Easy mistake.

7/22/2005 3:30:12 PM (Pacific Daylight Time, UTC-07:00)  #   

 Thursday, July 21, 2005

It seems JScript was a bit ahead of its time, in much the same sense that Lisp was. More accurately ECMAScript was, the standard on which Microsoft's implementation was based.

In 3 lines of code, here is a REPL that compiles and works. It is written in JScript.NET itself (jsc.exe):

import System;
while (true)
    print(eval(Console.ReadLine()));

A more robust version can be written in roughly 50 lines of code:

import System;
import System.Text;

function read()
{
    var program = new StringBuilder();

    while (true)
    {
        Console.Write("{0}{0} ", program.Length == 0 ? ">" : ".");
        var line = Console.ReadLine();
        if (line != "")
        {
            if (program.Length == 0 && line.StartsWith("!q"))
                break;
            else
                program.AppendLine(line);
        }
        else if (program.Length != 0)
        {
            break;
        }
    }

    return program.ToString();
}

function evalprint(program)
{
    try
    {
        var o = eval(program);
        Console.WriteLine("=> {0}", o);
    }
    catch (e)
    {
        Console.ForegroundColor = ConsoleColor.Red;
        Console.Error.WriteLine(e.ToString());
        Console.ResetColor();
    }
}

while (true)
{
    var program = read();
    if (program == "") break;
    evalprint(program);
}

It's just a matter of time before C# and the world at large embrace the power of eval().

7/21/2005 12:26:40 AM (Pacific Daylight Time, UTC-07:00)  #   

 Sunday, July 17, 2005

Note to self: if you happen to write code that AVs the FJIT in Rotor, this prevents you from building the FX tree. I honestly don't quite know why the runtime is loaded there and what managed code executes, but according to Jan Kotas, a dev on the CLR team, it is. And furthermore, the debugging experience kind of sucked... the build log had no errors in it, but binplace failed to find the output DLL when it tried to copy. Sure enough it didn't get built. I'm pasting the error for folks searching in the future:

Binplacing - objd\rotor_x86\system.xml.dll for all platforms
binplace : warning BNP0000: CopyFile(C:\dev\play\sscli-1.0__STM\fx\src\xml\objd\rotor_x86\System.Xml.dll,C:\dev\play\sscli-1.0__STM\build\v1.x86chk.rotor\.\System.Xml.dll) failed 2
binplace : error BNP0000: Unable to place file objd\rotor_x86\System.Xml.dll - exiting.

It killed at least 1 hour of my time tracking it down. Running a quick test under the devenv debugger:

C:\dev\play\sscli-1.0__STM\tests\il_bvt\base\objd>devenv /debugexe %TARGETCOMPLUS%\clix.exe ceq.exe

Did the trick. Stupid bug, easily fixed, and now I'm back building the tree again. Hoorah.

7/17/2005 10:39:27 PM (Pacific Daylight Time, UTC-07:00)  #   

I've spent a bit of time this weekend on my concurrency talk for PDC. It's taking me longer than expected, mostly because I'm writing "a story" up front... before I even think about touching PPT or writing code. The end result will be a great story to tell captured in a paper and--so that I have a convenient way to guide me through the talk--a slide deck. Too many people use PPT as a crutch for presentations, and most of the time it shows.

The talk's focus is on the hows and whys of concurrency with a good mix of the realities of the Windows platform thrown in. This necessarily involves some mechanics (e.g. best practices with explicit threading and the ThreadPool, synchronization, locks, lock-free programming), but also a detailed look inside our platform's legacy, how and why we got here, why some of our legacy still affects how we write concurrent code (anti-concurrency), and where we're headed.

If you're interested in reading up on this stuff, I'd recommend any of the following books. It just so happens that they're all sitting in front of me and being used as references:

Another great related resource that you might want to check out is an article Vance Morisson wrote for August's MSDN magazine. Vance is one of the most senior guys on the team, and is the architect for the CLR's JIT. Bottom line: one of the smartest guys I've ever met.

7/17/2005 7:41:31 PM (Pacific Daylight Time, UTC-07:00)  #   

 Thursday, July 14, 2005

As I'm sure you've heard, the PDC talk abstracts just went live.

Jan Gray and I are doing a two part series on Concurrency. His talk (Part I) focuses on the philosophy, hardware, and primitives. I jump up a notch (in Part II) to look at how the Windows platform exposes concurrency, and some of the abstractions we ship to help you take advantage of it:

Programming with Concurrency (Part II)—Multithreaded Programming with Shared Memory
In this session, see hands-on examples illustrating how best to achieve parallelism safely using multithreaded techniques on Longhorn and the Common Language Runtime (CLR). We walk through some common scenarios, APIs, best practices and pitfalls, and take an in-depth look at both managed and native technologies such as threading on the CLR, Windows threads, and OpenMP. To protect your code from concurrency hazards, we discuss how Longhorn and CLR can help you handle deadlocks and other hangs as well as shared memory exhaustion. We touch on more advanced topics such as CLR explicit threading and the thread pool and asynchronous programming. Legacy issues that impact concurrent programming today such as COM and UI apartment threading and thread affinity are considered. You can expect to walk away from this session with the knowledge necessary to get started on writing efficient and reliable concurrent programs.
Session Level(s): 400
Track(s): Fundamentals

I'm also co-presenting with Mr. Pobar in a talk every compiler geek would love... (and anybody who wants to see an Aussie and a Bostonian duke it out on stage over my assertion that Lisp is the one and only truth in the world (don't worry, I'm just an academic ;) )...)

CLR: Writing a Managed Script Compiler in One Hour
Learn about writing a scripting language compiler that targets Intermediate Language in a single session. Coverage of key decision/choice points when compiling a language on the Common Language Runtime (CLR) are discussed, including the decision to statically or dynamically type and the impacts this has on your design. Includes coverage of writing a late-binder, showing that everything really can be typeless in your source language. Demonstration uses a strawman scripting language as the base language.
Track(s): Tools & Languages

Are you going to PDC? Either one of these talks interest you?

7/14/2005 11:37:58 PM (Pacific Daylight Time, UTC-07:00)  #   

 Sunday, July 10, 2005

I'm wrapping up a chapter in my book on Unmanaged Interop this evening. In the process, I've fallen back in love with some classics on my bookshelf:

COM is still cool in my book. (Pun not intended.)

And furthermore, I can't tell you what a blessing it is to be able to write about a topic, encounter a question or two, and walk right down the hall to the guy's office who 1) knows the absolute most about a specific technology and 2) is kind enough to answer questions in exceeding detail. I hope this translates into a better end product.

Here are just a few (externally available) amazing resources related to hosting, CERs, and SafeHandles, the new face of Unmanaged Interop for V2.0:

7/10/2005 10:04:34 PM (Pacific Daylight Time, UTC-07:00)  #   

The Designing .NET Framework Class Libraries series that aired on MSDN a while back was good fun. The format was fun for us here at Microsoft (video on Friday, chat on the following Wednesday). I hope those who participated agreed. If not, I'd love to get your feedback: what did you like, what didn't you like about the format? Should we do precisely the same way if we do that type of thing in the future... make a couple tweaks?

Here's a cross index to each of the talks with associated chat transcripts:

  1. Setting the Stage
  2. Naming Conventions
  3. Rich Type System
  4. Member Types
  5. Designing Inheritence Hierarchies
  6. API Usability
  7. Designing Progressive APIs
  8. CLR Performance Tips**
  9. Designing for a Managed Memory World**
  10. Understanding Interoperability**
  11. Packaging, Assemblies, and Namespaces
  12. FxCop in Depth
  13. Enabling Development Tools**
  14. Security**
  15. Q&A**

We had a great viewing count (I don't have the #s off hand), comparable to some of the more popular MSDN articles and downloads.

Unfortunately, a few chat transcripts are still missing from the home page. I apolgoize for this, it's in part my fault. The good news: I've been assured they'll be up this week.

In the interim, this cross index should suffice. Those marked with ** are currently missing their chat transcripts. The videos for all are available from the Talk Homepage links. Enjoy!

7/10/2005 6:14:14 PM (Pacific Daylight Time, UTC-07:00)  #   

 Friday, July 08, 2005

Brad just pointed out the recent DotNetRocks episode with the PDC planning folks. They give a good insight into the insanity that goes behind planning such a huge event. I'm helping to organize the CLR Team's presence there, but my part is minimal compared to some guys (like the folks in the interview).

I'm really psyched about PDC this year. We've got a plethora of great talks lined up, and some of the best technical speakers you'll find this side of tha' Missisippi. Just take a look at the talks we've release thus far...

And they have an RSS feed so you can keep an eye on the talks as they are released!

If you haven't convinced your boss to pay yet, better work harder (and faster).

The fun begins 2 months from this weekend!

7/8/2005 10:11:42 PM (Pacific Daylight Time, UTC-07:00)  #   

 

RSS 2.0

Me
 

Joe Send mail to the author(s) is an architect and developer on a systems incubation project at Microsoft.

Recent

Search

Browse

Disclaimer:
The content of this site are my own personal opinions and do not represent my employer's view in anyway.

© 2013, Joe Duffy