pryrt has asked for the wisdom of the Perl Monks concerning the following question:

I was surprised by my test results on Travis-CI, where my module failed on 5.16, 5.18, and 5.20, but not on the versions above or below those.

Doing some digging, it's because of the way that stat works on an in-memory filehandle: on most versions, it gives a warning in the unopened subcategory of the io warnings category, so I set up my module to trap on that warning, and die with a more meaningful message to the end-user, which should help them avoid the problem. But when it ran on multiple versions on Travis-CI, I found that 5.16-5.20 apparently do not give that (or any) warning, but still result in the empty list for the in-memory filehandle.

The issue can be simply replicated with the one-liner SSCCE (shown in both windows/berrybrew and linux/perlbrew) in the spoiler below.

I found a workaround (see second spoiler below), but I was curious, so I skimmed the perldelta for 5.16 and 5.22, but couldn't find a mention of the unopened-filehandle warning changing in either of those versions. So I guess the wisdom I am seeking: does anyone have insight as to why the warning disappeared in 5.16, but came back in 5.22? Was it intentional (and if so, why try removing it, and why re-instate it)? Or was it an accidental bug (if so, why wasn't it mentioned, or did I just not notice)?

*workaround =

Instead of a custom local $SIG{__WARN__} = sub {...};, I will just check whether defined( $size=(stat($fh))[7] ). The real problem is that another module that I have no control over assumes that (stat($fh))[7] will have a defined $size, and doesn't error check the stat() call, so it later dies because the undefined $size does bad things in their code -- but the die message won't help my end user. By trapping the warning and giving a meaningful die message in my code, I hoped to avoid confusion for the end user. Now, I'll just trap on the definedness of the $size element, so I don't have to worry about the warning staying consistent across perl versions. It also has a side benefit: because of the way I had implemented the trap, I couldn't easily inject a couple of conditions, so I either had to live with ~95% Devel::Cover, or "cheat" with # uncoverable statement / condition comments. With trapping on undef instead, as long as stat returns an empty list when the stat fails so that $size is undef, coverage is much easier to come by.

And thank you: while working on the earlier issues -- figuring out that in-memory filehandle's don't stat right, but give the misleading "unopened filehandle" warning, even though Scalar::Util::openhandle() shows it as open; and trying to get the __WARN__ handler correct -- I thought I was going to need to SoPW, but developing a SSCCE showed me the problem. So thanks for the Rubber duck that you didn't even know you provided, too. :-)

Replies are listed 'Best First'.
Re: stat on in-memory filehandle warns inconsistently across perl versions
by choroba (Archbishop) on Mar 07, 2019 at 17:46 UTC
    Maybe you can first verify that fileno returns -1 for the filehandle, than it must be the in-memory handle.

    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]

      Thanks. I hadn't run across fileno as a way to distinguish the in-memory handles. Great idea.