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

[PATCH] Serious regression in 5.14: require func() #11329

Closed
p5pRT opened this issue May 11, 2011 · 11 comments
Closed

[PATCH] Serious regression in 5.14: require func() #11329

p5pRT opened this issue May 11, 2011 · 11 comments

Comments

@p5pRT
Copy link

p5pRT commented May 11, 2011

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

Searchable as RT90296$

@p5pRT
Copy link
Author

p5pRT commented May 11, 2011

From @cpansprout

This is in response to <nntp​://nntp.perl.org/87k4dy9pl2.fsf@​biokovo.herceg.de>.

Sorry to spoil the excitement on the eve of the release, but I really think this needs to be fixed.

‘require func()’ does not work if the path is absolute and ends with .pm, and there is no .pmc file.

The patch attached hereto fixes that. I *think* the test is portable, but it might be safer just to apply the fix for now, and leave the test till later (unless we can get it tested on VMS and Windows).


Flags​:
  category=core
  severity=critical


Site configuration information for perl 5.14.0​:

Configured by sprout at Thu May 5 13​:28​:18 PDT 2011.

Summary of my perl5 (revision 5 version 14 subversion 0) configuration​:
  Snapshot of​: f5a93a4
  Platform​:
  osname=darwin, osvers=10.5.0, archname=darwin-thread-multi-2level
  uname='darwin pint.local 10.5.0 darwin kernel version 10.5.0​: fri nov 5 23​:20​:39 pdt 2010; root​:xnu-1504.9.17~1release_i386 i386 '
  config_args='-Dusedevel -de -Duseithreads -Doptimize=-g'
  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 ='-fno-common -DPERL_DARWIN -fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include',
  optimize='-g',
  cppflags='-fno-common -DPERL_DARWIN -fno-strict-aliasing -pipe -fstack-protector -I/usr/local/include'
  ccversion='', gccversion='4.2.1 (Apple Inc. build 5664)', 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 =' -fstack-protector -L/usr/local/lib'
  libpth=/usr/local/lib /usr/lib
  libs=-ldbm -ldl -lm -lutil -lc
  perllibs=-ldl -lm -lutil -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 -fstack-protector'

Locally applied patches​:
  RC2


@​INC for perl 5.14.0​:
  /usr/local/lib/perl5/site_perl/5.14.0/darwin-thread-multi-2level
  /usr/local/lib/perl5/site_perl/5.14.0
  /usr/local/lib/perl5/5.14.0/darwin-thread-multi-2level
  /usr/local/lib/perl5/5.14.0
  /usr/local/lib/perl5/site_perl
  .


Environment for perl 5.14.0​:
  DYLD_LIBRARY_PATH (unset)
  HOME=/Users/sprout
  LANG=en_US.UTF-8
  LANGUAGE (unset)
  LD_LIBRARY_PATH (unset)
  LOGDIR (unset)
  PATH=/usr/bin​:/bin​:/usr/sbin​:/sbin​:/usr/local/bin​:/usr/X11/bin​:/usr/local/bin
  PERL_BADLANG (unset)
  SHELL=/bin/bash

@p5pRT
Copy link
Author

p5pRT commented May 11, 2011

From @cpansprout

From​: Father Chrysostomos <sprout@​cpan.org>

Make ‘require func()’ work with .pm abs path

As of commit 282b29e, pp_requires passes an SV to S_doopen_pm, instead of char*/length pair.

That commit also used sv_mortalcopy() to copy the sv when trying out a .pmc extension​:
+ SV *const pmcsv = sv_mortalcopy(name);

When the path is absolute, the sv passed to S_doopen_pm is the very sv that was passed to require. If it was returned from a (non-lvalue) subroutine, it will be marked TEMP, so the buffer gets stolen.

After the .pmc file is discovered to be nonexistent, S_doopen_pm then uses its original sv to open the .pm file. But the buffer has been stolen, so it’s trying to open undef, which fais.

In the mean time, pp_require still has a pointer to the stolen buffer, which now has a .pmc extenion, it blithely reports that the .pmc file cannot be found, not realising that its string has changed out from under it. (Actually, if the file name were just the right length, it could be reallocated and we could end up with a crash.)

This patch copies the sv more kindly.

