[Mono-list] patch for mono/jit/exception.c

Linus Upson linus@linus.com
Sat, 4 May 2002 22:48:01 -0700


This is a multi-part message in MIME format.

------=_NextPart_000_0019_01C1F3BD.BEDB82F0
Content-Type: text/plain;
	charset="us-ascii"
Content-Transfer-Encoding: 7bit

Attached is a test class mcs/class/corlib/Test/System/ExceptionTest.cs
which implements an NUnit test case for the exception described
previously. Also attached is the corresponding patch for
System/AllTests.cs. The ExceptionTest class only tests for this one
issue and so isn't a very good test of the Exception class as a whole. I
don't know if you want to include stub tests like this or not.

Linus


-----Original Message-----
From: mono-list-admin@ximian.com [mailto:mono-list-admin@ximian.com] On
Behalf Of Linus Upson
Sent: Saturday, May 04, 2002 2:39 PM
To: mono-list@ximian.com
Subject: RE: [Mono-list] patch for mono/jit/exception.c


I forgot to include the small test program which demonstrates the
problem:

using System;

public class TryTest {
	public static void ThrowException() {
		throw new Exception();
	}

	public static void Main() {
		ThrowException();

		// If the following line is uncommented, mono will work
right.
		// Console.WriteLine("This shouldn't matter");

		try {
			Console.WriteLine("In try block");
		} catch (Exception e) {
			Console.WriteLine("------------------------");
			Console.WriteLine(e);
			Console.WriteLine("------------------------");
		}
	}
}

Before the patch, the Exception thrown in ThrowException() would be
caught by the catch block in Main().

Linus


-----Original Message-----
From: mono-list-admin@ximian.com [mailto:mono-list-admin@ximian.com] On
Behalf Of Linus Upson
Sent: Saturday, May 04, 2002 2:09 PM
To: mono-list@ximian.com
Subject: [Mono-list] patch for mono/jit/exception.c


Running NUnitConsole_mono.exe in mono on Windows exposed the following
bug:

If an exception were throw by the instruction immediately preceding a
try block, the exception would be considered to be thrown inside the try
block.

A patch is attached which appears to solve the problem. The patch won't
work if arch_handle_exception() can be called with ctx->SC_EIP pointing
to the instruction which threw the exception. I think an exception can
only be thrown by a CALL (as far as managed code is concerned) so EIP
will always point to the instruction after the CALL. If this isn't the
case, a different fix will be needed.

I believe the same problem exists on Linux as well, but I haven't
tested. 

Cheers,
Linus


_______________________________________________
Mono-list maillist  -  Mono-list@ximian.com
http://lists.ximian.com/mailman/listinfo/mono-list

------=_NextPart_000_0019_01C1F3BD.BEDB82F0
Content-Type: text/plain;
	name="ExceptionTest.cs"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
	filename="ExceptionTest.cs"

//
// ExceptionTest.cs - NUnit Test Cases for the System.Exception class
//=20
// Linus Upson (linus@linus.com)
//

using System;
using NUnit.Framework;

