CompoundFile.Dispose internally locks in an attempt to be thread safe, however it then sets the lockObject field to null. Any concurrent calls that happen to be about to enter that point will throw an ArumentNullException if they try to wait on the lock. Also as lockObject is not volatile that assignment may take a while to persist.
This error is a thread based race condition and will only occur when a separate thread passes to the lock call right after lockObject is assigned to null, and before _disposed is set to true.
Also if something waits on the lock then continues to run it will crash due to DirectoryEntries being null.
_disposed is also not volatile so treating Dispose as thread safe is misleading and not thread safe.
This test may not show the issues every time, but should be able to highlight some of the errors.
[TestMethod]
public void ConcurrentDisposeTest()
{
IDisposable file = new CompoundFile();
Parallel.Invoke(file.Dispose, file.Dispose, file.Dispose, file.Dispose,
file.Dispose, file.Dispose, file.Dispose);
}
Sector.Dispose also attempts to be thread safe. While it does not have the lockObject issue it does have the non volatile _disposed issue.
Yay, concurrency!