[runtime] Overwrite stacktrace for exception on re-throw. Fixes #1856.
authorAlexander Kyte <alexmkyte@gmail.com>
Mon, 30 Mar 2015 17:23:59 +0000 (13:23 -0400)
committerAlexander Kyte <alexander.kyte@xamarin.com>
Mon, 6 Apr 2015 17:24:47 +0000 (13:24 -0400)
This fixes a bug where we did not completely mimic .NET's exception handling.

We previously held onto the stacktrace when an exception was thrown if it already had one. This differs from how .NET behaves, which is to always set the stacktrace to the place that it was last thrown.

Ex:

using System;

class C
{
    static Exception e;

    static void Throw ()
    {
        try {
            int.Parse (null);
        } catch (Exception ex) {
            e = ex;
        }
    }

    public static void Main ()
    {
        Throw ();

        try {
            throw e;
        } catch (Exception ex) {
            Console.WriteLine (ex.StackTrace);
        }
    }
}

Would previously output:

  at System.Int32.Parse (System.String s) [0x00000] in <filename unknown>:0
  at C.Throw () [0x00000] in <filename unknown>:0

when

   at C.Main()

is what .NET output. After this commit we output the same stacktrace as .NET.

mono/mini/exceptions-amd64.c
mono/mini/exceptions-arm.c
mono/mini/exceptions-ia64.c
mono/mini/exceptions-mips.c
mono/mini/exceptions-ppc.c
mono/mini/exceptions-s390x.c
mono/mini/exceptions-sparc.c
mono/mini/exceptions-x86.c
mono/tests/Makefile.am
mono/tests/exception18.cs [new file with mode: 0644]