Inline Patch
diff --git a/pp_ctl.c b/pp_ctl.c
index a9072df..1b0b5f7 100644
--- a/pp_ctl.c
+++ b/pp_ctl.c
@@ -3467,9 +3467,10 @@ S_doopen_pm(pTHX_ SV *name)
     PERL_ARGS_ASSERT_DOOPEN_PM;
 
     if (namelen > 3 && memEQs(p + namelen - 3, 3, ".pm")) {
-	SV *const pmcsv = sv_mortalcopy(name);
+	SV *const pmcsv = sv_newmortal();
 	Stat_t pmcstat;
 
+	SvSetSV_nosteal(pmcsv,name);
 	sv_catpvn(pmcsv, "c", 1);
 
 	if (PerlLIO_stat(SvPV_nolen_const(pmcsv), &pmcstat) >= 0)
diff --git a/t/comp/require.t b/t/comp/require.t
index d4ca56c..069fe88 100644
--- a/t/comp/require.t
+++ b/t/comp/require.t
@@ -22,7 +22,7 @@ krunch.pm krunch.pmc whap.pm whap.pmc);
 
 my $Is_EBCDIC = (ord('A') == 193) ? 1 : 0;
 my $Is_UTF8   = (${^OPEN} || "") =~ /:utf8/;
-my $total_tests = 50;
+my $total_tests = 51;
 if ($Is_EBCDIC || $Is_UTF8) { $total_tests -= 3; }
 print "1..$total_tests\n";
 
@@ -223,7 +223,8 @@ EOT
     my $simple = ++$i;
     my $pmc_older = ++$i;
     my $pmc_dies = ++$i;
-    if ($ccflags =~ /(?:^|\s)-DPERL_DISABLE_PMC\b/) {
+    my $pmc_off = $ccflags =~ /(?:^|\s)-DPERL_DISABLE_PMC\b/;
+    if ($pmc_off) {
 	print "# .pmc files are ignored, so test that\n";
 	write_file_not_thing('krunch.pmc', '.pmc', $pmc_older);
 	write_file('urkkk.pm', qq(print "ok $simple\n"));
@@ -259,6 +260,20 @@ EOT
     }
 }
 
+# Test "require func()" with abs path when there is no .pmc file.
+++$::i;
+require Cwd;
+require File::Spec::Functions;
+eval {
+ CORE::require(File::Spec::Functions::catfile(Cwd::getcwd(),"bleah.pm"));
+};
+if ($@ =~ /^This is an expected error/) {
+    print "ok $i\n";
+} else {
+    print "not ok $i\n";
+}
+
+
 ##########################################
 # What follows are UTF-8 specific tests. #
 # Add generic tests before this point.   #

@p5pRT
Copy link
Author

p5pRT commented May 11, 2011

From @cpansprout

On Tue May 10 21​:47​:52 2011, sprout wrote​:

This is in response to
<nntp​://nntp.perl.org/87k4dy9pl2.fsf@​biokovo.herceg.de>.

Sorry to spoil the excitement on the eve of the release, but I really
think this needs to be fixed.

‘require func()’ does not work if the path is absolute and ends with
.pm, and there is no .pmc file.

The patch attached hereto fixes that. I *think* the test is portable,
but it might be safer just to apply the fix for now, and leave the
test till later (unless we can get it tested on VMS and Windows).

Here’s a better version of the patch. In the first, I forgot to undo a
temporary change to the test file that proved unnecessary.

@p5pRT
Copy link
Author

p5pRT commented May 11, 2011

From @cpansprout

From​: Father Chrysostomos <sprout@​cpan.org>

Make ‘require func()’ work with .pm abs path

As of commit 282b29e, pp_requires passes an SV to S_doopen_pm, instead of char*/length pair.

That commit also used sv_mortalcopy() to copy the sv when trying out a .pmc extension​:
+ SV *const pmcsv = sv_mortalcopy(name);

When the path is absolute, the sv passed to S_doopen_pm is the very sv that was passed to require. If it was returned from a (non-lvalue) subroutine, it will be marked TEMP, so the buffer gets stolen.

After the .pmc file is discovered to be nonexistent, S_doopen_pm then uses its original sv to open the .pm file. But the buffer has been stolen, so it’s trying to open undef, which fais.

In the mean time, pp_require still has a pointer to the stolen buffer, which now has a .pmc extenion, it blithely reports that the .pmc file cannot be found, not realising that its string has changed out from under it. (Actually, if the file name were just the right length, it could be reallocated and we could end up with a crash.)

This patch copies the sv more kindly.