namespace MonoTests.System
{
	public class ExceptionTest : TestCase
	{
		public ExceptionTest() : base ("MonoTests.System.ExceptionTest =
testsuite") {}
		public ExceptionTest(string name) : base(name) {}
	=09
		public static ITest Suite {
			get {
				return new TestSuite(typeof(ExceptionTest));
			}
		}
	=09
		// This test makes sure that exceptions thrown on block boundaries are
		// handled in the correct block. The meaning of the 'caught' variable =
is
		// a little confusing since there are two catchers: the method being
		// tested the the method calling the test. There is probably a better
		// name, but I can't think of it right now.
	=09
		public void TestThrowOnBlockBoundaries()
		{
			bool caught;
		=09
			try {
				caught =3D false;
				ThrowBeforeTry();
			} catch {
				caught =3D true;
			}
			Assert("Exceptions thrown before try blocks should not be caught", =
caught);
		=09
			try {
				caught =3D false;
				ThrowAtBeginOfTry();
			} catch {
				caught =3D true;
			}
			Assert("Exceptions thrown at begin of try blocks should be caught", =
!caught);

			try {
				caught =3D false;
				ThrowAtEndOfTry();
			} catch {
				caught =3D true;
			}
			Assert("Exceptions thrown at end of try blocks should be caught", =
!caught);

			try {
				caught =3D false;
				ThrowAtBeginOfCatch();
			} catch {
				caught =3D true;
			}
			Assert("Exceptions thrown at begin of catch blocks should not be =
caught", caught);

			try {
				caught =3D false;
				ThrowAtEndOfCatch();
			} catch {
				caught =3D true;
			}
			Assert("Exceptions thrown at end of catch blocks should not be =
caught", caught);

			try {
				caught =3D false;
				ThrowAtBeginOfFinally();
			} catch {
				caught =3D true;
			}
			Assert("Exceptions thrown at begin of finally blocks should not be =
caught", caught);

			try {
				caught =3D false;
				ThrowAtEndOfFinally();
			} catch {
				caught =3D true;
			}
			Assert("Exceptions thrown at end of finally blocks should not be =
caught", caught);

			try {
				caught =3D false;
				ThrowAfterFinally();
			} catch {
				caught =3D true;
			}
			Assert("Exceptions thrown after finally blocks should not be caught", =
caught);
		}
	=09
		private static void DoNothing()
		{
		}

		private static void ThrowException()
		{
			throw new Exception();
		}
	=09
		private static void ThrowBeforeTry()
		{
			ThrowException();
			try {
				DoNothing();
			} catch (Exception) {
				DoNothing();
			}
		}

		private static void ThrowAtBeginOfTry()
		{
			DoNothing();
			try {
				ThrowException();
				DoNothing();
			} catch (Exception) {
				DoNothing();
			}
		}

		private static void ThrowAtEndOfTry()
		{
			DoNothing();
			try {
				DoNothing();
				ThrowException();
			} catch (Exception) {
				DoNothing();
			}
		}

		private static void ThrowAtBeginOfCatch()
		{
			DoNothing();
			try {
				DoNothing();
				ThrowException();
			} catch (Exception) {
				throw;
			}
		}

		private static void ThrowAtEndOfCatch()
		{
			DoNothing();
			try {
				DoNothing();
				ThrowException();
			} catch (Exception) {
				DoNothing();
				throw;
			}
		}

		private static void ThrowAtBeginOfFinally()
		{
			DoNothing();
			try {
				DoNothing();
				ThrowException();
			} catch (Exception) {
				DoNothing();
			} finally {
				ThrowException();
				DoNothing();
			}
		}

		private static void ThrowAtEndOfFinally()
		{
			DoNothing();
			try {
				DoNothing();
				ThrowException();
			} catch (Exception) {
				DoNothing();
			} finally {
				DoNothing();
				ThrowException();
			}
		}

		private static void ThrowAfterFinally()
		{
			DoNothing();
			try {
				DoNothing();
				ThrowException();
			} catch (Exception) {
				DoNothing();
			} finally {
				DoNothing();
			}
			ThrowException();
		}
	}
}

------=_NextPart_000_0019_01C1F3BD.BEDB82F0
Content-Type: application/octet-stream;
	name="System.AllTests.patch"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
	filename="System.AllTests.patch"

Index: class/corlib/Test/System/AllTests.cs=0A=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0A=
RCS file: /mono/mcs/class/corlib/Test/System/AllTests.cs,v=0A=
retrieving revision 1.20=0A=
diff -u -r1.20 AllTests.cs=0A=
--- class/corlib/Test/System/AllTests.cs	30 Apr 2002 19:19:04 -0000	1.20=0A=
+++ class/corlib/Test/System/AllTests.cs	5 May 2002 05:38:49 -0000=0A=
@@ -49,6 +49,7 @@=0A=
                                 suite.AddTest (UInt64Test.Suite);=0A=
 				suite.AddTest (VersionTest.Suite);=0A=
 				suite.AddTest (MulticastDelegateTest.Suite);=0A=
+				suite.AddTest (ExceptionTest.Suite);=0A=
 				return suite;=0A=
                         }=0A=
                 }=0A=

------=_NextPart_000_0019_01C1F3BD.BEDB82F0--