[
  {
    "Id": "1275701",
    "ThreadId": "552655",
    "Html": "If there is an error writing to the underlying stream, ZipOutputStream's Dispose() method leaves the underlying stream open.  The cause of this is the _exceptionPending logic.\r<br />\n<br />\nIn ZipOutputStream.cs there is a variable called _exceptionPending with a comment that says:<br />\n<pre><code>// When ZipOutputStream is employed within a using clause, which\n// is the typical scenario, and an exception is thrown within\n// the scope of the using, Close()/Dispose() is invoked\n// implicitly before processing the initial exception.  In that\n// case, _exceptionPending is true, and we don't want to try to\n// write anything in the Close/Dispose logic.  Doing so can\n// cause additional exceptions that mask the original one. So,\n// the _exceptionPending flag is used to track that, and to\n// allow the original exception to be propagated to the\n// application without extra &quot;noise.&quot;</code></pre>\n\nThat makes sense.  But current implementation using _exceptionPending does not actually address this problem.  Also, the current implementation leaks the underlying file stream in that case.\r<br />\n<br />\nSo regarding the first problem:\r<br />\n_exceptionPending is only set to true when the ZipOutputStream code throws an exception.  It does not get set if the underlying stream throws an exception.  Oops!  For example, if the volume is dismounted, disk space fills up, etc.<br />\n\r<br />\nIn that case, _exceptionPending = false so the Dispose() tries to do all the usual work, and thus throws an exception.  That exception not only means it &quot;masks&quot; the original exception as described in the comment, but it also never gets to the Dispose() call on the underlying stream!\r<br />\n<br />\nAnd the second problem:\r<br />\nIf _exceptionPending = true, it skips the entire Dispose() method, except for setting _disposed = true.  This means the underlying stream is not closed.  In our application, it meant the stream was left open until garbage collection closed it.\r<br />\n<br />\nI think the original idea in the code is correct, but it did not go far enough.\r<br />\n<br />\nThe Framework Design Guidelines (2nd ed) has this as (§9.4.1):<br />\n<blockquote>\nAVOID throwing an exception from within Dispose(bool) except under critical situations where the containing process has been corrupted (leaks, inconsistent shared state, etc.).<br />\n</blockquote>\nI believe that the correct fix is to change the Dispose() method to simply not throw exceptions.  Here is what our team did:\r<br />\n1) Put a try/catch block around the calls that flush the file and swallow whatever exception happens that.  So even if those calls throw an exception, the underlying stream is still closed.\r<br />\n2) Dispose() the underlying stream regardless of the setting of _exceptionPending.  Also, put a try/catch around that in case the underlying stream gets an exception.\r<br />\n<br />\nWe did this in our application and it solved our problem.<br />\n\r<br />\nMy only question is this: At that point, _exceptionPending serves no purpose.  It still could be used to prevent it from even trying to flush to disk.  But with a try/catch + swallow there, I see no benefit to it.\r<br />\n<br />\nI would like some feedback before I try to submit a patch.  (I've never done that to CodePlex before).<br />\n",
    "PostedDate": "2014-07-23T13:58:48.633-07:00",
    "UserRole": null,
    "MarkedAsAnswerDate": null
  }
]