Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cwd's pure perl abs_path and its test disagree on what's ok #11931

Open
p5pRT opened this issue Feb 4, 2012 · 14 comments
Open

Cwd's pure perl abs_path and its test disagree on what's ok #11931

p5pRT opened this issue Feb 4, 2012 · 14 comments

Comments

@p5pRT
Copy link

p5pRT commented Feb 4, 2012

Migrated from rt.perl.org#109760 (status was 'open')

Searchable as RT109760$

@p5pRT
Copy link
Author

p5pRT commented Feb 4, 2012

From @ikegami

Created by @ikegami

[ Applies to 5.10.1, 5.12.2, 5.14.2, blead, etc ]

Whenever I build Perl on my web host, I get a failure in Cwd.

# Failed test at t/cwd.t line 209.
#
'/home/ikegami/usr/perlbrew/build/perl-5.14.2/dist/Cwd/t/linktest'
# doesn't match
'(?^i​:\/home\/ikegami\/usr\/perlbrew\/build\/perl\-5\.14\.2\/dist\/Cwd\/t\/_ptrslt_\/_path_\/_to_\/_a_\/_dir_$)'
# Looks like you failed 1 test of 34.
../dist/Cwd/t/cwd.t ...............................................
Dubious, test returned 1 (wstat 256, 0x100)
Failed 1/34 subtests
  (less 1 skipped subtest​: 32 okay)

C<abs_path> is a function that returns an absolute path with symbolic links
resolved. The failing check tests a pure perl version of abs_path called
C<_perl_abs_path>. The pure perl version does not resolve symlinks if any
ancestor of the symlink's target directory cannot be read, and /home cannot
be read on my web host.

You can test this yourself using the attached script (extracted from cwd.t)
and C<< chmod u-r .. >>.

I don't know if C<_perl_abs_path> should croak or if the test shouldn't
fail, but they currently disagree as to what is acceptable, forcing me to
force install Perl every time. This is especially silly since
C<_perl_abs_path> is only used when "the XS version doesn't load"
(according to a comment).

- Eric

Perl Info

Flags:
    category=library
    severity=low
    module=Cwd

Site configuration information for perl 5.10.1:

Configured by Debian Project at Wed Dec 21 09:13:32 UTC 2011.

Summary of my perl5 (revision 5 version 10 subversion 1) configuration:

  Platform:
    osname=linux, osvers=2.6.32-5-amd64,
archname=x86_64-linux-gnu-thread-multi
    uname='linux barber 2.6.32-5-amd64 #1 smp thu nov 3 03:41:26 utc 2011
x86_64 gnulinux '
    config_args='-Dusethreads -Duselargefiles -Dccflags=-DDEBIAN
-Dcccdlflags=-fPIC -Darchname=x86_64-linux-gnu -Dprefix=/usr
-Dprivlib=/usr/share/perl/5.10 -Darchlib=/usr/lib/perl/5.10
-Dvendorprefix=/usr -Dvendorlib=/usr/share/perl5
-Dvendorarch=/usr/lib/perl5 -Dsiteprefix=/usr/local
-Dsitelib=/usr/local/share/perl/5.10.1
-Dsitearch=/usr/local/lib/perl/5.10.1 -Dman1dir=/usr/share/man/man1
-Dman3dir=/usr/share/man/man3 -Dsiteman1dir=/usr/local/man/man1
-Dsiteman3dir=/usr/local/man/man3 -Dman1ext=1 -Dman3ext=3perl
-Dpager=/usr/bin/sensible-pager -Uafs -Ud_csh -Ud_ualarm -Uusesfio -Uusenm
-DDEBUGGING=-g -Doptimize=-O2 -Duseshrplib -Dlibperl=libperl.so.5.10.1
-Dd_dosuid -des'
    hint=recommended, useposix=true, d_sigaction=define
    useithreads=define, usemultiplicity=define
    useperlio=define, d_sfio=undef, uselargefiles=define, usesocks=undef
    use64bitint=define, use64bitall=define, uselongdouble=undef
    usemymalloc=n, bincompat5005=undef
  Compiler:
    cc='cc', ccflags ='-D_REENTRANT -D_GNU_SOURCE -DDEBIAN
-fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include
-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64',
    optimize='-O2 -g',
    cppflags='-D_REENTRANT -D_GNU_SOURCE -DDEBIAN -fno-strict-aliasing
-pipe -fstack-protector -I/usr/local/include'
    ccversion='', gccversion='4.4.5', gccosandvers=''
    intsize=4, longsize=8, ptrsize=8, doublesize=8, byteorder=12345678
    d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=16
    ivtype='long', ivsize=8, nvtype='double', nvsize=8, Off_t='off_t',
lseeksize=8
    alignbytes=8, prototype=define
  Linker and Libraries:
    ld='cc', ldflags =' -fstack-protector -L/usr/local/lib'
    libpth=/usr/local/lib /lib /usr/lib /lib64 /usr/lib64
    libs=-lgdbm -lgdbm_compat -ldb -ldl -lm -lpthread -lc -lcrypt
    perllibs=-ldl -lm -lpthread -lc -lcrypt
    libc=/lib/libc-2.11.3.so, so=so, useshrplib=true,
libperl=libperl.so.5.10.1
    gnulibc_version='2.11.3'
  Dynamic Linking:
    dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-Wl,-E'
    cccdlflags='-fPIC', lddlflags='-shared -O2 -g -L/usr/local/lib
-fstack-protector'

Locally applied patches:
    DEBPKG:debian/arm_thread_stress_timeout -
http://bugs.debian.org/501970Raise the timeout of
ext/threads/shared/t/stress.t to accommodate slower
build hosts
    DEBPKG:debian/cpan_config_path - Set location of CPAN::Config to
/etc/perl as /usr may not be writable.
    DEBPKG:debian/cpan_definstalldirs - Provide a sensible INSTALLDIRS
default for modules installed from CPAN.
    DEBPKG:debian/db_file_ver - http://bugs.debian.org/340047 Remove overly
restrictive DB_File version check.
    DEBPKG:debian/doc_info - Replace generic man(1) instructions with
Debian-specific information.
    DEBPKG:debian/enc2xs_inc - http://bugs.debian.org/290336 Tweak enc2xs
to follow symlinks and ignore missing @INC directories.
    DEBPKG:debian/errno_ver - http://bugs.debian.org/343351 Remove Errno
version check due to upgrade problems with long-running processes.
    DEBPKG:debian/extutils_hacks - Various debian-specific ExtUtils changes
    DEBPKG:debian/fakeroot - Postpone LD_LIBRARY_PATH evaluation to the
