Interesting re-entrant tracing behaviour in .NET 2

Dan alerted me to some interesting re-entrant behaviour he was seeing in an application ported from .NET framework 1.1 to .NET 2. I did some digging and was able to write this fairly innocent looking program:

using System;
using System.Diagnostics;

namespace TraceListenerTest
{
    class Program
    {
        static void Main(string[] args)
        {
            //Trace.Listeners.Add(new TestListener());
            Trace.Write(“this is a test”);
            Console.ReadLine();
        }
    }

    class TestListener : TraceListener
    {
        public TestListener()
        {
            TraceListenerCollection l = Trace.Listeners;
        }

        public override void Write(string message)
        {
            Console.Write(message);
        }

        public override void WriteLine(string message)
        {
            Console.WriteLine(message);
        }
    }
}

If you add this trace listener programatically (for instance by commenting out the first line of the “Main” method) everything works as expected, however if you add the trace listener via a configuration file you get a stack overflow in the TestListener constructor. Exciting, and certainly not the way things worked in .NET 1.1.