Skip to content

Commit

Permalink
readdir() etc: better warning if called on handle open()ed as file
Browse files Browse the repository at this point in the history
  • Loading branch information
tonycoz committed Jul 22, 2024
1 parent 1c8b66f commit 22c16a1
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 40 deletions.
2 changes: 2 additions & 0 deletions embed.fnc
Original file line number Diff line number Diff line change
Expand Up @@ -5086,6 +5086,8 @@ S |OP * |doform |NN CV *cv \
|NULLOK OP *retop
S |SV * |space_join_names_mortal \
|NULLOK char * const *array
S |void |warn_not_dirhandle \
|NN GV *gv
# if !defined(HAS_MKDIR) || !defined(HAS_RMDIR)
RS |int |dooneliner |NN const char *cmd \
|NN const char *filename
Expand Down
1 change: 1 addition & 0 deletions embed.h
Original file line number Diff line number Diff line change
Expand Up @@ -1596,6 +1596,7 @@
# if defined(PERL_IN_PP_SYS_C)
# define doform(a,b,c) S_doform(aTHX_ a,b,c)
# define space_join_names_mortal(a) S_space_join_names_mortal(aTHX_ a)
# define warn_not_dirhandle(a) S_warn_not_dirhandle(aTHX_ a)
# if !defined(HAS_MKDIR) || !defined(HAS_RMDIR)
# define dooneliner(a,b) S_dooneliner(aTHX_ a,b)
# endif
Expand Down
39 changes: 14 additions & 25 deletions pod/perldiag.pod
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,20 @@ version.
(F) A subroutine invoked from an external package via call_sv()
exited by calling exit.

=item %s() attempted on invalid dirhandle %s

(W io) You called readdir(), telldir(), seekdir(), rewinddir() or
closedir() on a handle that has not been opened, or is now closed. A
handle must be successfully opened with opendir() to be used with
these functions. Check your control flow.

=item %s() attempted on handle %s opened with open()

(W io) You called readdir(), telldir(), seekdir(), rewinddir() or
closedir() on a handle that was opened with open(). If you want to
use these functions to traverse the contents of a directory you need
to open the handle with opendir().

=item %s() called too early to check prototype

(W prototype) You've called a function that has a prototype before the
Expand Down Expand Up @@ -1883,11 +1897,6 @@ keyword.

(F) Creating a new thread inside the C<s///> operator is not supported.

=item closedir() attempted on invalid dirhandle %s

(W io) The dirhandle you tried to close is either closed or not really
a dirhandle. Check your control flow.

=item close() on unopened filehandle %s

(W unopened) You tried to close a filehandle that was never opened.
Expand Down Expand Up @@ -5646,11 +5655,6 @@ range, and at least one of the end points is a decimal digit. Under the
stricter rules, when this happens, both end points should be digits in
the same group of 10 consecutive digits.

=item readdir() attempted on invalid dirhandle %s

(W io) The dirhandle you're reading from is either closed or not really
a dirhandle. Check your control flow.

=item readline() on closed filehandle %s

(W closed) The filehandle you're reading from got itself closed sometime
Expand Down Expand Up @@ -5851,11 +5855,6 @@ for the character.
(W syntax) You wrote your assignment operator backwards. The = must
always come last, to avoid ambiguity with subsequent unary operators.

=item rewinddir() attempted on invalid dirhandle %s

(W io) The dirhandle you tried to do a rewinddir() on is either closed
or not really a dirhandle. Check your control flow.

=item Scalars leaked: %d

(S internal) Something went wrong in Perl's internal bookkeeping
Expand Down Expand Up @@ -5905,11 +5904,6 @@ construct, not just the empty search pattern. Therefore code written
in Perl 5.10.0 or later that uses the // as the I<defined-or> can be
misparsed by pre-5.10.0 Perls as a non-terminated search pattern.

=item seekdir() attempted on invalid dirhandle %s

(W io) The dirhandle you are doing a seekdir() on is either closed or not
really a dirhandle. Check your control flow.

=item %sseek() on unopened filehandle

(W unopened) You tried to use the seek() or sysseek() function on a
Expand Down Expand Up @@ -6494,11 +6488,6 @@ know about your kind of stdio. You'll have to use a filename instead.
(F) You tried to use C<goto> to reach a label that was too deeply nested
for Perl to reach. Perl is doing you a favor by refusing.

=item telldir() attempted on invalid dirhandle %s

(W io) The dirhandle you tried to telldir() is either closed or not really
a dirhandle. Check your control flow.

=item tell() on unopened filehandle

