This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
[perl #125305] handle chdir to closed handle correctly
authorTony Cook <tony@develop-help.com>
Thu, 25 Jun 2015 03:58:57 +0000 (13:58 +1000)
committerTony Cook <tony@develop-help.com>
Mon, 29 Jun 2015 00:56:34 +0000 (10:56 +1000)
pod/perldiag.pod
pp_sys.c
t/op/chdir.t

index 9d048cf..6ac8ee8 100644 (file)
@@ -1559,6 +1559,10 @@ defined in the C<:alias> import argument to C<use charnames>, but they
 could be defined by a translator installed into C<$^H{charnames}>.
 See L<charnames/CUSTOM ALIASES>.
 
+=item chdir() on unopened filehandle %s
+
+(W unopened) You tried chdir() on a filehandle that was never opened.
+
 =item \C no longer supported in regex; marked by S<<-- HERE> in m/%s/
 
 (F) The \C character class used to allow a match of single byte within a
index 78d9584..da25f0f 100644 (file)
--- a/pp_sys.c
+++ b/pp_sys.c
@@ -3599,6 +3599,16 @@ PP(pp_chdir)
        SV * const sv = POPs;
        if (PL_op->op_flags & OPf_SPECIAL) {
            gv = gv_fetchsv(sv, 0, SVt_PVIO);
+            if (!gv) {
+                if (ckWARN(WARN_UNOPENED)) {
+                    Perl_warner(aTHX_ packWARN(WARN_UNOPENED),
+                                "chdir() on unopened filehandle %" SVf, sv);
+                }
+                SETERRNO(EBADF,RMS_IFI);
+                PUSHi(0);
+                TAINT_PROPER("chdir");
+                RETURN;
+            }
        }
         else if (!(gv = MAYBE_DEREF_GV(sv)))
                tmps = SvPV_nomg_const_nolen(sv);
index e2e5429..8a4c49c 100644 (file)
@@ -10,11 +10,11 @@ BEGIN {
     # possibilities into @INC.
     unshift @INC, qw(t . lib ../lib);
     require "./test.pl";
-    plan(tests => 39);
+    plan(tests => 44);
 }
 
 use Config;
-use Errno qw(ENOENT);
+use Errno qw(ENOENT EBADF);
 
 my $IsVMS   = $^O eq 'VMS';
 
@@ -54,7 +54,7 @@ SKIP: {
 $Cwd = abs_path;
 
 SKIP: {
-    skip("no fchdir", 16) unless $has_fchdir;
+    skip("no fchdir", 21) unless $has_fchdir;
     my $has_dirfd = ($Config{d_dirfd} || $Config{d_dir_dd_fd} || "") eq "define";
     ok(opendir(my $dh, "."), "opendir .");
     ok(open(my $fh, "<", "op"), "open op");
@@ -107,6 +107,13 @@ SKIP: {
     ok(closedir(H), "closedir");
     ok(chdir(H), "fchdir to base");
     ok(-f "cond.t", "verify that we are in 'base'");
+    ok(close(H), "close");
+    $! = 0;
+    ok(!chdir(H), "check we can't chdir to closed handle");
+    is(0+$!, EBADF, 'check $! set appropriately');
+    $! = 0;
+    ok(!chdir(NEVEROPENED), "check we can't chdir to never opened handle");
+    is(0+$!, EBADF, 'check $! set appropriately');
     chdir ".." or die $!;
 }