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

Backwards compat issue with File::Copy #9138

Closed
p5pRT opened this issue Dec 3, 2007 · 13 comments
Closed

Backwards compat issue with File::Copy #9138

p5pRT opened this issue Dec 3, 2007 · 13 comments

Comments

@p5pRT
Copy link

p5pRT commented Dec 3, 2007

Migrated from rt.perl.org#48078 (status was 'resolved')

Searchable as RT48078$

@p5pRT
Copy link
Author

p5pRT commented Dec 3, 2007

From @jdv

Created by @jdv

File​::Copy​::copy() checks whether its two args are equal. Newer
versions like 2.10 & 2.11 break when passed Path​::Class objects.
Version 2.9 worked just fine. The following patch seems to fix the
problem.

--- ./perl-5.10.0-RC2/lib/File/Copy.pm 2007-11-25 13​:09​:07.000000000
-0500
+++ ./lib/File/Copy.pm 2007-12-02 18​:06​:41.000000000 -0500
@​@​ -12,6 +12,7 @​@​
use warnings;
use File​::Spec;
use Config;
+use Scalar​::Util qw( reftype );
our(@​ISA, @​EXPORT, @​EXPORT_OK, $VERSION, $Too_Big, $Syscopy_is_copy);
sub copy;
sub syscopy;
@​@​ -67,7 +68,8 @​@​
# _eq($from, $to) tells whether $from and $to are identical
# works for strings and references
sub _eq {
- return $_[0] == $_[1] if ref $_[0] && ref $_[1];
+ return $_[0] == $_[1]
+ if reftype( $_[0] ) eq 'GLOB' && reftype( $_[1] ) eq 'GLOB';
  return $_[0] eq $_[1] if !ref $_[0] && !ref $_[1];
  return "";
}

The test case I used was this​:
<snip>
use File​::Copy;
use Path​::Class;
use strict;
use warnings;
copy( file( 'file1' ), file( 'file2' ) ) or die "Copy failed​: $!";
</snip>

Thanks,
  jdv

Perl Info

Flags:
    category=library
    severity=medium

Site configuration information for perl 5.10.0:

Configured by jdv at Sun Dec  2 04:38:26 EST 2007.

Summary of my perl5 (revision 5 version 10 subversion 0) configuration:
  Platform:
    osname=darwin, osvers=8.11.1, archname=darwin-2level
    uname='darwin maclap 8.11.1 darwin kernel version 8.11.1: wed oct
10 18:23:28 pdt 2007; root:xnu-792.25.20~1release_i386 i386 i386 '
    config_args='-de'
    hint=recommended, useposix=true, d_sigaction=define
    useithreads=undef, usemultiplicity=undef
    useperlio=define, d_sfio=undef, uselargefiles=define, usesocks=undef
    use64bitint=undef, use64bitall=undef, uselongdouble=undef
    usemymalloc=n, bincompat5005=undef
  Compiler:
    cc='cc', ccflags ='-fno-common -DPERL_DARWIN -no-cpp-precomp
-fno-strict-aliasing -pipe -I/usr/local/include
-I/opt/local/include',
    optimize='-O3',
    cppflags='-no-cpp-precomp -fno-common -DPERL_DARWIN
-no-cpp-precomp -fno-strict-aliasing -pipe -I/usr/local/include
-I/opt/local/include'
    ccversion='', gccversion='4.0.1 (Apple Computer, Inc. build
5250)', gccosandvers=''
    intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=1234
    d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=16
    ivtype='long', ivsize=4, nvtype='double', nvsize=8, Off_t='off_t',
lseeksize=8
    alignbytes=8, prototype=define
  Linker and Libraries:
    ld='env MACOSX_DEPLOYMENT_TARGET=10.3 cc', ldflags ='
-L/usr/local/lib -L/opt/local/lib'
    libpth=/usr/local/lib /opt/local/lib /usr/lib
    libs=-ldbm -ldl -lm -lc
    perllibs=-ldl -lm -lc
    libc=/usr/lib/libc.dylib, so=dylib, useshrplib=false,
libperl=libperl.a
    gnulibc_version=''
  Dynamic Linking:
    dlsrc=dl_dlopen.xs, dlext=bundle, d_dlsymun=undef, ccdlflags=' '
    cccdlflags=' ', lddlflags=' -bundle -undefined dynamic_lookup
-L/usr/local/lib -L/opt/local/lib'

Locally applied patches:
    RC2


