-
-using System;
-using System.Collections;
+using System;
using System.Threading;
-public class foo {
- public static LocalDataStoreSlot dataslot = Thread.AllocateDataSlot();
- public static int final_count=0;
+public class FinalizerException {
- ~foo() {
- // Demonstrate that this is still the same thread
- string ID=(string)Thread.GetData(dataslot);
- if(ID==null) {
- Console.WriteLine("Set ID: foo");
- Thread.SetData(dataslot, "foo");
- }
+ ~FinalizerException () {
+ throw new Exception ();
+ }
- // Don't run forever
- if(final_count++>10) {
- Environment.Exit(0);
- }
+ static IntPtr aptr;
- Console.WriteLine("finalizer thread ID: {0}", (string)Thread.GetData(dataslot));
- throw new SystemException("wibble");
- }
-
- public static int Main() {
- ArrayList list = new ArrayList ();
- Thread.SetData(dataslot, "ID is wibble");
- Environment.ExitCode = 2;
- while(true) {
- foo instance = new foo();
- list.Add (new WeakReference(instance));
- Thread.Sleep (0);
+ /*
+ * We allocate the exception object deep down the stack so
+ * that it doesn't get pinned.
+ */
+ public static unsafe void MakeException (int depth) {
+ // Avoid tail calls
+ int* values = stackalloc int [20];
+ aptr = new IntPtr (values);
+ if (depth <= 0) {
+ for (int i = 0; i < 10; i++)
+ new FinalizerException ();
+ return;
}
- return 1;
- }
-}
+ MakeException (depth - 1);
+ }
+
+ public static int Main () {
+ AppDomain.CurrentDomain.UnhandledException += (sender, args) => {
+ Console.WriteLine ("caught");
+ Environment.Exit (0);
+ };
+
+ var t = new Thread (delegate () { MakeException (1024); });
+ t.Start ();
+ t.Join ();
+
+ GC.Collect ();
+ GC.WaitForPendingFinalizers ();
+
+ Thread.Sleep (Timeout.Infinite); // infinite wait so we don't race against the unhandled exception callback
+ return 2;
+ }
+}