binary targets.
    DEBPKG:debian/instmodsh_doc - Debian policy doesn't install .packlist
files for core or vendor.
    DEBPKG:debian/ld_run_path - Remove standard libs from LD_RUN_PATH as
per Debian policy.
    DEBPKG:debian/libnet_config_path - Set location of libnet.cfg to
/etc/perl/Net as /usr may not be writable.
    DEBPKG:debian/m68k_thread_stress -
http://bugs.debian.org/495826Disable some threads tests on m68k for
now due to missing TLS.
    DEBPKG:debian/mod_paths - Tweak @INC ordering for Debian
    DEBPKG:debian/module_build_man_extensions -
http://bugs.debian.org/479460 Adjust Module::Build manual page extensions
for the Debian Perl policy
    DEBPKG:debian/perl_synopsis - http://bugs.debian.org/278323 Rearrange
perl.pod
    DEBPKG:debian/prune_libs - http://bugs.debian.org/128355 Prune the list
of libraries wanted to what we actually need.
    DEBPKG:debian/use_gdbm - Explicitly link against -lgdbm_compat in
ODBM_File/NDBM_File.
    DEBPKG:fixes/assorted_docs - http://bugs.debian.org/443733 [384f06a]
Math::BigInt::CalcEmu documentation grammar fix
    DEBPKG:fixes/net_smtp_docs - http://bugs.debian.org/100195
[rt.cpan.org#36038] Document the Net::SMTP 'Port' option
    DEBPKG:fixes/processPL - http://bugs.debian.org/357264
[rt.cpan.org#17224] Always use PERLRUNINST when building perl modules.
    DEBPKG:debian/perlivp - http://bugs.debian.org/510895 Make perlivp skip
include directories in /usr/local
    DEBPKG:fixes/pod2man-index-backslash -
http://bugs.debian.org/521256Escape backslashes in .IX entries
    DEBPKG:debian/disable-zlib-bundling - Disable zlib bundling in
Compress::Raw::Zlib
    DEBPKG:fixes/kfreebsd_cppsymbols -
http://bugs.debian.org/533098[3b910a0] Add gcc predefined macros to
$Config{cppsymbols} on GNU/kFreeBSD.
    DEBPKG:debian/cpanplus_definstalldirs -
http://bugs.debian.org/533707Configure CPANPLUS to use the site
directories by default.
    DEBPKG:debian/cpanplus_config_path - Save local versions of
CPANPLUS::Config::System into /etc/perl.
    DEBPKG:fixes/kfreebsd-filecopy-pipes -
http://bugs.debian.org/537555[16f708c] Fix File::Copy::copy with pipes
on GNU/kFreeBSD
    DEBPKG:fixes/anon-tmpfile-dir - http://bugs.debian.org/528544 [perl
#66452] Honor TMPDIR when open()ing an anonymous temporary file
    DEBPKG:fixes/abstract-sockets - http://bugs.debian.org/329291 [89904c0]
Add support for Abstract namespace sockets.
    DEBPKG:fixes/hurd_cppsymbols - http://bugs.debian.org/544307 [eeb92b7]
Add gcc predefined macros to $Config{cppsymbols} on GNU/Hurd.
    DEBPKG:fixes/autodie-flock - http://bugs.debian.org/543731 Allow for
flock returning EAGAIN instead of EWOULDBLOCK on linux/parisc
    DEBPKG:fixes/archive-tar-instance-error - http://bugs.debian.org/539355[
rt.cpan.org #48879] Separate Archive::Tar instance error strings from each
other
    DEBPKG:fixes/positive-gpos - http://bugs.debian.org/545234 [perl
#69056] [c584a96] Fix \\G crash on first match
    DEBPKG:debian/devel-ppport-ia64-optim -
http://bugs.debian.org/548943Work around an ICE on ia64
    DEBPKG:fixes/trie-logic-match - http://bugs.debian.org/552291 [perl
#69973] [0abd0d7] Fix a DoS in Unicode processing [CVE-2009-3626]
    DEBPKG:fixes/hppa-thread-eagain - http://bugs.debian.org/554218 make
the threads-shared test suite more robust, fixing failures on hppa
    DEBPKG:fixes/crash-on-undefined-destroy -
http://bugs.debian.org/564074[perl #71952] [1f15e67] Fix a NULL
pointer dereference when looking for a
DESTROY method
    DEBPKG:fixes/tainted-errno - http://bugs.debian.org/574129 [perl
#61976] [be1cf43] fix an errno stringification bug in taint mode
    DEBPKG:fixes/safe-upgrade - http://bugs.debian.org/582978 Upgrade
Safe.pm to 2.25, fixing CVE-2010-1974
    DEBPKG:fixes/tell-crash - http://bugs.debian.org/578577 [f4817f3] Fix a
tell() crash on bad arguments.
    DEBPKG:fixes/format-write-crash - http://bugs.debian.org/579537 [perl
#22977] [421f30e] Fix a crash in format/write
    DEBPKG:fixes/arm-alignment - http://bugs.debian.org/289884 [f1c7503]
Prevent gcc from optimizing the alignment test away on armel
    DEBPKG:fixes/fcgi-test - Fix a failure in CGI/t/fast.t when FCGI is
installed
    DEBPKG:fixes/hurd-ccflags - http://bugs.debian.org/587901 Make
hints/gnu.sh append to $ccflags rather than overriding them
    DEBPKG:debian/squelch-locale-warnings -
http://bugs.debian.org/508764Squelch locale warnings in Debian package
maintainer scripts
    DEBPKG:fixes/lc-numeric-docs - http://bugs.debian.org/379329 [perl
#78452] [903eb63] LC_NUMERIC documentation fixes
    DEBPKG:fixes/lc-numeric-sprintf - http://bugs.debian.org/601549 [perl
#78632] [b3fd614] Fix sprintf not to ignore LC_NUMERIC with constants
    DEBPKG:fixes/concat-stack-corruption -
http://bugs.debian.org/596105[perl #78674] [e3393f5] Fix stack pointer
corruption in pp_concat() with
'use encoding'
    DEBPKG:fixes/cgi-multiline-header -
http://bugs.debian.org/606995[CVE-2010-2761 CVE-2010-4410
CVE-2010-4411] CGI.pm MIME boundary and
multiline header vulnerabilities
    DEBPKG:fixes/casing-taint-cve-2011-1487 -
http://bugs.debian.org/622817[perl #87336] fix unwanted taint
laundering in lc(), uc() et al.
    DEBPKG:fixes/safe-reval-rdo-cve-2010-1447 - [PATCH] Wrap by default
coderefs returned by rdo and reval
    DEBPKG:fixes/encode-heap-overflow - [PATCH] Fix decode_xs n-byte
heap-overflow security bug in
    DEBPKG:fixes/digest_eval_hole - Close the eval \"require $module\"
security hole in
    DEBPKG:fixes/unregister_signal_handler - [PATCH] main: Unregister
signal handler before destroying my_perl
    DEBPKG:patchlevel - http://bugs.debian.org/567489 List packaged patches
for 5.10.1-17squeeze3 in patchlevel.h


@INC for perl 5.10.1:
    /etc/perl
    /usr/local/lib/perl/5.10.1
    /usr/local/share/perl/5.10.1
    /usr/lib/perl5
    /usr/share/perl5
    /usr/lib/perl/5.10
    /usr/share/perl/5.10
    /usr/local/lib/site_perl
    .


Environment for perl 5.10.1:
    HOME=/home/ikegami
    LANG=en_US.UTF-8
    LANGUAGE (unset)
    LC_COLLATE=C
    LD_LIBRARY_PATH (unset)
    LOGDIR (unset)

PATH=/home/ikegami/usr/perlbrew/bin:.:/home/ikegami/bin:/home/ikegami/.gems/bin:/usr/lib/ruby/gems/1.8/bin/:/usr/local/bin:/usr/bin:/bin:/usr/bin/X11:/usr/games
    PERLBREW_BASHRC_VERSION=0.41
    PERLBREW_HOME=/home/ikegami/.perlbrew
    PERLBREW_PATH=/home/ikegami/usr/perlbrew/bin
    PERLBREW_ROOT=/home/ikegami/usr/perlbrew
    PERL_BADLANG (unset)
    SHELL=/bin/bash

@p5pRT
Copy link
Author

p5pRT commented Feb 4, 2012

From @ikegami

On Fri, Feb 3, 2012 at 10​:03 PM, Eric Brine <perlbug-followup@​perl.org>wrote​:

You can test this yourself using the attached script (extracted from cwd.t)
and C<< chmod u-r .. >>.

Oops, now attached.

@p5pRT
Copy link
Author

p5pRT commented Feb 4, 2012

From @ikegami

cwdtest.pl

@p5pRT
Copy link
Author

p5pRT commented Feb 24, 2013

From @jkeenan

On Fri Feb 03 19​:03​:14 2012, ikegami@​adaelis.com wrote​:

This is a bug report for perl from ikegami@​adaelis.com,
generated with the help of perlbug 1.39 running under perl 5.10.1.

-----------------------------------------------------------------
[Please describe your issue here]

[ Applies to 5.10.1, 5.12.2, 5.14.2, blead, etc ]

Whenever I build Perl on my web host, I get a failure in Cwd.

# Failed test at t/cwd.t line 209.
#
'/home/ikegami/usr/perlbrew/build/perl-5.14.2/dist/Cwd/t/linktest'
# doesn't match
'(?^i​:\/home\/ikegami\/usr\/perlbrew\/build\/perl\-
5\.14\.2\/dist\/Cwd\/t\/_ptrslt_\/_path_\/_to_\/_a_\/_dir_$)'
# Looks like you failed 1 test of 34.
../dist/Cwd/t/cwd.t ...............................................
Dubious, test returned 1 (wstat 256, 0x100)
Failed 1/34 subtests
(less 1 skipped subtest​: 32 okay)