(W unopened) You tried to use the tell() function on a filehandle that
Expand Down
37 changes: 22 additions & 15 deletions pp_sys.c
Original file line number Diff line number Diff line change
Expand Up @@ -4285,6 +4285,23 @@ PP_wrapped(pp_open_dir, 2, 0)
#endif
}

static void
S_warn_not_dirhandle(pTHX_ GV *gv) {
IO *io = GvIOn(gv);

if (IoIFP(io)) {
Perl_ck_warner(aTHX_ packWARN(WARN_IO),
"%s() attempted on handle %" HEKf
" opened with open()",
OP_DESC(PL_op), HEKfARG(GvENAME_HEK(gv)));
}
else {
Perl_ck_warner(aTHX_ packWARN(WARN_IO),
"%s() attempted on invalid dirhandle %" HEKf,
OP_DESC(PL_op), HEKfARG(GvENAME_HEK(gv)));
}
}

PP_wrapped(pp_readdir, 1, 0)
{
#if !defined(Direntry_t) || !defined(HAS_READDIR)
Expand All @@ -4302,9 +4319,7 @@ PP_wrapped(pp_readdir, 1, 0)
IO * const io = GvIOn(gv);

if (!IoDIRP(io)) {
Perl_ck_warner(aTHX_ packWARN(WARN_IO),
"readdir() attempted on invalid dirhandle %" HEKf,
HEKfARG(GvENAME_HEK(gv)));
warn_not_dirhandle(gv);
goto nope;
}

Expand Down Expand Up @@ -4352,9 +4367,7 @@ PP_wrapped(pp_telldir, 1, 0)
IO * const io = GvIOn(gv);

if (!IoDIRP(io)) {
Perl_ck_warner(aTHX_ packWARN(WARN_IO),
"telldir() attempted on invalid dirhandle %" HEKf,
HEKfARG(GvENAME_HEK(gv)));
warn_not_dirhandle(gv);
goto nope;
}

Expand All @@ -4378,9 +4391,7 @@ PP_wrapped(pp_seekdir, 2, 0)
IO * const io = GvIOn(gv);

if (!IoDIRP(io)) {
Perl_ck_warner(aTHX_ packWARN(WARN_IO),
"seekdir() attempted on invalid dirhandle %" HEKf,
HEKfARG(GvENAME_HEK(gv)));
warn_not_dirhandle(gv);
goto nope;
}
(void)PerlDir_seek(IoDIRP(io), along);
Expand All @@ -4403,9 +4414,7 @@ PP_wrapped(pp_rewinddir, 1, 0)
IO * const io = GvIOn(gv);

if (!IoDIRP(io)) {
Perl_ck_warner(aTHX_ packWARN(WARN_IO),
"rewinddir() attempted on invalid dirhandle %" HEKf,
HEKfARG(GvENAME_HEK(gv)));
warn_not_dirhandle(gv);
goto nope;
}
(void)PerlDir_rewind(IoDIRP(io));
Expand All @@ -4427,9 +4436,7 @@ PP_wrapped(pp_closedir, 1, 0)
IO * const io = GvIOn(gv);

if (!IoDIRP(io)) {
Perl_ck_warner(aTHX_ packWARN(WARN_IO),
"closedir() attempted on invalid dirhandle %" HEKf,
HEKfARG(GvENAME_HEK(gv)));
warn_not_dirhandle(gv);
goto nope;
}
#ifdef VOID_CLOSEDIR
Expand Down
5 changes: 5 additions & 0 deletions proto.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 28 additions & 0 deletions t/op/readdir.t
Original file line number Diff line number Diff line change
Expand Up @@ -86,4 +86,32 @@ SKIP:
is($errno, 0, "errno preserved");
}

SKIP:
{
open my $fh, "<", "op"
or skip "can't open a directory on this platform", 10;
my $warned;
local $SIG{__WARN__} = sub { $warned = "@_" };
ok(!readdir($fh), "cannot readdir file handle");
like($warned, qr/readdir\(\) attempted on handle \$fh opened with open/,
"check the message");
undef $warned;
ok(!telldir($fh), "cannot telldir file handle");
like($warned, qr/telldir\(\) attempted on handle \$fh opened with open/,
"check the message");
undef $warned;
ok(!seekdir($fh, 0), "cannot seekdir file handle");
like($warned, qr/seekdir\(\) attempted on handle \$fh opened with open/,
"check the message");
undef $warned;
ok(!rewinddir($fh), "cannot rewinddir file handle");
like($warned, qr/rewinddir\(\) attempted on handle \$fh opened with open/,
"check the message");
undef $warned;
ok(!closedir($fh), "cannot closedir file handle");
like($warned, qr/closedir\(\) attempted on handle \$fh opened with open/,
"check the message");
undef $warned;
}

done_testing();

0 comments on commit 22c16a1

Please sign in to comment.