-
-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 {
+ ~FinalizerException () {
+ throw new Exception ();
+ }
- ~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");
+ /*
+ * 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];
+ if (depth <= 0) {
+ new FinalizerException ();
+ return;
}
+ MakeException (depth - 1);
+ }
- // Don't run forever
- if(final_count++>10) {
- Environment.Exit(0);
- }
+ public static int Main () {
+ AppDomain.CurrentDomain.UnhandledException += (sender, args) => {
+ Console.WriteLine ("caught");
+ Environment.Exit (0);
+ };
- Console.WriteLine("finalizer thread ID: {0}", (string)Thread.GetData(dataslot));
- throw new SystemException("wibble");
- }
+ MakeException (1024);
- 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));
- }
- return 1;
- }
-}
+ GC.Collect ();
+ GC.WaitForPendingFinalizers ();
+
+ Thread.Sleep (Timeout.Infinite); // infinite wait so we don't race against the unhandled exception callback
+ return 2;
+ }
+}