C<abs_path> is a function that returns an absolute path with symbolic
links
resolved. The failing check tests a pure perl version of abs_path
called
C<_perl_abs_path>. The pure perl version does not resolve symlinks if
any
ancestor of the symlink's target directory cannot be read, and /home
cannot
be read on my web host.

You can test this yourself using the attached script (extracted from
cwd.t)
and C<< chmod u-r .. >>.

I don't know if C<_perl_abs_path> should croak or if the test
shouldn't
fail, but they currently disagree as to what is acceptable, forcing me
to
force install Perl every time. This is especially silly since
C<_perl_abs_path> is only used when "the XS version doesn't load"
(according to a comment).

- Eric

I get your point, but when I tried to replicate the problem on my
machine in a slightly modified manner, I got a result that suggested a
problem in Cwd​::abs_path() *even before* looking at Cwd​::_perl_abs_path().

I split your test file into two separate programs so that I could create
the test directories, then modify the directory permissions as you
suggested, then create the symlink and run the second program, which was
essentially the remainder of yours. Both files are attached.

In 'a_109760_cwdtest.pl', I remove the test directories and symlink if
they're still present from a previous run, then create the test directories.

In the first pass, I leave directory permissions untouched and run
'b_109760_cwdtest.pl', which creates the symlinks, performs tests (which
all pass), and then cleans up after itself.

The output is therefore​:
#########
$ prove -v a_109760_cwdtest.pl
a_109760_cwdtest.pl ..
ok 1 - mkpath created expected number of directories
1..1
ok
All tests successful.
Files=1, Tests=1, 1 wallclock secs ( 0.12 usr 0.03 sys + 0.14 cusr
0.04 csys = 0.33 CPU)
Result​: PASS

$ prove -v b_109760_cwdtest.pl
b_109760_cwdtest.pl ..
ok 1 - symlink to test_dir created
# abs_path​: /Users/jimk/learn/perl/p5p/_ptrslt_/_path_/_to_/_a_/_dir_
ok 2 - Cwd​::abs_path matches File​::Spec->rel2abs
ok 3 - Cwd​::fast_abs_path matches File​::Spec->rel2abs
ok 4 - Cwd​::_perl_abs_path matches File​::Spec->rel2abs
1..4
ok
All tests successful.
Files=1, Tests=4, 0 wallclock secs ( 0.12 usr 0.04 sys + 0.15 cusr
0.07 csys = 0.38 CPU)
Result​: PASS
##########

In the second pass, I run the first program, then chmod u-r .., then run
the second program. This time, the output is​:

##########
$ prove -v a_109760_cwdtest.pl
a_109760_cwdtest.pl ..
ok 1 - mkpath created expected number of directories
1..1
ok
All tests successful.
Files=1, Tests=1, 0 wallclock secs ( 0.12 usr 0.04 sys + 0.13 cusr
0.04 csys = 0.33 CPU)
Result​: PASS

$ chmod u-r ..

