Based on this post, I created a bridge between components for Windows forms and IDisposable objects. It pretty much looks like this:
namespace MyApp
{
public class Disposer: Component
{
private readonly Action<bool> _dispose;
public Disposer(Action<bool> disposeCallback)
{
if (disposeCallback == null)
throw new ArgumentNullException(nameof(disposeCallback));
this._dispose = disposeCallback;
}
protected override void Dispose(bool disposing)
{
this._dispose(disposing);
base.Dispose(disposing);
}
}
}
So far so good. Then I created unit tests, including one for the particular validation on the constructor argument.
[TestMethod]
[ExpectedException(typeof(ArgumentNullException))]
public void Disposer_ShouldNotAllowNullActions()
{
new Disposer(null);
}
Here's the catch: not only my test fails, but it actually gets aborted. The test platform itself crashes (ReSharper test runner). By digging into my Windows Event Viewer I could see that the Dispose() method is being called, and since this._dispose is essentially null at this point, it fails with a NullReferenceException.
I fixed this with providing an empty lambda as the default value.
But if the constructor throws an exception (which I confirmed it does), why is the Dispose method called at all?
The Component class must have a finalizer that calls this.Dispose(), which causes your override to be called.
Finalizers are run even if the constructor did not complete - this allows all resources that were allocated before the constructor failed to be cleaned up.
why is the Dispose method called at all?
The finalizer for a class is called even if the constructor throws an exception. The finalizer for Component calls Dispose():
~Component() {
Dispose(false);
}
Since you override Dispose(bool), your override is called if the constructor throws an exception. Since this is a real possibility in your code, I'd suggest making sure both this and this._dispose are not null.
Related
I am writing error to event log but when i checked for leakage i got event log leakage in .net profiler, Do I need to dispose this object? Is it will create any issue in multi threading?
public override void ProcessWarning(string title, string message)
{
if (title == null)
eventLog.WriteEntry(message, EventLogEntryType.Warning);
else
eventLog.WriteEntry(title + '\n' + message, EventLogEntryType.Warning);
}
}
The EventLog class extends Component, which shows that it implements IDisposable. So yes, you will need to (eventually) Dispose() of it.
Apparently your eventLog is a field in your class. This (an IDisposable field) means that your class needs to implement IDisposable itself. In your own Dispose method you will then need to dispose of that eventLog.
And of course this means that anything using this class must treat it as the IDisposable that it now is.
The same question has been asked for Java, but I'm interested in a .NET answer.
Consider the following code:
class Program
{
static void Main()
{
try
{
RunTransaction();
// If there was an exception within the transaction,
// I won't be here anymore. But if the transaction was
// cancelled without an exception being thrown, I really
// need to know because I must stop here anyway.
OtherCode();
}
catch (Excexption ex)
{
// Log the exception...
// If an exception was thrown in the transaction scope,
// this must be logged here. If a "helper" exception was
// created in the Dispose method, this may be logged, but
// it won't say much. It just made sure that nothing else
// was executed in this try block.
}
}
static void RunTransaction()
{
using (var trans = new Transaction())
{
// An error may occur here and it should be logged.
throw new Exception();
// Maybe the scope is simply left without an exception.
return;
// Otherwise, the transaction is committed.
trans.Commit();
}
}
}
class Transaction : IDisposable
{
bool isCommitted;
public void Commit()
{
isCommitted = true;
}
public void Dispose()
{
if (!isCommitted)
{
// Was an exception thrown before this is called?
// If not, I might consider throwing one here.
// I can't always throw an exception here because if
// another exception is already propagated, it would
// be dropped and the real error cause would not be
// visible anymore.
}
}
}
In the Transaction.Dispose method, how can I know whether an exception was already thrown?
Note that the finally block is not explicitly shown here, but hidden in the using statement which calls the IDisposable.Dispose method, which is shown here.
Update: My background is that I have a transaction wrapper class that behaves a bit like TransactionScope. But TransactionScope is too much magic and doesn't work as expected so I went back to real database transactions. Some methods need a transaction but if they're called from another method that already needed a transaction, the inner "transaction" must "join" the outer transaction instead of requesting a new, nested transaction from the database, which is not supported anywhere I know of. The real code is a bit more complex than my sample, where the inner transaction may be cancelled, effectively ending the transaction. Then, if anything continues to run in the outer transaction, which does not exist anymore, it cannot be rolled back, but will effectively run outside of any transaction! This must be prevented by all means. Thoring an exception in the first place would do it, but the inner transaction can also be cancelled without that. This is what I want to detect in my scope helper class.
public void Dispose()
{
if (!isCommitted)
{
// Was an exception thrown before this is called?
// If not, I might consider throwing one here.
// I can't always throw an exception here because if
// another exception is already propagated, it would
// be dropped and the real error cause would not be
// visible anymore.
}
}
You say you want to throw an exception from Dispose if one wasn't thrown already.
But Dispose should not throw exceptions. From Implementing a Dispose method:
To help ensure that resources are always cleaned up appropriately, a Dispose method should be callable multiple times without throwing an exception.
Also from Dispose Pattern:
AVOID throwing an exception from within Dispose(bool) except under critical situations where the containing process has been corrupted (leaks, inconsistent shared state, etc.).
Users expect that a call to Dispose will not raise an exception.
If Dispose could raise an exception, further finally-block cleanup logic will not execute. To work around this, the user would need to wrap every call to Dispose (within the finally block!) in a try block, which leads to very complex cleanup handlers. If executing a Dispose(bool disposing) method, never throw an exception if disposing is false. Doing so will terminate the process if executing inside a finalizer context.
The question that you need to ask yourself is "why does this object have any business knowing if there was an exception?". And maybe I'm wrong here, but it seems that it is because you perceive that RunTransaction() has something to do with transaction itself, and that's a wrong assumption here, because the code seems to be located outside of Transaction class.
The way you should refactor your code is:
class Transaction : IDisposable
{
bool isCommitted;
public void Commit() { ... }
public void Dispose() { ... }
public void RunTransaction() { ... }
}
This way if RunTransaction() throws, you could tell.
EDIT: Alternatively, if the code MUST be located outside Transaction class, you can further refactor Transaction to do:
public void RunTransaction(Action action) { ... }
and invoke it with:
trans.RunTransaction(() => RunTransaction());
I have a class that implements IDisposable, because it uses image resources (Bitmap class) from GDI+. I use it for wrapping all that gimmicky LockBits/UnlockBits. And it works fine, be it when I call Dispose() or with the using statement.
However, if I leave the program to terminate without disposing, I get a System.AccessViolationException. Intuitively, I think the GC would call the Dispose the same way I do, and the object would gracefully release the resources, but that's not what happening. Why?
Here's the IDisposable code:
private bool _disposing = false;
~QuickBitmap() {
Dispose(false);
}
public void Dispose() {
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool safeDispose) {
if (_disposing)
return;
SaveBits(); // private wrapper to UnlockBits
bytes = null; // byte[] of the image
bmpData = null; // BitmapData object
if (safeDispose && bm != null) {
bm.Dispose(); // Bitmap object
bm = null;
}
_disposing = true;
}
Here's when it works ok:
using (var qbm = new QuickBitmap("myfile.jpg"))
{
// use qbm.GetPixel/qbm.SetPixel at will
}
Here's when it doesn't work:
public static void Main (string[] args) {
// this is just an example, simply constructing the object and doing nothing will throw the exception
var qbm = new QuickBitmap(args[0]);
qbm.SetPixel(0, 0, Color.Black);
qbm.Save();
}
The complete excetion is (there's no inner exception):
An unhandled exception of type 'System.AccessViolationException' occurred in mscorlib.dll
Additional information: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
The reproduction is 100%, even on different machines. I do figure out we should use using or Dispose(), not using it is bad and all that stuff. I just want to know: why does this happen? Why is the memory "protected"? Which kind of access am I violating?
The problem occurs because you included an unnecessary finalizer in your implementation. Code executed from a finalizer generally cannot access managed objects safely. It is likely that the call to SaveBits results in the use of managed objects in violation of this rule, though you did not include the code for that method.
The best solution would be to simply remove the finalizer from QuickBitmap, since the QuickBitmap class does not directly own unmanaged resources.
The whole point of IDisposable is to gracefully clean up unmanaged resources. The literal definition of an unmanaged resource is a resource that the GC won't be able to clean up on its own. Unsurprisingly, it won't be able to clean it up on its own if you don't. Objects that can be cleaned up entirely through the GC need not be disposable, and this require no manual disposal. If the object could be cleaned up without manual disposable then it wouldn't have a need to implement IDisposable in the first place.
(I know, this is a ridiculously long question. I tried to separate the question from my investigation so far, so it's slightly easier to read.)
I'm running my unit tests using MSTest.exe. Occasionally, I see this test error:
On the individual unit test method: "The agent process was stopped while the test was running."
On the entire test run:
One of the background threads threw exception:
System.NullReferenceException: Object reference not set to an instance of an object.
at System.Runtime.InteropServices.Marshal.ReleaseComObject(Object o)
at System.Management.Instrumentation.MetaDataInfo.Dispose()
at System.Management.Instrumentation.MetaDataInfo.Finalize()
So, here's what I think I need to do: I need to track down what is causing the error in MetaDataInfo, but I'm drawing a blank. My unit test suite takes over half an hour to run, and the error doesn't happen every time, so it's hard to get it to reproduce.
Has anyone else seen this type of failure in running unit tests? Were you able to track it down to a specific component?
Edit:
The code under test is a mix of C#, C++/CLI, and a little bit of unmanaged C++ code. The unmanaged C++ is used only from the C++/CLI, never directly from the unit tests. The unit tests are all C#.
The code under test will be running in a standalone Windows Service, so there's no complication from ASP.net or anything like that. In the code under test, there's threads starting & stopping, network communication, and file I/O to the local hard drive.
My investigation so far:
I spent some time digging around the multiple versions of the System.Management assembly on my Windows 7 machine, and I found the MetaDataInfo class in System.Management that's in my Windows directory. (The version that's under Program Files\Reference Assemblies is much smaller, and doesn't have the MetaDataInfo class.)
Using Reflector to inspect this assembly, I found what seems to be an obvious bug in MetaDataInfo.Dispose():
// From class System.Management.Instrumentation.MetaDataInfo:
public void Dispose()
{
if (this.importInterface == null) // <---- Should be "!="
{
Marshal.ReleaseComObject(this.importInterface);
}
this.importInterface = null;
GC.SuppressFinalize(this);
}
With this 'if' statement backwards, MetaDataInfo will leak the COM object if present, or throw a NullReferenceException if not. I've reported this on Microsoft Connect: https://connect.microsoft.com/VisualStudio/feedback/details/779328/
Using reflector, I was able to find all uses of the MetaDataInfo class. (It's an internal class, so just searching the assembly should be a complete list.) There is only one place it is used:
public static Guid GetMvid(Assembly assembly)
{
using (MetaDataInfo info = new MetaDataInfo(assembly))
{
return info.Mvid;
}
}
Since all uses of MetaDataInfo are being properly Disposed, here's what's happening:
If MetaDataInfo.importInterface is not null:
static method GetMvid returns MetaDataInfo.Mvid
The using calls MetaDataInfo.Dispose
Dispose leaks the COM object
Dispose sets importInterface to null
Dispose calls GC.SuppressFinalize
Later, when the GC collects the MetaDataInfo, the finalizer is skipped.
.
If MetaDataInfo.importInterface is null:
static method GetMvid gets a NullReferenceException calling MetaDataInfo.Mvid.
Before the exception propagates up, the using calls MetaDataInfo.Dispose
Dispose calls Marshal.ReleaseComObject
Marshal.ReleaseComObject throws a NullReferenceException.
Because an exception is thrown, Dispose doesn't call GC.SuppressFinalize
The exception propagates up to GetMvid's caller.
Later, when the GC collects the MetaDataInfo, it runs the Finalizer
Finalize calls Dispose
Dispose calls Marshal.ReleaseComObject
Marshal.ReleaseComObject throws a NullReferenceException, which propagates all the way up to the GC, and the application is terminated.
For what it's worth, here's the rest of the relevant code from MetaDataInfo:
public MetaDataInfo(string assemblyName)
{
Guid riid = new Guid(((GuidAttribute) Attribute.GetCustomAttribute(typeof(IMetaDataImportInternalOnly), typeof(GuidAttribute), false)).Value);
// The above line retrieves this Guid: "7DAC8207-D3AE-4c75-9B67-92801A497D44"
IMetaDataDispenser o = (IMetaDataDispenser) new CorMetaDataDispenser();
this.importInterface = (IMetaDataImportInternalOnly) o.OpenScope(assemblyName, 0, ref riid);
Marshal.ReleaseComObject(o);
}
private void InitNameAndMvid()
{
if (this.name == null)
{
uint num;
StringBuilder szName = new StringBuilder {
Capacity = 0
};
this.importInterface.GetScopeProps(szName, (uint) szName.Capacity, out num, out this.mvid);
szName.Capacity = (int) num;
this.importInterface.GetScopeProps(szName, (uint) szName.Capacity, out num, out this.mvid);
this.name = szName.ToString();
}
}
public Guid Mvid
{
get
{
this.InitNameAndMvid();
return this.mvid;
}
}
Edit 2:
I was able to reproduce the bug in the MetaDataInfo class for Microsoft. However, my reproduction is slightly different from the issue I'm seeing here.
Reproduction: I try to create a MetaDataInfo object on a file that isn't a managed assembly. This throws an exception from the constructor before importInterface is initialized.
My issue with MSTest: MetaDataInfo is constructed on some managed assembly, and something happens to make importInterface null, or to exit the constructor before importInterface is initialized.
I know that MetaDataInfo is created on a managed assembly, because MetaDataInfo is an internal class, and the only API that calls it does so by passing the result of Assembly.Location.
However, re-creating the issue in Visual Studio meant that it downloaded the source to MetaDataInfo for me. Here's the actual code, with the original developer's comments.
public void Dispose()
{
// We implement IDisposable on this class because the IMetaDataImport
// can be an expensive object to keep in memory.
if(importInterface == null)
Marshal.ReleaseComObject(importInterface);
importInterface = null;
GC.SuppressFinalize(this);
}
~MetaDataInfo()
{
Dispose();
}
The original code confirms what was seen in reflector: The if statement is backwards, and they shouldn't be accessing the managed object from the Finalizer.
I said before that because it was never calling ReleaseComObject, that it was leaking the COM object. I read up more on the use of COM objects in .Net, and if I understand it properly, that was incorrect: The COM object isn't released when Dispose() is called, but it is released when the garbage collector gets around to collecting the Runtime Callable Wrapper, which is a managed object. Even though it's a wrapper for an unmanaged COM object, the RCW is still a managed object, and the rule about "don't access managed objects from the finalizer" should still apply.
Try to add the following code to your class definition:
bool _disposing = false // class property
public void Dispose()
{
if( !disposing )
Marshal.ReleaseComObject(importInterface);
importInterface = null;
GC.SuppressFinalize(this);
disposing = true;
}
If MetaDataInfo uses the IDisposable pattern, then there should also be a finalizer (~MetaDataInfo() in C#). The using statement will make sure to call Dispose(), which sets the importInterface to null. Then when the GC is ready to finalize, the ~MetaDataInfo() is called, which would normally call Dispose (or rather the overload taking a bool disposing: Dispose(false)).
I would say that this error should turn up quite often.
Are you trying to fix this for your tests? If so, rewrite your using. Don't dispose of it yourself but write some code to use reflection to access the private fields and dispose of them correctly and then call GC.SuppressFinalize to prevent the finalizer from running.
As a brief aside (loved your investigation btw) you state that Dispose calls Finalize. It's the other way round, Finalize when invoked by the GC calls Dispose.
Finalizers are always called by .net framework, so the sequence could be out of control; and even if the constructor failed, the destructor still can be triggered.
This could bring troubles, when such finalizer exceptions come from a 3rd-party library: I can't find a way to handle them!
For example, in the code below, although class A's constructor always throw an exception and fail, finalizer of A will be triggered by the .net framework, also ~B() is called as A has a property of B type.
class Program // my code
{
static void Main(string[] args)
{
A objA;
try
{
objA = new A();
}
catch (Exception)
{
}
; // when A() throws an exception, objA is null
GC.Collect(); // however, this can force ~A() and ~B() to be called.
Console.ReadLine();
}
}
public class A // 3rd-party code
{
public B objB;
public A()
{
objB = new B(); // this will lead ~B() to be called.
throw new Exception("Exception in A()");
}
~A() // called by .net framework
{
throw new Exception("Exception in ~A()"); // bad coding but I can't modify
}
}
public class B // 3rd-party code
{
public B() { }
~B() // called by .net framework
{
throw new Exception("Exception in ~B()"); // bad coding but I can't modify
}
}
If these are my code, it is a bit easier
- I can use try-catch in finalizers, at least I can do some logging
- I can allow the exception to crash the program, to discover the error asap
- or if I want to "tolerate" the exception, I can have a try-catch to suppress the exception, and have a graceful exit.
But if A and B are classes from a 3rd-party library, I can do nothing!
I can't control the exception to happen, I can't catch them, so I can't log it or suppress it!
What can I do?
Sounds like the 3rd party utility is poorly written. :)
Have you tried catching it using AppDomain.UnhandledException?
You might want to consider a global exception handler for your application. You didn't indicate if your doing ASP.NET, WinForm, MVC, etc, but here's one for a console application:
.NET Global exception handler in console application
In ASP.NET, you can use the Global.asax file to catch unhandled exceptions.
If you are always calling GC.Collect() in your application, you might try wrapping that in a try-catch block as well.
Just some ideas to consider.
You can use GC.SuppressFinalizer(objA) and GC.KeepAlive(objA) which will prevent the garbage collector from calling the finalize on that object,and so when using KeepAlive the objB will not finalize because objA "which is alive" is still has reference of it. however you should then be aware from memory leaks if you forget to finalize or dispose objA in a proper way.
But suppose that the objA at some point in a method for instance has initialize another objectB and it does not dispose it properly, Then unfortunately I don't thing you can do anything about it.
Another thing you can try is to check if that library behaves differently when you are in Release mode rather than the Debug mode; for example they maybe only throw exception at the finalizer if it get called in debug mode "it kind of helper to developers so if they not call dispose or finalize the object in right way an exception will throw while debugging":
~A()
{
#if DEBUG
throw new Exception("Exception in ~A()");
#endif//DEBUG
}
If that is not the case, then I think you will have a bad days dealing with that library.