@INC for perl 5.10.0:
    ./lib
    /sw/lib/perl5
    /sw/lib/perl5/darwin
    /Users/jdv/Desktop/lib
    /usr/local/lib/perl5/5.10.0/darwin-2level
    /usr/local/lib/perl5/5.10.0
    /usr/local/lib/perl5/site_perl/5.10.0/darwin-2level
    /usr/local/lib/perl5/site_perl/5.10.0
    .


Environment for perl 5.10.0:
    DYLD_LIBRARY_PATH (unset)
    HOME=/Users/jdv
    LANG (unset)
    LANGUAGE (unset)
    LD_LIBRARY_PATH (unset)
    LOGDIR (unset)
    PATH=/opt/local/bin:/opt/local/sbin:/sw/bin:/sw/sbin:/Users/jdv/Desktop/bin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/X11R6/bin
    PERL5LIB=/sw/lib/perl5:/sw/lib/perl5/darwin:/Users/jdv/Desktop/lib:
    PERL_BADLANG (unset)
    SHELL=/bin/bash


@p5pRT
Copy link
Author

p5pRT commented Dec 3, 2007

From @rgs

On 03/12/2007, via RT Justin DeVuyst <perlbug-followup@​perl.org> wrote​:

File​::Copy​::copy() checks whether its two args are equal. Newer
versions like 2.10 & 2.11 break when passed Path​::Class objects.
Version 2.9 worked just fine. The following patch seems to fix the
problem.

--- ./perl-5.10.0-RC2/lib/File/Copy.pm 2007-11-25 13​:09​:07.000000000
-0500
+++ ./lib/File/Copy.pm 2007-12-02 18​:06​:41.000000000 -0500
@​@​ -12,6 +12,7 @​@​
use warnings;
use File​::Spec;
use Config;
+use Scalar​::Util qw( reftype );
our(@​ISA, @​EXPORT, @​EXPORT_OK, $VERSION, $Too_Big, $Syscopy_is_copy);
sub copy;
sub syscopy;
@​@​ -67,7 +68,8 @​@​
# _eq($from, $to) tells whether $from and $to are identical
# works for strings and references
sub _eq {
- return $_[0] == $_[1] if ref $_[0] && ref $_[1];
+ return $_[0] == $_[1]
+ if reftype( $_[0] ) eq 'GLOB' && reftype( $_[1] ) eq 'GLOB';

reftype() might be a bit overkill here. I think we want use ref address
comparison if both refs are (unblessed) GLOBs, and use eq as a fallback​:

 return $\_\[0\] eq $\_\[1\] if \!ref $\_\[0\] && \!ref $\_\[1\];

  return $_[0] eq $_[1];

This way, objects with overloaded stringification will work.
Comments?

 return "";

}

The test case I used was this​:
<snip>
use File​::Copy;
use Path​::Class;
use strict;
use warnings;
copy( file( 'file1' ), file( 'file2' ) ) or die "Copy failed​: $!";
</snip>

@p5pRT
Copy link
Author

p5pRT commented Dec 3, 2007

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

@p5pRT
Copy link
Author

p5pRT commented Dec 4, 2007

From @jdv

Rafael Garcia-Suarez via RT wrote​:

On 03/12/2007, via RT Justin DeVuyst <perlbug-followup@​perl.org>
wrote​:

File​::Copy​::copy() checks whether its two args are equal. Newer
versions like 2.10 & 2.11 break when passed Path​::Class objects.
Version 2.9 worked just fine. The following patch seems to fix the
problem.

--- ./perl-5.10.0-RC2/lib/File/Copy.pm 2007-11-25
13​:09​:07.000000000
-0500
+++ ./lib/File/Copy.pm 2007-12-02 18​:06​:41.000000000 -0500
@​@​ -12,6 +12,7 @​@​
use warnings;
use File​::Spec;
use Config;
+use Scalar​::Util qw( reftype );
our(@​ISA, @​EXPORT, @​EXPORT_OK, $VERSION, $Too_Big,
$Syscopy_is_copy);
sub copy;
sub syscopy;
@​@​ -67,7 +68,8 @​@​
# _eq($from, $to) tells whether $from and $to are identical
# works for strings and references
sub _eq {
- return $_[0] == $_[1] if ref $_[0] && ref $_[1];
+ return $_[0] == $_[1]
+ if reftype( $_[0] ) eq 'GLOB' && reftype( $_[1] ) eq 'GLOB';

reftype() might be a bit overkill here. I think we want use ref
address
comparison if both refs are (unblessed) GLOBs, and use eq as a
fallback​:

 return $\_\[0\] eq $\_\[1\] if \!ref $\_\[0\] && \!ref $\_\[1\];
   return $\_\[0\] eq $\_\[1\];

This way, objects with overloaded stringification will work.
Comments?

That sounds much more sane. I did my patch hastily and realized
it wasn't very good after the fact. Thanks for not accepting it.

 return "";

}

The test case I used was this​:
<snip>
use File​::Copy;
use Path​::Class;
use strict;
use warnings;
copy( file( 'file1' ), file( 'file2' ) ) or die "Copy failed​: $!";
</snip>

@p5pRT
Copy link
Author

p5pRT commented Dec 10, 2007

From @jdv

How about this?

Inline Patch
diff -ru lib/File/Copy.pm lib2/File/Copy.pm
--- lib/File/Copy.pm    2007-12-10 04:53:02.000000000 -0500
+++ lib2/File/Copy.pm   2007-12-10 04:12:33.000000000 -0500
@@ -12,6 +12,7 @@
 use warnings;
 use File::Spec;
 use Config;
+use Scalar::Util qw( blessed refaddr );
 our(@ISA, @EXPORT, @EXPORT_OK, $VERSION, $Too_Big, $Syscopy_is_copy);
 sub copy;
 sub syscopy;
@@ -67,9 +68,9 @@
 # _eq($from, $to) tells whether $from and $to are identical
 # works for strings and references
 sub _eq {
-    return $_[0] == $_[1] if ref $_[0] && ref $_[1];
-    return $_[0] eq $_[1] if !ref $_[0] && !ref $_[1];
-    return "";
+    return refaddr $_[0] == refaddr $_[1]
+      if ref $_[0] && ref $_[1] && ! blessed $_[0] && ! blessed $_[1];
+    return $_[0] eq $_[1];
 }

 sub copy {
diff -ru lib/File/Copy.t lib2/File/Copy.t
--- lib/File/Copy.t     2007-12-10 04:14:20.000000000 -0500
+++ lib2/File/Copy.t    2007-12-10 05:00:28.000000000 -0500
@@ -11,7 +11,7 @@

 my $TB = Test::More->builder;

-plan tests => 60;
+plan tests => 72;

 # We're going to override rename() later on but Perl has to see an
override \# at compile time to honor it\. @​@​ \-142\,6 \+142\,33 @​@​   ok \-s "file\-$$"\, 'contents preserved';   \}

+ {
+ open( my $fh, 'file-$$' ) or die $!;
+ my $warnings = '';
+ local $SIG{__WARN__} = sub { $warnings .= join '', @​_ };
+ ok copy($fh, $fh), 'copy(fh, fh) succeeds';
+
+ like $warnings, qr/are identical/, 'but warns';
+ ok -s "file-$$", 'contents preserved';
+ }
+
+ {
+ package SomeClass;
+ use overload
+ '""' => sub { $_[0]->{str} },
+ fallback => 1;
+ package main;
+ my $obj1 = bless( { str =&gt; "file-$$" }, 'SomeClass' );
+ my $obj2 = bless( { str =&gt; "file-$$" }, 'SomeClass' );
+ my $warnings = '';
+ local $SIG{__WARN__} = sub { $warnings .= join '', @​_ };
+ ok copy($obj1, $obj2), 'copy(o, o) succeeds';
+
+ unlike $warnings, qr/isn't numeric/, 'rt.perl.org 48078​: bad
comparison';
+ like $warnings, qr/are identical/, 'but warns';
+ ok -s $obj1, 'contents preserved';
+ }
+
  move "file-$$", "lib";
  open(R, "lib/file-$$") or die "open lib/file-$$​: $!"; $foo = <R>;
close(R);
  is $foo, "ok\n", 'move(fn, dir)​: same contents';

-jdv

@p5pRT
Copy link
Author

p5pRT commented Oct 6, 2008

From @ribasushi

Created by @ribasushi

The _eq() function used to determine if 'from' and 'to' are the same
has an extremely naive implementation, completely unable to deal
with smart objects (i.e. Path​::Class​::File). I propose the following
version instead​:

use overload ();
use Scalar​::Util ();
sub _eq {
  my ($from, $to) = map {
  ( Scalar​::Util​::blessed ($_) and overload​::Method ($_, q{""}) )
  ? "$_"
  : $_
  } (@​_);
  return '' if ( (ref $from) xor (ref $to) );
  return $from == $to if ref $from;
  return $from eq $to;
}

Perl Info

Flags:
    category=library
    severity=medium

Site configuration information for perl 5.10.0:

Configured by Debian Project at Tue Sep 30 16:11:07 UTC 2008.

Summary of my perl5 (revision 5 version 10 subversion 0) configuration:
  Platform:
    osname=linux, osvers=2.6.26.1, archname=i486-linux-gnu-thread-multi
    uname='linux ninsei 2.6.26.1 #1 smp preempt sun aug 3 22:34:07 pdt 2008 i686 gnulinux '
    config_args='-Dusethreads -Duselargefiles -Dccflags=-DDEBIAN -Dcccdlflags=-fPIC -Darchname=i486-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.0 -Dsitearch=/usr/local/lib/perl/5.10.0 -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.0 -Dd_dosuid -des'
    hint=recommended, useposix=true, d_sigaction=define
    useithreads=define, usemultiplicity=define
    useperlio=define, d_sfio=undef, uselargefiles=define, usesocks=undef
    use64bitint=undef, use64bitall=undef, uselongdouble=undef
    usemymalloc=n, bincompat5005=undef
  Compiler:
    cc='cc', ccflags ='-D_REENTRANT -D_GNU_SOURCE -DDEBIAN -fno-strict-aliasing -pipe -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 -I/usr/local/include'
    ccversion='', gccversion='4.3.2', gccosandvers=''
    intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=1234
    d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=12
    ivtype='long', ivsize=4, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8
    alignbytes=4, prototype=define
  Linker and Libraries:
    ld='cc', ldflags =' -L/usr/local/lib'
    libpth=/usr/local/lib /lib /usr/lib /usr/lib64
    libs=-lgdbm -lgdbm_compat -ldb -ldl -lm -lpthread -lc -lcrypt
    perllibs=-ldl -lm -lpthread -lc -lcrypt
    libc=/lib/libc-2.7.so, so=so, useshrplib=true, libperl=libperl.so.5.10.0
    gnulibc_version='2.7'
  Dynamic Linking:
    dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-Wl,-E'
    cccdlflags='-fPIC', lddlflags='-shared -O2 -g -L/usr/local/lib'

Locally applied patches:
    


@INC for perl 5.10.0:
    /home/rabbit/devel/utils/perl
    /etc/perl
    /usr/local/lib/perl/5.10.0
    /usr/local/share/perl/5.10.0
    /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.0:
    HOME=/home/rabbit
    LANG=en_US.UTF-8
    LANGUAGE (unset)
    LC_ADDRESS=en_US.UTF-8
    LC_COLLATE=en_US.UTF-8
    LC_CTYPE=en_US.UTF-8
    LC_IDENTIFICATION=en_US.UTF-8
    LC_MESSAGES=en_US.UTF-8
    LC_MONETARY=en_US.UTF-8
    LC_NAME=en_US.UTF-8
    LC_NUMERIC=en_US.UTF-8
    LC_TELEPHONE=en_US.UTF-8
    LC_TIME=en_US.UTF-8
    LD_LIBRARY_PATH (unset)
    LOGDIR (unset)
    PATH=/home/rabbit/devel/utils:/home/rabbit/bin:/usr/local/bin:/usr/bin:/bin:/usr/games
    PERL5LIB=/home/rabbit/devel/utils/perl
    PERL_BADLANG (unset)
    SHELL=/bin/bash

@p5pRT
Copy link
Author

p5pRT commented Oct 18, 2008

From @nwc10

Thanks for the bug report, and the patch.

On Mon, Oct 06, 2008 at 04​:19​:10AM -0700, rabbit+bugs@​rabbit.us (via RT) wrote​:

The _eq() function used to determine if 'from' and 'to' are the same
has an extremely naive implementation, completely unable to deal
with smart objects (i.e. Path​::Class​::File). I propose the following
version instead​:

It doesn't even deal with two IO​::Scalar objects, which was the source of the
original bug report that prompted the change that created _eq()​:

http​://rt.perl.org/rt3/Public/Bug/Display.html?id=32135

use overload ();
use Scalar​::Util ();
sub _eq {
my ($from, $to) = map {
( Scalar​::Util​::blessed ($_) and overload​::Method ($_, q{""}) )
? "$_"
: $_
} (@​_);
return '' if ( (ref $from) xor (ref $to) );

Is there any particular reason you chose xor over ne ?
I can't think of any corner case where the two would differ, or one not warn
where the other would.

return $from == $to if ref $from;
return $from eq $to;

}

Nicholas Clark

@p5pRT
Copy link
Author

p5pRT commented Oct 18, 2008

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

@p5pRT
Copy link
Author

p5pRT commented Jan 17, 2010

From @rurban

The commit e55c0a8 for
[perl #59650] File​::Copy does not handle file objects sanely
Suggested change modified to cope with the hoop-jumping needed to keep
File​::Copy working whilst bootstrapping the core build.

which added the lines​:

# During perl build, we need File​::Copy but Scalar​::Util might not be
built yet
# And then we need these games to avoid loading overload, as that will
# confuse miniperl during the bootstrap of perl.
my $Scalar_Util_loaded = eval q{ require Scalar​::Util; require overload;
1 };

fails on cygwin since about 5.11.3 with

../../miniperl Makefile.PL INSTALLDIRS=perl INSTALLMAN1DIR=none
INSTALLMAN3DIR=none PERL_CORE=1 LIBPERL_A=cygperl5_11_3d@​b595cd4b.dll
Importing PAUSE public key into your GnuPG keychain... done!
(You may wish to trust it locally with 'gpg --lsign-key 450F89EC')
Attempt to reload Scalar/Util.pm aborted.
Compilation failed in require at ../../lib/overload.pm line 96.
65280 from cpan/CPAN's Makefile.PL at make_ext.pl line 390.

Scalar​::Util is required by CPAN even if it cannot be loaded at
bootstrap.

I've instrumented the pp_require stores into %INC.

Scalar/Utils.pm is dynamically eval-loaded by​:

../../lib/File/Copy.pm​:18
../../lib/IO/Compress/Base/Common.pm​:8
../../lib/File/Find.pm​:1345
Makefile.PL​:118 (as interesting_module)
../../lib/overload.pm​:96

but I dont see where it is stored into %INC to avoid the recursion failure.

(492​:../../lib/File/Copy.pm​:18) const(PV(" require Scalar​::Util; require
overload; 1 "\0))
(492​:../../lib/File/Copy.pm​:18) entereval
(492​:(eval 18)​:0) nextstate
(492​:(eval 18)​:1) const(PV("Scalar/Util.pm"\0))
(492​:(eval 18)​:1) require
(492​:(eval 18)​:1) pp_require "Scalar/Util.pm"
(492​:(eval 18)​:1) pp_require store in INC "Scalar/Util.pm" (!hook_sv)
..
(492​:../../lib/overload.pm​:96) require
(492​:../../lib/overload.pm​:96) pp_require "Scalar/Util.pm"
SV = NULL(0x0) at 0x26e8840
  REFCNT = 2147479514
  FLAGS = (READONLY)
Attempt to reload Scalar/Util.pm aborted.
Compilation failed in require at ../../lib/overload.pm line 96.

Scalar​::Util loads Scalar​::Util​::PP if the XS is not loaded.
But Scalar​::Util​::PP requires B​::svref_2object, which is not available
at miniperl bootstrap. So loading Scalar​::Util will always fail on
miniperl. We should get rid of B​::svref_2object in PP to be able to
bootstrap miniperl sanely

This is the fix​:

Inline Patch
diff --git a/make_ext.pl b/make_ext.pl
index de26d84..d31692a 100644
--- a/make_ext.pl
+++ b/make_ext.pl
@@ -34,6 +34,7 @@ my @toolchain = qw(cpan/AutoLoader/lib
 		   cpan/ExtUtils-MakeMaker/lib
 		   cpan/ExtUtils-Manifest/lib
 		   cpan/File-Path/lib
+		   cpan/List-Util/lib
 		   );
 
 # Used only in ExtUtils::Liblist::Kid::_win32_ext()

-- 

Reini Urban

@p5pRT
Copy link
Author

p5pRT commented Sep 26, 2010

From @cpansprout

On Mon Dec 10 05​:07​:13 2007, jdv79 wrote​:

How about this?

diff -ru lib/File/Copy.pm lib2/File/Copy.pm
--- lib/File/Copy.pm 2007-12-10 04​:53​:02.000000000 -0500
+++ lib2/File/Copy.pm 2007-12-10 04​:12​:33.000000000 -0500

It seems your patch was overlooked. Thank you anyway.

In the mean time, this was fixed by change 34519/e55c0a828f2.

@p5pRT
Copy link
Author

p5pRT commented Sep 26, 2010

@cpansprout - Status changed from 'open' to 'resolved'

@p5pRT p5pRT closed this as completed Sep 26, 2010
@p5pRT
Copy link
Author

p5pRT commented Sep 26, 2010

From @cpansprout

Fixed by 34519/e55c0a828f2.

@p5pRT
Copy link
Author

p5pRT commented Sep 26, 2010

@cpansprout - Status changed from 'open' to 'resolved'

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

1 participant