index 6b2fa44a737fc5c00db03e9662830300db32439c..4a12b5fdeb2f320461e227e95065f3e2528c5a89 100644 (file)
@@ -330,8 +330,10 @@ mono_amd64_throw_exception (guint64 dummy1, guint64 dummy2, guint64 dummy3, guin
 
        if (mono_object_isinst (exc, mono_defaults.exception_class)) {
                MonoException *mono_ex = (MonoException*)exc;
-               if (!rethrow)
+               if (!rethrow) {
                        mono_ex->stack_trace = NULL;
+                       mono_ex->trace_ips = NULL;
+               }
        }
 
        /* adjust eip so that it point into the call instruction */
index 2c9e748454e8d57a30fe6fa725542e64e4f01b5a..36f3e75ab827215c1304ad562e37e13b768050f1 100644 (file)
@@ -154,8 +154,10 @@ mono_arm_throw_exception (MonoObject *exc, mgreg_t pc, mgreg_t sp, mgreg_t *int_
 
        if (mono_object_isinst (exc, mono_defaults.exception_class)) {
                MonoException *mono_ex = (MonoException*)exc;
-               if (!rethrow)
+               if (!rethrow) {
                        mono_ex->stack_trace = NULL;
+                       mono_ex->trace_ips = NULL;
+               }
        }
        mono_handle_exception (&ctx, exc);
        mono_restore_context (&ctx);
index b8212c684bd3d47b5c3d5b32ca361319def675ad..b8e1929e8cb951cb6b35672edc1729e9eeb8b224 100644 (file)
@@ -243,8 +243,10 @@ throw_exception (MonoObject *exc, guint64 rethrow)
 
        if (mono_object_isinst (exc, mono_defaults.exception_class)) {
                MonoException *mono_ex = (MonoException*)exc;
-               if (!rethrow)
+               if (!rethrow) {
                        mono_ex->stack_trace = NULL;
+                       mono_ex->trace_ips = NULL;
+               }
        }
 
        res = unw_getcontext (&unw_ctx);
index 8ab97bf5a30068e487b4fd27e97ca02fd8fed0ca..a1720dcb241cae5b004ff40dcc4c34c46cae105b 100644 (file)
@@ -194,8 +194,10 @@ throw_exception (MonoObject *exc, unsigned long eip, unsigned long esp, gboolean
 
        if (mono_object_isinst (exc, mono_defaults.exception_class)) {
                MonoException *mono_ex = (MonoException*)exc;
-               if (!rethrow)
+               if (!rethrow) {
                        mono_ex->stack_trace = NULL;
+                       mono_ex->trace_ips = NULL;
+               }
        }
        mono_handle_exception (&ctx, exc);
 #ifdef DEBUG_EXCEPTIONS
index aa0b3f778cc125981b3faefb3d2fd961c87e42e8..036af00adc19ed3fde3cb08e2f96b7ebb10773dc 100644 (file)
@@ -331,8 +331,10 @@ mono_ppc_throw_exception (MonoObject *exc, unsigned long eip, unsigned long esp,
 
        if (mono_object_isinst (exc, mono_defaults.exception_class)) {
                MonoException *mono_ex = (MonoException*)exc;
-               if (!rethrow)
+               if (!rethrow) {
                        mono_ex->stack_trace = NULL;
+                       mono_ex->trace_ips = NULL;
+               }
        }
        mono_handle_exception (&ctx, exc);
        mono_restore_context (&ctx);
index 9c2cfc932d53a468890e4d7ef0dda901adf41dcd..1555fe0facb316e2b0849da62506d49c62b00569 100644 (file)
@@ -256,8 +256,10 @@ throw_exception (MonoObject *exc, unsigned long ip, unsigned long sp,
        
        if (mono_object_isinst (exc, mono_defaults.exception_class)) {
                MonoException *mono_ex = (MonoException*)exc;
-               if (!rethrow)
+               if (!rethrow) {
                        mono_ex->stack_trace = NULL;
+                       mono_ex->trace_ips = NULL;
+               }
        }
 //     mono_arch_handle_exception (&ctx, exc, FALSE);
        mono_handle_exception (&ctx, exc);
index 3ebe2e7a29c422b5bc72c2a65e1002cd8a1ad235..52a93ac1f13f925b20c3bb1961fe255c2e8071b3 100644 (file)
@@ -180,8 +180,10 @@ throw_exception (MonoObject *exc, gpointer sp, gpointer ip, gboolean rethrow)
 
        if (mono_object_isinst (exc, mono_defaults.exception_class)) {
                MonoException *mono_ex = (MonoException*)exc;
-               if (!rethrow)
+               if (!rethrow) {
                        mono_ex->stack_trace = NULL;
+                       mono_ex->trace_ips = NULL;
+               }
        }
        mono_handle_exception (&ctx, exc);
        restore_context (&ctx);
index bfd42414e0bf535b9080d175f45b1de5d342f569..f79e06cb22605a8a8da555b1df265ce6de6605ea 100644 (file)
@@ -463,8 +463,10 @@ mono_x86_throw_exception (mgreg_t *regs, MonoObject *exc,
 
        if (mono_object_isinst (exc, mono_defaults.exception_class)) {
                MonoException *mono_ex = (MonoException*)exc;
-               if (!rethrow)
+               if (!rethrow) {
                        mono_ex->stack_trace = NULL;
+                       mono_ex->trace_ips = NULL;
+               }
        }
 
        /* adjust eip so that it point into the call instruction */
index 93d105c90706e9ca042a80f2612eb023a2229836..64931531a347c4ca2777077281e2266b3b8b716f 100644 (file)
@@ -90,6 +90,7 @@ BASE_TEST_CS_SRC=             \
        exception15.cs          \
        exception16.cs          \
        exception17.cs          \
+       exception18.cs          \
        typeload-unaligned.cs   \
        struct.cs               \
        valuetype-gettype.cs    \
diff --git a/mono/tests/exception18.cs b/mono/tests/exception18.cs
new file mode 100644 (file)
index 0000000..8f1e492
--- /dev/null
@@ -0,0 +1,48 @@
+using System;
+
+class C
+{
+       static Exception e;
+
+       static void Throw ()
+       {
+               try {
+                       int.Parse (null);
+               } catch (Exception ex) {
+                       e = ex;
+               }
+       }
+
+       static int FrameCount (Exception ex)
+       {
+                       string fullTrace = ex.StackTrace;
+                       string[] frames = fullTrace.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
+                       return frames.Length;
+       }
+
+       public static void Main ()
+       {
+               Throw ();
+
+               try {
+                       throw e;
+               } catch (Exception ex) {
+                       int frames = FrameCount (ex);
+                       if (frames != 1)
+                               throw new Exception (String.Format("Exception carried {0} frames along with it when it should have reported one.", frames));
+               }
+
+               try {
+                       try {
+                               int.Parse (null);
+                       } catch (Exception) {
+                               throw;
+                       }
+               } catch (Exception ex) {
+                       int frames = FrameCount (ex);
+                       if (frames != 4)
+                               throw new Exception (String.Format("Exception carried {0} frames along with it when it should have reported four.", frames));
+               }
+
+       }
+}