$ prove -v b_109760_cwdtest.pl
b_109760_cwdtest.pl ..
ok 1 - symlink to test_dir created
# abs_path​:
Use of uninitialized value $abs_path in concatenation (.) or string at
b_109760_cwdtest.pl line 21.
Cannot chdir back to : No such file or directory at b_109760_cwdtest.pl
line 22.

1..1
# Looks like your test exited with 255 just after 1.
Dubious, test returned 255 (wstat 65280, 0xff00)
All 1 subtests passed

Test Summary Report


b_109760_cwdtest.pl (Wstat​: 65280 Tests​: 1 Failed​: 0)
  Non-zero exit status​: 255
Files=1, Tests=1, 0 wallclock secs ( 0.12 usr 0.04 sys + 0.14 cusr
0.04 csys = 0.34 CPU)
Result​: FAIL
############

I read this as saying that, once the higher directory had been rendered
unreadable, the call to Cwd​::abs_path() at line 20 essentially failed;
it returned an undefined value.

#########
  20 my $abs_path = Cwd​::abs_path($file);
  21 note("abs_path​: $abs_path");
#########

So I doubt the problem is *only* in Cwd​::_perl_abs_path().

Thank you very much.
Jim Keenan

@p5pRT
Copy link
Author

p5pRT commented Feb 24, 2013

From @jkeenan

a_109760_cwdtest.pl

@p5pRT
Copy link
Author

p5pRT commented Feb 24, 2013

From @jkeenan

b_109760_cwdtest.pl

@p5pRT
Copy link
Author

p5pRT commented Feb 24, 2013

The RT System itself - Status changed from 'new' to 'open'

@p5pRT
Copy link
Author

p5pRT commented Jun 13, 2013

From gottreu@gmail.com

This is a bug report for perl from gottreu@​gmail.com,
generated with the help of perlbug 1.39 running under perl 5.19.1.

From 5f28c1a5e9dd996eeec4fc4aade74a400a3af87e Mon Sep 17 00​:00​:00 2001
From​: Brian Gottreu <gottreu@​gmail.com>
Date​: Thu, 13 Jun 2013 14​:33​:36 -0500
Subject​: [PATCH] Skip _perl_abs_path() tests when they will fail with no ill
effects
MIME-Version​: 1.0
Content-Type​: multipart/mixed; boundary="------------1.7.10.4"

This is a multi-part message in MIME format.
--------------1.7.10.4
Content-Type​: text/plain; charset=UTF-8; format=fixed
Content-Transfer-Encoding​: 8bit


AUTHORS | 1 +
dist/Cwd/t/cwd.t | 11 +++++++++++
2 files changed, 12 insertions(+)

--------------1.7.10.4
Content-Type​: text/x-patch; name="0001-Skip-_perl_abs_path-tests-when-they-will-fail-with-n.patch"
Content-Transfer-Encoding​: 8bit
Content-Disposition​: attachment; filename="0001-Skip-_perl_abs_path-tests-when-they-will-fail-with-n.patch"

Inline Patch
diff --git a/AUTHORS b/AUTHORS
index 44f52e2..b00e7e5 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -163,6 +163,7 @@ Brian Carlson			<brian.carlson@cpanel.net>
 Brian Clarke			<clarke@appliedmeta.com>
 brian d foy			<brian.d.foy@gmail.com>
 Brian Fraser			<fraserbn@gmail.com>
+Brian Gottreu			<gottreu@gmail.com>
 Brian Greenfield		<briang@cpan.org>
 Brian Grossman
 Brian Harrison			<brie@corp.home.net>
