Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > ASP .Net > Unhandled exception in FileStream when writing to a full disk - bug in framework?

Reply
Thread Tools

Unhandled exception in FileStream when writing to a full disk - bug in framework?

 
 
Amit
Guest
Posts: n/a
 
      07-29-2003
Hello,

I just ran into a weird problem with FileStream. The problem occurs in
the following scenario:
- I create an instance of FileStream and use it to write to a disk
which have just a small amount of free space.
- When the disk gets full, FileStream throws an IOException. I catch
and process it.
- My program continues executing. At some later point, I'm getting an
unhandled IOException (althoug the whole code is wrapped in try-catch
block).
- After inspecting the call stack and the running threads I made the
following observations:
--- The second exception occurs in a thread which doesn't belong to my
process.
--- The call stack of the thread in which this exception occurs starts
within the FileStream finalize method.

By observing the calls in the call stack, I believe that what happen
is as follows:

When the disk gets full and the first exception (that I handle)
occurs, the buffer of the FileStream object is not empty. However,
since the object gets out of scope, the garbage collector tries to
release it at some point. The garbage collector calls finalize, which
calls dispose, and one of the calls in this sequense is a call to
flush() that tries to write the buffer before killing the object.
Since the disk is full, this call fails and an IOException is thrown
from the garbage collector thread.

I found no way to get around this, except from disabling garbage
collection for the FileStream object, which IMHO is pretty ugly. If the
garbage collector and FileStream always work in this way, i.e. the GC
calls finalize, which causes flush to be called without knowing that
the disk is already full and a previous write failed, then it seems
like a bug in the framework.

I would appreciate any comments,

TIA,

Amit

P.s. Below is the code I've been using for demonstrating this problem:

static void Main(string[] args)
{
try
{
FileStream fs =
new FileStream(args[0], FileMode.Create);
Console.WriteLine("starting to write...");
while (true)
fs.WriteByte(0xff);
}
catch (Exception e)
{
Console.WriteLine("Exception: {0}",
e.Message);
}
Console.WriteLine("press any key to continue");
Console.Read();


}
 
Reply With Quote
 
 
 
 
Alan Pretre
Guest
Posts: n/a
 
      07-29-2003
"Amit" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed) m...
> I found no way to get around this, except from disabling garbage
> collection for the FileStream object, which IMHO is pretty ugly. If the
> garbage collector and FileStream always work in this way, i.e. the GC
> calls finalize, which causes flush to be called without knowing that
> the disk is already full and a previous write failed, then it seems
> like a bug in the framework.


When you get the exception, can't you do fs.SetLength(0)? I haven't tried
it since I don't have a spare drive to run it on at the moment. I
rearranged your code. Let me know what happens.

static void Main(string[] args) {
try {
FileStream fs = new FileStream(args[0], FileMode.Create);
try {
Console.WriteLine("starting to write...");
while (true) fs.WriteByte(0xff);
} catch (Exception e1) {
Console.WriteLine("Exception: {0}", e1.Message);
fs.SetLength(0);
}
} catch (Exception e2) {
Console.WriteLine("Exception: {0}", e2.Message);
}
Console.WriteLine("press any key to continue");
Console.Read();
}

-- Alan


 
Reply With Quote
 
 
 
 
Amit
Guest
Posts: n/a
 
      07-30-2003
Alan,

Sorry, this doesn't help. I tried it and it failed - SetLength itself
throws an exception in this case, and if you catch and handle it, you
still get the unhandled exception later.

I also looked at SetLength code (in rotor), and it shows that
SetLength tries to flush the buffer. This of course fails.

I still thinks this is a bug in the framework - they should have
maintain state so Finalize will know that previous writes failed and
will not attempt to write the buffer.

Any more ideas?

Amit

"Alan Pretre" <no@spam> wrote in message news:<O#(E-Mail Removed)>...
> "Amit" <(E-Mail Removed)> wrote in message
> news:(E-Mail Removed) m...
> > I found no way to get around this, except from disabling garbage
> > collection for the FileStream object, which IMHO is pretty ugly. If the
> > garbage collector and FileStream always work in this way, i.e. the GC
> > calls finalize, which causes flush to be called without knowing that
> > the disk is already full and a previous write failed, then it seems
> > like a bug in the framework.

>
> When you get the exception, can't you do fs.SetLength(0)? I haven't tried
> it since I don't have a spare drive to run it on at the moment. I
> rearranged your code. Let me know what happens.
>
> static void Main(string[] args) {
> try {
> FileStream fs = new FileStream(args[0], FileMode.Create);
> try {
> Console.WriteLine("starting to write...");
> while (true) fs.WriteByte(0xff);
> } catch (Exception e1) {
> Console.WriteLine("Exception: {0}", e1.Message);
> fs.SetLength(0);
> }
> } catch (Exception e2) {
> Console.WriteLine("Exception: {0}", e2.Message);
> }
> Console.WriteLine("press any key to continue");
> Console.Read();
> }
>
> -- Alan

 
Reply With Quote
 