Inline Patch
diff --git a/pp_ctl.c b/pp_ctl.c
index a9072df..1b0b5f7 100644
--- a/pp_ctl.c
+++ b/pp_ctl.c
@@ -3467,9 +3467,10 @@ S_doopen_pm(pTHX_ SV *name)
     PERL_ARGS_ASSERT_DOOPEN_PM;
 
     if (namelen > 3 && memEQs(p + namelen - 3, 3, ".pm")) {
-	SV *const pmcsv = sv_mortalcopy(name);
+	SV *const pmcsv = sv_newmortal();
 	Stat_t pmcstat;
 
+	SvSetSV_nosteal(pmcsv,name);
 	sv_catpvn(pmcsv, "c", 1);
 
 	if (PerlLIO_stat(SvPV_nolen_const(pmcsv), &pmcstat) >= 0)
diff --git a/t/comp/require.t b/t/comp/require.t
index d4ca56c..069fe88 100644
--- a/t/comp/require.t
+++ b/t/comp/require.t
@@ -22,7 +22,7 @@ krunch.pm krunch.pmc whap.pm whap.pmc);
 
 my $Is_EBCDIC = (ord('A') == 193) ? 1 : 0;
 my $Is_UTF8   = (${^OPEN} || "") =~ /:utf8/;
-my $total_tests = 50;
+my $total_tests = 51;
 if ($Is_EBCDIC || $Is_UTF8) { $total_tests -= 3; }
 print "1..$total_tests\n";
 
@@ -259,6 +260,20 @@ EOT
     }
 }
 
+# Test "require func()" with abs path when there is no .pmc file.
+++$::i;
+require Cwd;
+require File::Spec::Functions;
+eval {
+ CORE::require(File::Spec::Functions::catfile(Cwd::getcwd(),"bleah.pm"));
+};
+if ($@ =~ /^This is an expected error/) {
+    print "ok $i\n";
+} else {
+    print "not ok $i\n";
+}
+
+
 ##########################################
 # What follows are UTF-8 specific tests. #
 # Add generic tests before this point.   #

@p5pRT
Copy link
Author

p5pRT commented May 11, 2011

From [Unknown Contact. See original ticket]

On Tue May 10 21​:47​:52 2011, sprout wrote​:

This is in response to
<nntp​://nntp.perl.org/87k4dy9pl2.fsf@​biokovo.herceg.de>.

Sorry to spoil the excitement on the eve of the release, but I really
think this needs to be fixed.

‘require func()’ does not work if the path is absolute and ends with
.pm, and there is no .pmc file.

The patch attached hereto fixes that. I *think* the test is portable,
but it might be safer just to apply the fix for now, and leave the
test till later (unless we can get it tested on VMS and Windows).

Here’s a better version of the patch. In the first, I forgot to undo a
temporary change to the test file that proved unnecessary.

@p5pRT
Copy link
Author

p5pRT commented May 11, 2011

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

@p5pRT
Copy link
Author

p5pRT commented May 11, 2011

From @cpansprout

On Tue May 10 21​:50​:15 2011, sprout wrote​:

On Tue May 10 21​:47​:52 2011, sprout wrote​:

This is in response to
<nntp​://nntp.perl.org/87k4dy9pl2.fsf@​biokovo.herceg.de>.

Sorry to spoil the excitement on the eve of the release, but I really
think this needs to be fixed.

‘require func()’ does not work if the path is absolute and ends with
.pm, and there is no .pmc file.

The patch attached hereto fixes that. I *think* the test is portable,
but it might be safer just to apply the fix for now, and leave the
test till later (unless we can get it tested on VMS and Windows).

Here’s a better version of the patch. In the first, I forgot to undo a
temporary change to the test file that proved unnecessary.

Er, third try. I’m in too much of a hurry *and* I’m falling asleep. :-)
I forgot to wrap the commit message, causing annoyance to anyone reading
it in future.

@p5pRT
Copy link
Author

p5pRT commented May 11, 2011

From @cpansprout

From​: Father Chrysostomos <sprout@​cpan.org>

Make ‘require func()’ work with .pm abs path

As of commit 282b29e, pp_requires passes an SV to S_doopen_pm,
instead of char*/length pair.

That commit also used sv_mortalcopy() to copy the sv when trying out a
.pmc extension​:
+ SV *const pmcsv = sv_mortalcopy(name);

When the path is absolute, the sv passed to S_doopen_pm is the very sv
that was passed to require. If it was returned from a (non-lvalue)
sub-routine, it will be marked TEMP, so the buffer gets stolen.

After the .pmc file is discovered to be nonexistent, S_doopen_pm then
uses its original sv to open the .pm file. But the buffer has been
stolen, so it’s trying to open undef, which fais.

