in reply to Testing for readdir failure

I finally figured out why my script testing on $! after provoked errors produced strange results.

Seems like $! is only correct if it's reset to undef before the error occurs otherwise the last state is used.

I couldn't find any documentation for this behaviour:

These are my results:

------ Error: off --- Reset: off $! 0: --- Reset: on $! 0: --- Reset: off $! 17: File exists --- Reset: on $! 0: --- Reset: off $! 17: File exists --- Reset: on $! 0: ------ Error: on --- Reset: off $! 17: File exists --- Reset: on $! 9: Bad file descriptor --- Reset: off $! 9: Bad file descriptor --- Reset: on $! 9: Bad file descriptor --- Reset: off $! 9: Bad file descriptor --- Reset: on $! 9: Bad file descriptor

use strict; use warnings; $|=1; my $dh; sub tst { my ($mk_error, $reset_errno)=@_; mkdir "/tmp/bla"; opendir $dh, "/tmp/bla" or warn "$!"; rmdir "/tmp/bla" if $mk_error; $!=undef if $reset_errno; my $a= scalar readdir($dh); print "\n\$! ",$!+0,": $!\n" ; } for my $mk_error (0,1) { print "\n\n------ Error: ", (qw(off on))[$mk_error] ; for my $reset_errno (0,1,0,1,0,1) { print "\n--- Reset: ", (qw(off on))[$reset_errno] ; tst($mk_error,$reset_errno) ; } }

would be nice to know if versions > 5.10 show the same problems

perl -version This is perl, v5.10.0 built for i486-linux-gnu-thread-multi

UPDATE
$! 17: File exists stems from former mkdir "/tmp/bla"; where the directory already existed.

Cheers Rolf

( addicted to the Perl Programming Language)

Replies are listed 'Best First'.
Re^2: Testing for readdir failure (Perl-bug)
by Corion (Patriarch) on May 25, 2013 at 08:07 UTC

    perlvar says in the second paragraph about $!:

    Many system or library calls set errno if they fail, to indicate the cause of failure. They usually do not set errno to zero if they succeed. This means errno , hence $! , is meaningful only immediately after a failure:
      yes, but did you notice:

      ------ Error: on --- Reset: off $! 17: File exists

      I included all cases for completeness and to make it easier to find the bug.

      Maybe this is clearer:

      DB<105> $!=666 => "Unknown error 666" DB<106> $!=666;scalar readdir X or warn "$!\n" Unknown error 666 DB<107> $!=undef;scalar readdir X or warn "$!\n" Bad file descriptor

      As you can see $! needs to be reset in advance "to be meaningful".

      Cheers Rolf

      ( addicted to the Perl Programming Language)

        As you can see $! needs to be reset in advance "to be meaningful".

        Yup, logic bug is logic bug :)

        Compare Perl_do_close (called by pp_close ie close ) to pp_readdir

        pp_readdir test errno without localizing, do_close doesn't test errno at all

        closedir has this issue, and probably many others, maybe 40 others

        I wouldn't be surprised if other functions testing errno have this issue too -- this needs explicit testing / reviewing / patching

Re^2: Testing for readdir failure (Perl-bug)
by choroba (Cardinal) on May 25, 2013 at 08:03 UTC
    The same output in 5.16.0.
    لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
Re^2: Testing for readdir failure (Perl-bug)
by Bob Cook (Acolyte) on May 27, 2013 at 21:04 UTC
    I have been following these contributions with interest, but I do not have the C expertise to understand some of it. So I wonder if you could advise me on these questions:

    You now refer to "perlbug errno test without localizing". Could you characterize how this bug shows up at the Perl (as opposed to the C) level? Is the answer just "readdir sometimes throws warnings and sometimes not", or can it be made more explicit?

    In addition to "use warnings", is the following the best I can do for discovering that a problem occurred during a readdir? If not, what would be better?

    $! = undef; @a = readdir(D); if ( defined($!) ) { # Process a readdir error }

    Finally, will this bug modify how "effective" this code is in recognizing the occurrence of an error on the readdir?

    Thanks very much for all your help.

      I can't neither help you on the C-level, Perl source code is very special with all its preprocessor macros.

      (UPDATE. striked nonsense, see reply)

      In the case of readdir the following should help

      $! = undef; @a = readdir(D) or process_errno();

      But in the case of readline it doesn't.

      The other advices I gave you - like catching $SIG{WARN} - are still valid,

      I will post the ticket-link after reporting the perlbug.

      Cheers Rolf

      ( addicted to the Perl Programming Language)

        @a = readdir(D) or process_errno();

        So you are assuming, if for example an I/O error occurs while the directory is being read, that the result of readdir will be an empty (or undefined) directory. Is that guaranteed to be true? It seemed to me that it might instead provide as much of the directory as it successfully read.