Dave
Guest
Posts: n/a
 
      07-30-2003
Can you dispose the object yourself when the exception occurs? This might
cause it to throw the second exception immediately rather then when the
finalizer runs.

"Amit" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed) om...
> Alan,
>
> Sorry, this doesn't help. I tried it and it failed - SetLength itself
> throws an exception in this case, and if you catch and handle it, you
> still get the unhandled exception later.
>
> I also looked at SetLength code (in rotor), and it shows that
> SetLength tries to flush the buffer. This of course fails.
>
> I still thinks this is a bug in the framework - they should have
> maintain state so Finalize will know that previous writes failed and
> will not attempt to write the buffer.
>
> Any more ideas?
>
> Amit
>
> "Alan Pretre" <no@spam> wrote in message

news:<O#(E-Mail Removed)>...
> > "Amit" <(E-Mail Removed)> wrote in message
> > news:(E-Mail Removed) m...
> > > I found no way to get around this, except from disabling garbage
> > > collection for the FileStream object, which IMHO is pretty ugly. If

the
> > > garbage collector and FileStream always work in this way, i.e. the GC
> > > calls finalize, which causes flush to be called without knowing that
> > > the disk is already full and a previous write failed, then it seems
> > > like a bug in the framework.

> >
> > When you get the exception, can't you do fs.SetLength(0)? I haven't

tried
> > it since I don't have a spare drive to run it on at the moment. I
> > rearranged your code. Let me know what happens.
> >
> > static void Main(string[] args) {
> > try {
> > FileStream fs = new FileStream(args[0], FileMode.Create);
> > try {
> > Console.WriteLine("starting to write...");
> > while (true) fs.WriteByte(0xff);
> > } catch (Exception e1) {
> > Console.WriteLine("Exception: {0}", e1.Message);
> > fs.SetLength(0);
> > }
> > } catch (Exception e2) {
> > Console.WriteLine("Exception: {0}", e2.Message);
> > }
> > Console.WriteLine("press any key to continue");
> > Console.Read();
> > }
> >
> > -- Alan



 
Reply With Quote
 
Amit
Guest
Posts: n/a
 
      07-31-2003
"Dave" <(E-Mail Removed)> wrote in message news:<(E-Mail Removed)>...
> Can you dispose the object yourself when the exception occurs? This might
> cause it to throw the second exception immediately rather then when the
> finalizer runs.


No, it won't help. Dispose will fail since it cannot write to the
disk, but even if you do that and catch the second exception, Finalize
will still try to dispose the file again. The point is, anything you
do trying to release the file will fail, so the buffer will remain
full. I would expect that the FileStream would "remeber" that it
cannot write, and it won't, after the first failure, attempt
writing again. However, apparently this is not how it works. There is
nothing one can do, AFAIK, to prevent Finalize from trying to flush
the file.

Cheers,
Amit
 
Reply With Quote
 
Dave
Guest
Posts: n/a
 
      07-31-2003
It sounds like the current version has been poorly implemented. How about
something silly....if you can reliably detect when this sort of failure
occurs perhaps you can redirect the filestream to point to a file that it
can always write to; a bit bucket that was always available. It's been a
long time since this has come up but I seem to recall there used to be such
a file. That might cause it to change its behavior during finalization.


"Amit" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed) om...
> "Dave" <(E-Mail Removed)> wrote in message

news:<(E-Mail Removed)>...
> > Can you dispose the object yourself when the exception occurs? This

might
> > cause it to throw the second exception immediately rather then when the
> > finalizer runs.

>
> No, it won't help. Dispose will fail since it cannot write to the
> disk, but even if you do that and catch the second exception, Finalize
> will still try to dispose the file again. The point is, anything you
> do trying to release the file will fail, so the buffer will remain
> full. I would expect that the FileStream would "remeber" that it
> cannot write, and it won't, after the first failure, attempt
> writing again. However, apparently this is not how it works. There is
> nothing one can do, AFAIK, to prevent Finalize from trying to flush
> the file.
>
> Cheers,
> Amit



 
Reply With Quote
 
Amit
Guest
Posts: n/a
 
      08-04-2003
I poked around a little bit, and I believe there are two separate
problems here:

1. I looked at the rotor FileStream code, and it seems that once you
get the "not enough space on disk" exception, FileStream do not
provide any means for closing the file and releasing the underlying
WIN32 handle. So even if you find a way to catch the exception,
handles might leak (even if the CLR would swalloe the exception, see
my next point).

2. It seems that all exceptions occuring in Finalizers should be
swallowed by the CLR. You may look at
http://blogs.gotdotnet.com/cbrumme/C...yView.aspx/CLR
at the "Unhandled Exceptions" section. In the case we are discussing,
this is apparently not the way it happens.


Anyway, I found a workaround by calling FileStream.Close() from within
a try/catch block, and if an exception occurs I call
CG.SuppressFinalize for the FileStream object. That way I do not get
unhandled exceptions, but I believe that I lose a leaking WIN32
hanlde. I just don't have enough time to mess with it anymore.

Cheers,

Amit


"Dave" <(E-Mail Removed)> wrote in message news:<(E-Mail Removed)>...
> It sounds like the current version has been poorly implemented. How about
> something silly....if you can reliably detect when this sort of failure
> occurs perhaps you can redirect the filestream to point to a file that it
> can always write to; a bit bucket that was always available. It's been a
> long time since this has come up but I seem to recall there used to be such
> a file. That might cause it to change its behavior during finalization.
>
>

 
Reply With Quote
 
Dave
Guest
Posts: n/a
 
      08-04-2003
It looks like a bug and/or a design deficiency in the FileStream class - it
seems like one of those problems that will get improved on as the runtime
becomes more mature. I'm very familiar with Chris's weblog - swallowing
exceptions in the finalizer thread makes sense, but they should be reported
as a bug in the object being finalized.

Closing the file object in a catch or finally block seems like good
programming practice anyway - files are one of those sensitive system
objects that need careful handling. I'm surprised you have to use
GC.SuppressFinalize on it after you have closed it - I would have expected
it to be able to retain the state info necessary to remember that it was
already closed.

Good luck with the rest of your project.

Dave



"Amit" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed) om...
> I poked around a little bit, and I believe there are two separate
> problems here:
>
> 1. I looked at the rotor FileStream code, and it seems that once you
> get the "not enough space on disk" exception, FileStream do not
> provide any means for closing the file and releasing the underlying
> WIN32 handle. So even if you find a way to catch the exception,
> handles might leak (even if the CLR would swalloe the exception, see
> my next point).
>
> 2. It seems that all exceptions occuring in Finalizers should be
> swallowed by the CLR. You may look at
> http://blogs.gotdotnet.com/cbrumme/C...yView.aspx/CLR
> at the "Unhandled Exceptions" section. In the case we are discussing,
> this is apparently not the way it happens.
>
>
> Anyway, I found a workaround by calling FileStream.Close() from within
> a try/catch block, and if an exception occurs I call
> CG.SuppressFinalize for the FileStream object. That way I do not get
> unhandled exceptions, but I believe that I lose a leaking WIN32
> hanlde. I just don't have enough time to mess with it anymore.
>
> Cheers,
>
> Amit
>
>
> "Dave" <(E-Mail Removed)> wrote in message

news:<(E-Mail Removed)>...
> > It sounds like the current version has been poorly implemented. How

about
> > something silly....if you can reliably detect when this sort of failure
> > occurs perhaps you can redirect the filestream to point to a file that

it
> > can always write to; a bit bucket that was always available. It's been a
> > long time since this has come up but I seem to recall there used to be

such
> > a file. That might cause it to change its behavior during finalization.
> >
> >



 
Reply With Quote
 
Alan Pretre
Guest
Posts: n/a
 
      08-04-2003
"Amit" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed) om...
> 1. I looked at the rotor FileStream code, and it seems that once you
> get the "not enough space on disk" exception, FileStream do not
> provide any means for closing the file and releasing the underlying
> WIN32 handle. So even if you find a way to catch the exception,
> handles might leak (even if the CLR would swalloe the exception, see
> my next point).


You do have access to the underlying OS handle, fs.Handle. Perhaps you
could use P/Invoke to close the handle to prevent leaks.

-- Alan


 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
an unhandled win32 exception was unhandled occurred in inetinfo.exe Warren Tang ASP .Net 1 09-23-2008 03:01 PM
FileStream Writing Problems Scott ASP .Net 1 08-06-2004 04:31 PM
An unhandled exception has been caught by the VSW exception filter. Tedka ASP .Net 2 07-19-2004 08:09 PM
An unhandled exception has been caught by the VSW exception filter. Ola ASP .Net 0 04-26-2004 01:00 PM
An unhandled exception occurred during compilation using the CodeDomProvider Pardhasaradhy ASP .Net 1 07-09-2003 05:37 AM



Advertisments