In the mean time, pp_require still has a pointer to the stolen buffer,
which now has a .pmc extenion, it blithely reports that the .pmc file
cannot be found, not realising that its string has changed out from
under it. (Actually, if the file name were just the right length, it
could be reallocated and we could end up with a crash.)

This patch copies the sv more kindly.

Inline Patch
diff --git a/pp_ctl.c b/pp_ctl.c
index a9072df..1b0b5f7 100644
--- a/pp_ctl.c
+++ b/pp_ctl.c
@@ -3467,9 +3467,10 @@ S_doopen_pm(pTHX_ SV *name)
     PERL_ARGS_ASSERT_DOOPEN_PM;
 
     if (namelen > 3 && memEQs(p + namelen - 3, 3, ".pm")) {
-	SV *const pmcsv = sv_mortalcopy(name);
+	SV *const pmcsv = sv_newmortal();
 	Stat_t pmcstat;
 
+	SvSetSV_nosteal(pmcsv,name);
 	sv_catpvn(pmcsv, "c", 1);
 
 	if (PerlLIO_stat(SvPV_nolen_const(pmcsv), &pmcstat) >= 0)
diff --git a/t/comp/require.t b/t/comp/require.t
index d4ca56c..069fe88 100644
--- a/t/comp/require.t
+++ b/t/comp/require.t
@@ -22,7 +22,7 @@ krunch.pm krunch.pmc whap.pm whap.pmc);
 
 my $Is_EBCDIC = (ord('A') == 193) ? 1 : 0;
 my $Is_UTF8   = (${^OPEN} || "") =~ /:utf8/;
-my $total_tests = 50;
+my $total_tests = 51;
 if ($Is_EBCDIC || $Is_UTF8) { $total_tests -= 3; }
 print "1..$total_tests\n";
 
@@ -259,6 +260,20 @@ EOT
     }
 }
 
+# Test "require func()" with abs path when there is no .pmc file.
+++$::i;
+require Cwd;
+require File::Spec::Functions;
+eval {
+ CORE::require(File::Spec::Functions::catfile(Cwd::getcwd(),"bleah.pm"));
+};
+if ($@ =~ /^This is an expected error/) {
+    print "ok $i\n";
+} else {
+    print "not ok $i\n";
+}
+
+
 ##########################################
 # What follows are UTF-8 specific tests. #
 # Add generic tests before this point.   #

@p5pRT
Copy link
Author

p5pRT commented May 11, 2011

From [Unknown Contact. See original ticket]

On Tue May 10 21​:50​:15 2011, sprout wrote​:

On Tue May 10 21​:47​:52 2011, sprout wrote​:

This is in response to
<nntp​://nntp.perl.org/87k4dy9pl2.fsf@​biokovo.herceg.de>.

Sorry to spoil the excitement on the eve of the release, but I really
think this needs to be fixed.

‘require func()’ does not work if the path is absolute and ends with
.pm, and there is no .pmc file.

The patch attached hereto fixes that. I *think* the test is portable,
but it might be safer just to apply the fix for now, and leave the
test till later (unless we can get it tested on VMS and Windows).

Here’s a better version of the patch. In the first, I forgot to undo a
temporary change to the test file that proved unnecessary.

Er, third try. I’m in too much of a hurry *and* I’m falling asleep. :-)
I forgot to wrap the commit message, causing annoyance to anyone reading
it in future.

@p5pRT
Copy link
Author

p5pRT commented May 11, 2011

From @cpansprout

On Tue May 10 21​:53​:41 2011, sprout wrote​:

On Tue May 10 21​:50​:15 2011, sprout wrote​:

On Tue May 10 21​:47​:52 2011, sprout wrote​:

This is in response to
<nntp​://nntp.perl.org/87k4dy9pl2.fsf@​biokovo.herceg.de>.

Sorry to spoil the excitement on the eve of the release, but I really
think this needs to be fixed.

‘require func()’ does not work if the path is absolute and ends with
.pm, and there is no .pmc file.

The patch attached hereto fixes that. I *think* the test is portable,
but it might be safer just to apply the fix for now, and leave the
test till later (unless we can get it tested on VMS and Windows).

Here’s a better version of the patch. In the first, I forgot to undo a
temporary change to the test file that proved unnecessary.

Er, third try. I’m in too much of a hurry *and* I’m falling asleep. :-)
I forgot to wrap the commit message, causing annoyance to anyone reading
it in future.

Applied as eb70bb4.

@p5pRT
Copy link
Author

p5pRT commented May 11, 2011

@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