Thread overview
Bad file descriptor in File destructor
Jul 13, 2017
unDEFER
Jul 13, 2017
unDEFER
Jul 13, 2017
unDEFER
Jul 13, 2017
Moritz Maxeiner
Jul 13, 2017
Moritz Maxeiner
Jul 13, 2017
unDEFER
Jul 13, 2017
Moritz Maxeiner
Jul 13, 2017
Moritz Maxeiner
Jul 13, 2017
unDEFER
July 13, 2017
Hello! I have the code like this:

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

...
    try {

    }
July 13, 2017
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!
July 13, 2017
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).
July 13, 2017
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.
July 13, 2017
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;
}


July 13, 2017
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);
---
July 13, 2017
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
---
July 13, 2017
Thank you. I will write if will find the reason of description corruption.
July 13, 2017
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