diff --git a/dist/Cwd/t/cwd.t b/dist/Cwd/t/cwd.t
index f7b03ed..3c83855 100644
--- a/dist/Cwd/t/cwd.t
+++ b/dist/Cwd/t/cwd.t
@@ -40,6 +40,17 @@ my $tests = 31;
 # _perl_abs_path() currently only works when the directory separator
 # is '/', so don't test it when it won't work.
 my $EXTRA_ABSPATH_TESTS = ($Config{prefix} =~ m/\//) && $^O ne 'cygwin';
+# _perl_abs_path() uses readdir() on all the directories in the path
+# passed to it.  If perl is built under /home (for example) and /home is
+# set to executable but not readable, then the extra abspath tests will
+# fail even though the perl built is perfectly fine.
+if($EXTRA_ABSPATH_TESTS) {
+    my @dirs = File::Spec->splitdir(cwd());
+    for(0..$#dirs) {
+        my $parent_dir = File::Spec->catdir(@dirs[0..$_]);
+        $EXTRA_ABSPATH_TESTS = 0 unless -r $parent_dir;
+    }
+}
 $tests += 4 if $EXTRA_ABSPATH_TESTS;
 plan tests => $tests;
 

--------------1.7.10.4--


---
Flags:   category=core   severity=low

Site configuration information for perl 5.19.1​:

Configured by gottreu at Thu Jun 13 11​:58​:47 CDT 2013.

Summary of my perl5 (revision 5 version 19 subversion 1) configuration​:
  Commit id​: 6b28e74
  Platform​:
  osname=linux, osvers=3.2.0-4-amd64, archname=x86_64-linux
  uname='linux frylock 3.2.0-4-amd64 #1 smp debian 3.2.39-2 x86_64 gnulinux '
  config_args='-des -Dprefix=/home/gottreu/devperl -Dusedevel'
  hint=recommended, useposix=true, d_sigaction=define
  useithreads=undef, usemultiplicity=undef
  useperlio=define, d_sfio=undef, uselargefiles=define, usesocks=undef
  use64bitint=define, use64bitall=define, uselongdouble=undef
  usemymalloc=n, bincompat5005=undef
  Compiler​:
  cc='cc', ccflags ='-fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64',
  optimize='-O2',
  cppflags='-fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include'
  ccversion='', gccversion='4.7.2', gccosandvers=''
  intsize=4, longsize=8, ptrsize=8, doublesize=8, byteorder=12345678
  d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=16
  ivtype='long', ivsize=8, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8
  alignbytes=8, prototype=define
  Linker and Libraries​:
  ld='cc', ldflags =' -fstack-protector -L/usr/local/lib'
  libpth=/usr/local/lib /lib/x86_64-linux-gnu /lib/../lib /usr/lib/x86_64-linux-gnu /usr/lib/../lib /lib /usr/lib
  libs=-lnsl -lgdbm -ldb -ldl -lm -lcrypt -lutil -lc -lgdbm_compat
  perllibs=-lnsl -ldl -lm -lcrypt -lutil -lc
  libc=, so=so, useshrplib=false, libperl=libperl.a
  gnulibc_version='2.13'
  Dynamic Linking​:
  dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-Wl,-E'
  cccdlflags='-fPIC', lddlflags='-shared -O2 -L/usr/local/lib -fstack-protector'

Locally applied patches​:
 


@​INC for perl 5.19.1​:
  /home/gottreu/devperl/lib/site_perl/5.19.1/x86_64-linux
  /home/gottreu/devperl/lib/site_perl/5.19.1
  /home/gottreu/devperl/lib/5.19.1/x86_64-linux
  /home/gottreu/devperl/lib/5.19.1
  .


Environment for perl 5.19.1​:
  HOME=/home/gottreu
  LANG=en_US.UTF-8
  LANGUAGE (unset)
  LD_LIBRARY_PATH (unset)
  LOGDIR (unset)
  PATH=/home/gottreu/bin​:/home/gottreu/bin​:/usr/local/bin​:/usr/bin​:/bin​:/usr/local/games​:/usr/games
  PERL_BADLANG (unset)
  SHELL=/bin/bash

@p5pRT
Copy link
Author

p5pRT commented Jun 14, 2013

From @jkeenan

On Thu Jun 13 13​:10​:46 2013, gottreu wrote​:

This is a bug report for perl from gottreu@​gmail.com,
generated with the help of perlbug 1.39 running under perl 5.19.1.

From 5f28c1a5e9dd996eeec4fc4aade74a400a3af87e Mon Sep 17 00​:00​:00 2001
From​: Brian Gottreu <gottreu@​gmail.com>
Date​: Thu, 13 Jun 2013 14​:33​:36 -0500
Subject​: [PATCH] Skip _perl_abs_path() tests when they will fail with
no ill
effects
MIME-Version​: 1.0
Content-Type​: multipart/mixed; boundary="------------1.7.10.4"

This is a multi-part message in MIME format.
--------------1.7.10.4
Content-Type​: text/plain; charset=UTF-8; format=fixed
Content-Transfer-Encoding​: 8bit

---
AUTHORS | 1 +
dist/Cwd/t/cwd.t | 11 +++++++++++
2 files changed, 12 insertions(+)

--------------1.7.10.4
Content-Type​: text/x-patch; name="0001-Skip-_perl_abs_path-tests-when-
they-will-fail-with-n.patch"
Content-Transfer-Encoding​: 8bit
Content-Disposition​: attachment; filename="0001-Skip-_perl_abs_path-
tests-when-they-will-fail-with-n.patch"

diff --git a/AUTHORS b/AUTHORS
index 44f52e2..b00e7e5 100644
--- a/AUTHORS
+++ b/AUTHORS
@​@​ -163,6 +163,7 @​@​ Brian Carlson <brian.carlson@​cpanel.net>
Brian Clarke <clarke@​appliedmeta.com>
brian d foy <brian.d.foy@​gmail.com>
Brian Fraser <fraserbn@​gmail.com>
+Brian Gottreu <gottreu@​gmail.com>
Brian Greenfield <briang@​cpan.org>
Brian Grossman
Brian Harrison <brie@​corp.home.net>
diff --git a/dist/Cwd/t/cwd.t b/dist/Cwd/t/cwd.t
index f7b03ed..3c83855 100644
--- a/dist/Cwd/t/cwd.t
+++ b/dist/Cwd/t/cwd.t
@​@​ -40,6 +40,17 @​@​ my $tests = 31;
# _perl_abs_path() currently only works when the directory separator
# is '/', so don't test it when it won't work.
my $EXTRA_ABSPATH_TESTS = ($Config{prefix} =~ m/\//) &amp;&amp; $^O ne
'cygwin';
+# _perl_abs_path() uses readdir() on all the directories in the path
+# passed to it. If perl is built under /home (for example) and /home
is
+# set to executable but not readable, then the extra abspath tests
will
+# fail even though the perl built is perfectly fine.
+if($EXTRA_ABSPATH_TESTS) {
+ my @​dirs = File​::Spec->splitdir(cwd());
+ for(0..$#dirs) {
+ my $parent_dir = File​::Spec->catdir(@​dirs[0..$_]);
+ $EXTRA_ABSPATH_TESTS = 0 unless -r $parent_dir;
+ }
+}
$tests += 4 if $EXTRA_ABSPATH_TESTS;
plan tests => $tests;

Thanks for the patch. Can you elaborate a bit as to how it addresses
the issues raised in the earlier posts in this RT?

Thank you very much.
Jim Keenan

@p5pRT
Copy link
Author

p5pRT commented Jun 14, 2013

From @ikegami

On Thu, Jun 13, 2013 at 10​:21 PM, James E Keenan via RT <
perlbug-followup@​perl.org> wrote​:

Thanks for the patch. Can you elaborate a bit as to how it addresses
the issues raised in the earlier posts in this RT?

Looking into your earlier comments, and testing to see if the patch
addresses my problem.

@p5pRT
Copy link
Author

p5pRT commented Jun 14, 2013

From gottreu@gmail.com

Thanks for the patch. Can you elaborate a bit as to how it addresses
the issues raised in the earlier posts in this RT?

It sort of didn't. It didn't solve the actual problem of _perl_abs_path()
not resolving all the paths that abs_path() can. It just made some harmlessly
failing tests not fail.

This new patch is an actual fix. I just translated the bsd_realpath() C
function to Perl.

This is a bug report for perl from gottreu@​gmail.com,
generated with the help of perlbug 1.39 running under perl 5.19.1.

From a380df6c6c1f9e17832236d07838efac3007a838 Mon Sep 17 00​:00​:00 2001
From​: Brian Gottreu <gottreu@​gmail.com>
Date​: Thu, 13 Jun 2013 22​:26​:22 -0500
Subject​: [PATCH] Replace _perl_abs_path() with a version that does not
require readable directories, only executable ones. It's
just a Perl version of the bsd_realpath() function already
used by abs_path() for Unix systems. This version mimics
the behavior of abs_path() more closely than the previous
version. It returns undef on failure instead of the empty
string.
MIME-Version​: 1.0
Content-Type​: multipart/mixed; boundary="------------1.7.10.4"

This is a multi-part message in MIME format.
--------------1.7.10.4
Content-Type​: text/plain; charset=UTF-8; format=fixed
Content-Transfer-Encoding​: 8bit


AUTHORS | 1 +
dist/Cwd/Cwd.pm | 129 ++++++++++++++++++++++++-------------------------------
2 files changed, 56 insertions(+), 74 deletions(-)

--------------1.7.10.4
Content-Type​: text/x-patch; name="0001-Replace-_perl_abs_path-with-a-version-that-does-not-.patch"
Content-Transfer-Encoding​: 8bit
Content-Disposition​: attachment; filename="0001-Replace-_perl_abs_path-with-a-version-that-does-not-.patch"

Inline Patch
diff --git a/AUTHORS b/AUTHORS
index 44f52e2..b00e7e5 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -163,6 +163,7 @@ Brian Carlson			<brian.carlson@cpanel.net>
 Brian Clarke			<clarke@appliedmeta.com>
 brian d foy			<brian.d.foy@gmail.com>
 Brian Fraser			<fraserbn@gmail.com>
+Brian Gottreu			<gottreu@gmail.com>
 Brian Greenfield		<briang@cpan.org>
 Brian Grossman
 Brian Harrison			<brie@corp.home.net>
diff --git a/dist/Cwd/Cwd.pm b/dist/Cwd/Cwd.pm
index 5cbb9d8..062e03c 100644
--- a/dist/Cwd/Cwd.pm
+++ b/dist/Cwd/Cwd.pm
@@ -536,82 +536,63 @@ sub chdir {
 }
 
 
-sub _perl_abs_path
-{
-    my $start = @_ ? shift : '.';
-    my($dotdots, $cwd, @pst, @cst, $dir, @tst);
-
-    unless (@cst = stat( $start ))
-    {
-	_carp("stat($start): $!");
-	return '';
+sub _perl_abs_path {
+    # NOTE that this routine assumes that '/' is the only directory separator.
+    my $path = @_ ? shift : '.';
+    my $resolved;
+    my $next_token;
+    my $left;
+    my $symlinks;
+    return '/' if $path eq '/';
+    if($path =~ m{^/(.+)}) {
+        $resolved = '/';
+        $left = $1;
     }
-
-    unless (-d _) {
-        # Make sure we can be invoked on plain files, not just directories.
-        # NOTE that this routine assumes that '/' is the only directory separator.
-	
-        my ($dir, $file) = $start =~ m{^(.*)/(.+)$}
-	    or return cwd() . '/' . $start;
-	
-	# Can't use "-l _" here, because the previous stat was a stat(), not an lstat().
-	if (-l $start) {
-	    my $link_target = readlink($start);
-	    die "Can't resolve link $start: $!" unless defined $link_target;
-	    
-	    require File::Spec;
-            $link_target = $dir . '/' . $link_target
-                unless File::Spec->file_name_is_absolute($link_target);
-	    
-	    return abs_path($link_target);
-	}
-	
-	return $dir ? abs_path($dir) . "/$file" : "/$file";
+    else {
+        $resolved = cwd();
+        $left = $path;
     }
-
-    $cwd = '';
-    $dotdots = $start;
-    do
-    {
-	$dotdots .= '/..';
-	@pst = @cst;
-	local *PARENT;
-	unless (opendir(PARENT, $dotdots))
-	{
-	    # probably a permissions issue.  Try the native command.
-	    require File::Spec;
-	    return File::Spec->rel2abs( $start, _backtick_pwd() );
-	}
-	unless (@cst = stat($dotdots))
-	{
-	    _carp("stat($dotdots): $!");
-	    closedir(PARENT);
-	    return '';
-	}
-	if ($pst[0] == $cst[0] && $pst[1] == $cst[1])
-	{
-	    $dir = undef;
-	}
-	else
-	{
-	    do
-	    {
-		unless (defined ($dir = readdir(PARENT)))
-	        {
-		    _carp("readdir($dotdots): $!");
-		    closedir(PARENT);
-		    return '';
-		}
-		$tst[0] = $pst[0]+1 unless (@tst = lstat("$dotdots/$dir"))
-	    }
-	    while ($dir eq '.' || $dir eq '..' || $tst[0] != $pst[0] ||
-		   $tst[1] != $pst[1]);
-	}
-	$cwd = (defined $dir ? "$dir" : "" ) . "/$cwd" ;
-	closedir(PARENT);
-    } while (defined $dir);
-    chop($cwd) unless $cwd eq '/'; # drop the trailing /
-    $cwd;
+    while($left ne '' and $left =~ m{^(.*?)(?:/|$)(.*)}) {
+        $next_token = $1;
+        $left = $2;
+        $resolved .= '/' unless $resolved =~ m{/$};
+        if($next_token eq '') { next; }
+        if($next_token eq '.') { next; }
+        if($next_token eq '..') {
+            if($resolved ne '/') {
+                $resolved =~ s{/[^/]+/$}{/};
+            }
+            next;
+        }
+        my $resolved_parent = $resolved;
+        $resolved .= $next_token;
+        my @sb;
+        @sb = lstat($resolved);
+        unless(@sb) {
+            return undef if $path =~ m{/$};
+            return $resolved if $left eq '' and -x $resolved_parent;
+            return undef;
+        }
+        if(-l $resolved) {
+            my $symlink;
+            return undef if ++$symlinks > 50;
+            $symlink = readlink($resolved);
+            unless($symlink) { return undef; }
+            if($symlink =~ m{^/}) {
+                $resolved = '/';
+            }
+            elsif(length($resolved) > 1) {
+                $resolved =~ s{/[^/]+$}{};
+            }
+            if($left ne '') {
+                $symlink .= '/' unless $symlink =~ m{/$};
+                $symlink .= $left;
+            }
+            $left = $symlink;
+        }
+    }
+    $resolved =~ s{/$}{} if length($resolved) > 1;
+    return $resolved;
 }
 
 

--------------1.7.10.4--


---
Flags:   category=core   severity=low

Site configuration information for perl 5.19.1​:

Configured by gottreu at Thu Jun 13 17​:46​:12 CDT 2013.

Summary of my perl5 (revision 5 version 19 subversion 1) configuration​:
  Derived from​: 9152021
  Platform​:
  osname=linux, osvers=3.2.0-4-amd64, archname=x86_64-linux
  uname='linux frylock 3.2.0-4-amd64 #1 smp debian 3.2.39-2 x86_64 gnulinux '
  config_args='-des -Dprefix=/home/gottreu/devperl2 -Dusedevel'
  hint=recommended, useposix=true, d_sigaction=define
  useithreads=undef, usemultiplicity=undef
  useperlio=define, d_sfio=undef, uselargefiles=define, usesocks=undef
  use64bitint=define, use64bitall=define, uselongdouble=undef
  usemymalloc=n, bincompat5005=undef
  Compiler​:
  cc='cc', ccflags ='-fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64',
  optimize='-O2',
  cppflags='-fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include'
  ccversion='', gccversion='4.7.2', gccosandvers=''
  intsize=4, longsize=8, ptrsize=8, doublesize=8, byteorder=12345678
  d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=16
  ivtype='long', ivsize=8, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8
  alignbytes=8, prototype=define
  Linker and Libraries​:
  ld='cc', ldflags =' -fstack-protector -L/usr/local/lib'
  libpth=/usr/local/lib /lib/x86_64-linux-gnu /lib/../lib /usr/lib/x86_64-linux-gnu /usr/lib/../lib /lib /usr/lib
  libs=-lnsl -lgdbm -ldb -ldl -lm -lcrypt -lutil -lc -lgdbm_compat
  perllibs=-lnsl -ldl -lm -lcrypt -lutil -lc
  libc=, so=so, useshrplib=false, libperl=libperl.a
  gnulibc_version='2.13'
  Dynamic Linking​:
  dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-Wl,-E'
  cccdlflags='-fPIC', lddlflags='-shared -O2 -L/usr/local/lib -fstack-protector'

Locally applied patches​:
 


@​INC for perl 5.19.1​:
  /home/gottreu/perl5/lib/perl5/x86_64-linux-gnu-thread-multi
  /home/gottreu/perl5/lib/perl5
  /home/gottreu/devperl2/lib/site_perl/5.19.1/x86_64-linux
  /home/gottreu/devperl2/lib/site_perl/5.19.1
  /home/gottreu/devperl2/lib/5.19.1/x86_64-linux
  /home/gottreu/devperl2/lib/5.19.1
  .


Environment for perl 5.19.1​:
  HOME=/home/gottreu
  LANG=en_US.UTF-8
  LANGUAGE (unset)
  LD_LIBRARY_PATH (unset)
  LOGDIR (unset)
  PATH=/home/gottreu/bin​:/home/gottreu/perl5/bin​:/home/gottreu/perl5/perlbrew/bin​:/usr/local/bin​:/usr/bin​:/bin​:/usr/local/games​:/usr/games
  PERL5LIB=/home/gottreu/perl5/lib/perl5/x86_64-linux-gnu-thread-multi​:/home/gottreu/perl5/lib/perl5
  PERLBREW_BASHRC_VERSION=0.42
  PERLBREW_HOME=/home/gottreu/.perlbrew
  PERLBREW_PATH=/home/gottreu/perl5/perlbrew/bin
  PERLBREW_ROOT=/home/gottreu/perl5/perlbrew
  PERL_BADLANG (unset)
  PERL_LOCAL_LIB_ROOT=/home/gottreu/perl5
  PERL_MB_OPT=--install_base /home/gottreu/perl5
  PERL_MM_OPT=INSTALL_BASE=/home/gottreu/perl5
  SHELL=/bin/bash

@p5pRT
Copy link
Author

p5pRT commented Jun 14, 2013

From @ikegami

On Sat, Feb 23, 2013 at 8​:35 PM, James E Keenan via RT <
perlbug-followup@​perl.org> wrote​:

$ prove -v b_109760_cwdtest.pl

b_109760_cwdtest.pl ..

ok 1 - symlink to test_dir created
# abs_path​:
Use of uninitialized value $abs_path in concatenation (.) or string at
b_109760_cwdtest.pl line 21.
Cannot chdir back to : No such file or directory at b_109760_cwdtest.pl
line 22.

I don't get that. I get something similar if I run "b" twice without
running "a" in between

ok 1 - symlink to test_dir created
Use of uninitialized value $abs_path in concatenation (.) or string at
b.plline 21.
# abs_path​:
linktest​: No such file or directory at b.pl line 22.
1..1
# Looks like your test exited with 255 just after 1.

But if I execute the commands you executed in the order you said you did, I
get​:

ok 1 - symlink to test_dir created
# abs_path​: /home/ikegami/projects/perl/_ptrslt_/_path_/_to_/_a_/_dir_
ok 2 - Cwd​::abs_path matches File​::Spec->rel2abs
ok 3 - Cwd​::fast_abs_path matches File​::Spec->rel2abs
not ok 4 - Cwd​::_perl_abs_path matches File​::Spec->rel2abs
# Failed test 'Cwd​::_perl_abs_path matches File​::Spec->rel2abs'
# at b.pl line 31.
# '/home/ikegami/projects/perl/linktest'
# doesn't match
'(?^i​:\/home\/ikegami\/projects\/perl\/_ptrslt_\/_path_\/_to_\/_a_\/_dir_$)'
1..4
# Looks like you failed 1 test of 4.

Brian's first patch ("Skip _perl_abs_path() tests when they will fail with
no ill effects") does address the problem I reported, and in an acceptable
manner.

I don't have time to look at his alternate/second patch right now.

- Eric

@p5pRT
Copy link
Author

p5pRT commented Jun 14, 2013

From gottreu@gmail.com

Attached is a test (dist/Cwd/t/abs_path.t) that makes sure _perl_abs_path() and abs_path() return
the same results.

@p5pRT
Copy link
Author

p5pRT commented Jun 14, 2013

From gottreu@gmail.com

#!./perl -w

use strict;

# XXX All the crossplatform stuff is cargo-cultedly copied from cwd.t
use Cwd;

chdir 't';

use Config;
use File​::Spec;
use File​::Path qw(make_path remove_tree);

use lib File​::Spec->catdir('t', 'lib');
use Test​::More;

# _perl_abs_path() currently only works when the directory separator
# is '/', so don't test it when it won't work.
unless(($Config{prefix} =~ m/\//) &amp;&amp; $^O ne 'cygwin') {
  plan skip_all => "only check _perl_abs_path() when the directory separator is '/'";
}

my @​real_dirs = qw(
  _base_
  _base_/ok
  _base_/ok/dir
  _base_/unreadable
  _base_/unreadable/dir
  _base_/unexec
  _base_/unexec/dir
  _base_/nothing
  _base_/nothing/dir
);

my @​real_files = qw(
  _base_/ok/file1
  _base_/ok/dir/file2
  _base_/unreadable/file3
  _base_/unreadable/dir/file4
  _base_/unexec/file5
  _base_/unexec/dir/file6
  _base_/nothing/file7
  _base_/nothing/dir/file8
);

my %valid_links = qw(
  _base_/link-ok0 ok
  _base_/link-ok1 ok/file1
  _base_/link-ok2 ok/dir
  _base_/link-ok3 ok/dir/file2
  _base_/link-unreadable0 unreadable
  _base_/link-unreadable1 unreadable/file3
  _base_/link-unreadable2 unreadable/dir
  _base_/link-unreadable3 unreadable/dir/file4

  _base_/link-bin /bin
  _base_/link-rm /bin/rm
);

my %broken_links = qw(
  _base_/link-unexec0 unexec
  _base_/link-unexec1 unexec/file5
  _base_/link-unexec2 unexec/dir
  _base_/link-unexec3 unexec/dir/file6

  _base_/link-nothing0 nothing
  _base_/link-nothing1 nothing/file7
  _base_/link-nothing2 nothing/dir
  _base_/link-nothing3 nothing/dir/file8

  _base_/link-loop link-loop

  _base_/link-non-existant non-existant
  _base_/link-non-existant2 non/existant/dirs
);

my @​reg_paths = qw(
  _base_/../_base_/ok/file1
  _base_/ok/dir/../file1
  _base_/ok//file1
  _base_/./ok/./file1
  _base_/unreadable/dir/../../ok/file1
  _base_/unreadable/../ok/file1
  _base_/unexec/dir/../../ok/file1
  _base_/unexec/../ok/file1
  _base_/non-existant
);

my @​link_paths = qw(
  _base_/link-ok2/file2
  _base_/link-ok2/../file1

  _base_/link-ok2/file1
  _base_/link-ok2/../file2
);

#my $tests = 1 + list_files("don't run cwd()");
my $tests = 1 + 3*list_reg_files() + 3*list_symlinks();
plan tests => $tests;
my $cwd;
my $CWD_WORKS = 0;

my $IsVMS = $^O eq 'VMS';
my $vms_unix_rpt = 0;
if ($IsVMS) {
  require VMS​::Filespec;
  use Carp;
  use Carp​::Heavy;
  if (eval 'require VMS​::Feature') {
  $vms_unix_rpt = VMS​::Feature​::current("filename_unix_report");
  } else {
  my $unix_rpt = $ENV{'DECC$FILENAME_UNIX_REPORT'} || '';
  $vms_unix_rpt = $unix_rpt =~ /^[ET1]/i;
  }
}

SKIP​: {
  # Must find an external pwd (or equivalent) command.
  my $pwd = $^O eq 'MSWin32' ? "cmd" : "pwd";
  my $pwd_cmd = ($^O eq "NetWare") ? "cd" :
  (grep { -x && -f } map { "$_/$pwd$Config{exe_ext}" }
  split m/$Config{path_sep}/, $ENV{PATH})[0];
  $pwd_cmd = 'SHOW DEFAULT' if $IsVMS;
  if ($^O eq 'MSWin32') {
  $pwd_cmd =~ s{/}{\\}g;
  $pwd_cmd = "$pwd_cmd /c cd";
  }
  $pwd_cmd =~ s{\\}{/}g if ($^O eq 'dos');

  skip "No native pwd command found to test against", 1 unless $pwd_cmd;

  local @​ENV{qw(PATH IFS CDPATH ENV BASH_ENV)};
  my ($pwd_cmd_untainted) = $pwd_cmd =~ /^(.+)$/; # Untaint.
  chomp(my $start = `$pwd_cmd_untainted`);

  # Win32's cd returns native C​:\ style
  $start =~ s{\\}{/}g if ($^O eq 'MSWin32' || $^O eq "NetWare");
  if ($IsVMS) {
  # DCL SHOW DEFAULT has leading spaces
  $start =~ s/^\s+//;

  # When in UNIX report mode, need to convert to compare it.
  if ($vms_unix_rpt) {
  $start = VMS​::Filespec​::unixpath($start);
  # Remove trailing slash.
  $start =~ s{/$}{};
  }
  }
  skip("'$pwd_cmd' failed, nothing to test against", 1) if $?;
  skip("/afs seen, paths unlikely to match", 1) if $start =~ m{/afs/};

  # Darwin's getcwd(3) (which Cwd.xs​:bsd_realpath() uses which
  # Cwd.pm​:getcwd uses) has some magic related to the PWD
  # environment variable​: if PWD is set to a directory that
  # looks about right (guess​: has the same (dev,ino) as the '.'?),
  # the PWD is returned. However, if that path contains
  # symlinks, the path will not be equal to the one returned by
  # /bin/pwd (which probably uses the usual walking upwards in
  # the path -trick). This situation is easy to reproduce since
  # /tmp is a symlink to /private/tmp. Therefore we invalidate
  # the PWD to force getcwd(3) to (re)compute the cwd in full.
  # Admittedly fixing this in the Cwd module would be better
  # long-term solution but deleting $ENV{PWD} should not be
  # done light-heartedly. --jhi
  delete $ENV{PWD} if $^O eq 'darwin';

  $cwd = cwd;
  is($cwd, $start, 'cwd()') and $CWD_WORKS=1;
}

eval {
  create_files();
  SKIP​: {
  compare_perl_and_xs( list_reg_files() );
  compare_perl_and_xs( map { "$_/" } list_reg_files() );
  if($CWD_WORKS) {
  compare_perl_and_xs( map { "$cwd/$_" } list_reg_files() );
  } else {
  skip "cwd() may not be correct", scalar(list_reg_files());
  }
  }

  SKIP​: {
  skip "no symlinks on this platform", (list_symlinks() * 3)
  unless $Config{d_symlink};
  compare_perl_and_xs( list_symlinks() );
  compare_perl_and_xs( map { "$_/" } list_symlinks() );
  if($CWD_WORKS) {
  compare_perl_and_xs( map { "$cwd/$_" } list_symlinks() );
  } else {
  skip "cwd() may not be correct", scalar(list_symlinks());
  }
  }
};
delete_files();

sub list_reg_files {
  my @​all = (@​real_dirs, @​real_files, @​reg_paths);
  return @​all;
}

sub list_symlinks {
  my @​all = (sort(keys %valid_links), sort(keys %broken_links), @​link_paths);
  return @​all;
}

sub compare_perl_and_xs {
  my @​files = @​_;
  for my $file (@​files) {
  my $c = Cwd​::abs_path($file);
  my $p = Cwd​::_perl_abs_path($file);
  is($p, $c) or diag("path​: $file");
  }
}

sub create_files {
  make_path($_) for @​real_dirs;
  system("touch $_") for @​real_files;
  symlink($valid_links{$_}, $_) for keys %valid_links;
  symlink($broken_links{$_}, $_) for keys %broken_links;
  chmod 0311, '_base_/unreadable';
  chmod 0644, '_base_/unexec';
  chmod 0200, '_base_/nothing';
}

sub delete_files {
  remove_tree("_base_");
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants