www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Bad file descriptor in File destructor

reply unDEFER <undefer gmail.com> writes:
Hello! I have the code like this:

     File file;
     try {
         file = File(path);
     }
     catch (Exception exp)
     {
         return;
     }

...
     try {

     }
Jul 13
next sibling parent reply unDEFER <undefer gmail.com> writes:
What the God? I was not ready to post...

     File file;
     try {
         file = File(path);
     }
     catch (Exception exp)
     {
         return;
     }

     try {
         //Some actions with file
     }
     catch (ErrnoException)
     {
         return;
     }


catch (ErrnoException) is necessary because there is sometimes 
"Bad file descriptor" error.
But now I have "Bad descriptior" in destructor. Where I must put 
my try/catch section to avoid it?

Thank you!
Jul 13
parent reply unDEFER <undefer gmail.com> writes:
Seems I have found. I must do:
try{
     File file;
     try {
         file = File(path);
     }
     catch (Exception exp)
     {
         return;
     }

     //Some actions with file
}
catch (ErrnoException)
{
     return;
}
Jul 13
parent Moritz Maxeiner <moritz ucworks.org> writes:
On Thursday, 13 July 2017 at 10:56:20 UTC, unDEFER wrote:
 Seems I have found. I must do:
 try{
     File file;
     try {
         file = File(path);
     }
     catch (Exception exp)
     {
         return;
     }

     //Some actions with file
 }
 catch (ErrnoException)
 {
     return;
 }
Well, yes, you can also encompass your entire function body in a try catch, though that makes your code somewhat hard to read[1]. With these many try/catches you may want to take a look at std.exception.collectException[2]. [1] https://en.wikipedia.org/wiki/Spaghetti_code [2] https://dlang.org/phobos/std_exception.html#.collectException
Jul 13
prev sibling parent reply Moritz Maxeiner <moritz ucworks.org> writes:
On Thursday, 13 July 2017 at 08:38:52 UTC, unDEFER wrote:
 Hello! I have the code like this:

     File file;
     try {
         file = File(path);
     }
     catch (Exception exp)
     {
         return;
     }

 ...
     try {

     }
Where does that `File` come from? If it's std.stdio.File, that one is a struct with internal reference counting, so it shouldn't crash in the above. Could you provide a minimal working (in this case crashing) example? If the `File` above is not std.stdio.File, but some custom type: Be aware that structs have deterministic lifetimes, so `file`'s destructor will be called even when you return in the catch clause (on the default constructed `file`), so `File`'s destructor must check the field carrying the file descriptor for being valid; I advise setting such fields to be default constructed to some invalid value (e.g. `-1` in case of file descriptors).
Jul 13
parent reply unDEFER <undefer gmail.com> writes:
On Thursday, 13 July 2017 at 08:53:24 UTC, Moritz Maxeiner wrote:
 Where does that `File` come from? If it's std.stdio.File, that 
 one is a struct with internal reference counting, so it 
 shouldn't crash in the above. Could you provide a minimal 
 working (in this case crashing) example?
Yes File is std.stdio.File. And I can't provide a minimal crashing example because this code crashes very rarely. I just want to put try/catch and don't know where to do it.
Jul 13
parent reply Moritz Maxeiner <moritz ucworks.org> writes:
On Thursday, 13 July 2017 at 10:28:30 UTC, unDEFER wrote:
 On Thursday, 13 July 2017 at 08:53:24 UTC, Moritz Maxeiner 
 wrote:
 Where does that `File` come from? If it's std.stdio.File, that 
 one is a struct with internal reference counting, so it 
 shouldn't crash in the above. Could you provide a minimal 
 working (in this case crashing) example?
Yes File is std.stdio.File. And I can't provide a minimal crashing example because this code crashes very rarely. I just want to put try/catch and don't know where to do it.
Well, if you get an ErrnoException on std.stdio.File.~this you are AFAIK either encountering an OS bug, or you have previously corrupted the file descriptor that File instance wraps around. To be specific, it sounds to me like you're trying to close a file descriptor that's already been closed, i.e. you should fix that instead of trying to work around the consequences of it. Under the assumption, though, that it's an OS bug you're encountering, you can't deal with it with just a try catch in that function, because a (stack allocated) struct's destructor is always called when it goes out of scope. I see essentially two workarounds: - Use two functions foo and bar, where bar has `file` on it's stack, and `foo` calls `bar` and catches the destructor exception via try catch block around the call to `bar` - Hide the `file` from the automatic out-of-scope destruction by using another type for storage Personally I'd prefer the second variant, it could look like this: --- ubyte[File.sizeof] _file; ref File file() { return *(cast(File*) &_file[0]); } [create File instance and assign to file] scope (exit) destroy(file); ---
Jul 13
parent reply Moritz Maxeiner <moritz ucworks.org> writes:
On Thursday, 13 July 2017 at 11:15:56 UTC, Moritz Maxeiner wrote:
 ---
 ubyte[File.sizeof] _file;
 ref File file() { return *(cast(File*) &_file[0]); }
 [create File instance and assign to file]
 scope (exit) destroy(file);
 ---
Forgot to add the try catch: --- ubyte[File.sizeof] _file; ref File file() { return *(cast(File*) &_file[0]); } [create File instance and assign to file] scope (exit) try destroy(file) catch (ErrnoException) {}; --- or just --- scope (exit) destroy(file).collectException ---
Jul 13
parent unDEFER <undefer gmail.com> writes:
Thank you. I will write if will find the reason of description 
corruption.
Jul 13