2006-12-11 Miguel de Icaza <miguel@novell.com>
authorMiguel de Icaza <miguel@gnome.org>
Tue, 12 Dec 2006 00:40:52 +0000 (00:40 -0000)
committerMiguel de Icaza <miguel@gnome.org>
Tue, 12 Dec 2006 00:40:52 +0000 (00:40 -0000)
* SafeHandle.cs: Fix a handful of bugs, and add tests for them.
Only release the handle if its owned by us.  Also throw
ObjectDisposedException's

svn path=/trunk/mcs/; revision=69378

mcs/class/corlib/System.Runtime.InteropServices/ChangeLog
mcs/class/corlib/System.Runtime.InteropServices/SafeHandle.cs
mcs/class/corlib/Test/System.Runtime.InteropServices/SafeHandleTest.cs [new file with mode: 0644]
mcs/class/corlib/corlib_test.dll.sources

index 9aa712152ad556fde1cdb7f793e18ab4dc97a5a8..d4905b35531a8d157c405e98f1b1fd790d3eeaa5 100644 (file)
@@ -1,6 +1,10 @@
 2006-12-11  Miguel de Icaza  <miguel@novell.com>
 
-       * SafeHandle.cs: Implement finalizer.
+       * SafeHandle.cs: Fix a handful of bugs, and add tests for them.
+       Only release the handle if its owned by us.  Also throw
+       ObjectDisposedException's
+
+       Implement finalizer.
 
        DangerousAddRef will now throw an exception if the object was
        disposed.
index eb23e9c13a551bce769909d455108c47542a2754..438bb7998bfd158cee47c7bcc23ec86e86142264 100644 (file)
@@ -70,9 +70,12 @@ namespace System.Runtime.InteropServices
 
                public void Close ()
                {
+                       if (refcount == 0)
+                               throw new ObjectDisposedException (GetType ().FullName);
+
                        lock (handle_lock){
                                refcount--;
-                               if (refcount == 0){
+                               if (refcount == 0 && owns_handle){
                                        ReleaseHandle ();
                                        handle = invalid_handle_value;
                                }
@@ -90,6 +93,9 @@ namespace System.Runtime.InteropServices
                //
                public void DangerousAddRef (ref bool success)
                {
+                       if (refcount == 0)
+                               throw new ObjectDisposedException (GetType ().FullName);
+
                        lock (handle_lock){
                                if (handle == invalid_handle_value || refcount == 0){
                                        //
@@ -98,7 +104,7 @@ namespace System.Runtime.InteropServices
                                        // am left wondering: when would "success" be
                                        // set to false?
                                        //
-                                       throw new ObjectDisposedException ("handle");
+                                       throw new ObjectDisposedException (GetType ().FullName);
                                }
                                
                                refcount++;
@@ -108,12 +114,18 @@ namespace System.Runtime.InteropServices
 
                public IntPtr DangerousGetHandle ()
                {
+                       if (refcount == 0){
+                               throw new ObjectDisposedException (GetType ().FullName);
+                       }
+
                        return handle;
                }
 
                public void DangerousRelease ()
                {
-                       Console.WriteLine ("DangerousRelease called");
+                       if (refcount == 0)
+                               throw new ObjectDisposedException (GetType ().FullName);
+
                        lock (handle_lock){
                                refcount--;
                                if (refcount == 0 && owns_handle){
@@ -148,7 +160,7 @@ namespace System.Runtime.InteropServices
                                // the question is whether:
                                //   * The runtime will ever call Dipose(false) for SafeHandles (special runtime case)
                                //   * Whether we should just call ReleaseHandle regardless?
-                               // 
+                               //
                        }
                }
 
diff --git a/mcs/class/corlib/Test/System.Runtime.InteropServices/SafeHandleTest.cs b/mcs/class/corlib/Test/System.Runtime.InteropServices/SafeHandleTest.cs
new file mode 100644 (file)
index 0000000..9cedc70
--- /dev/null
@@ -0,0 +1,93 @@
+//
+// System.Runtime.InteropServices.SafeHandle Test Cases
+//
+// Authors:
+//     Miguel de Icaza (miguel@novell.com)
+//
+// Copyright (C) 2004-2006 Novell, Inc (http://www.novell.com)
+//
+#if NET_2_0
+using NUnit.Framework;
+using System;
+using System.Runtime.InteropServices;
+using System.Security;
+using Microsoft.Win32.SafeHandles;
+
+namespace MonoTests.System.Runtime.InteropServices
+{
+       [TestFixture]
+       public class SafeHandleTest 
+       {
+               //
+               // This mimics SafeFileHandle, but does not actually own a handle
+               // We use this to test ownership and dispose exceptions.
+               //
+               public class FakeSafeHandle : SafeHandleZeroOrMinusOneIsInvalid
+               {
+                       public bool released = false;
+                       
+                       public FakeSafeHandle (): base (true)
+                       {
+                       }
+                       
+                       public FakeSafeHandle (bool ownership) : base (ownership)
+                       {
+                       }
+
+                       protected override bool ReleaseHandle ()
+                       {
+                               released = true;
+                               return true;
+                       }
+               }
+               
+               [Test]
+               [ExpectedException (typeof (ObjectDisposedException))]
+               public void Dispose1 ()
+               {
+                       FakeSafeHandle sf = new FakeSafeHandle ();
+
+                       sf.DangerousRelease ();
+                       sf.DangerousRelease ();
+               }
+
+               [Test]
+               [ExpectedException (typeof (ObjectDisposedException))]
+               public void Dispose2 ()
+               {
+                       FakeSafeHandle sf = new FakeSafeHandle ();
+
+                       sf.DangerousRelease ();
+                       sf.Close ();
+               }
+
+               [Test]
+               [ExpectedException (typeof (ObjectDisposedException))]
+               public void Dispose3 ()
+               {
+                       FakeSafeHandle sf = new FakeSafeHandle ();
+
+                       sf.Close ();
+                       sf.DangerousRelease ();
+               }
+
+               [Test]
+               public void NoReleaseUnowned ()
+               {
+                       FakeSafeHandle sf = new FakeSafeHandle (false);
+
+                       sf.Close ();
+                       Assert.AreEqual (sf.released, false, "r1");
+
+                       sf = new FakeSafeHandle (false);
+                       sf.DangerousRelease ();
+                       Assert.AreEqual (sf.released, false, "r2");
+
+                       sf = new FakeSafeHandle (false);
+                       ((IDisposable) sf).Dispose ();
+                       Assert.AreEqual (sf.released, false, "r3");
+               }
+       }
+}
+
+#endif
index 3d3a8e29a75ea81bcf1fa81c8cc10c4a2e38729e..1f3ba2a2e0f0efbd92e3d3c3ec0072ed95271cd1 100644 (file)
@@ -130,6 +130,7 @@ System.Runtime.CompilerServices/RuntimeWrappedExceptionTest.cs
 System.Runtime.InteropServices/GCHandleTest.cs
 System.Runtime.InteropServices/MarshalTest.cs
 System.Runtime.InteropServices/RuntimeEnvironmentTest.cs
+System.Runtime.InteropServices/SafeHandleTest.cs
 System.Runtime.Remoting/ContextTest.cs
 System.Runtime.Remoting/SoapServicesTest.cs
 System.Runtime.Remoting/SynchronizationAttributeTest.cs