Closed p5pRT closed 8 years ago
I got some strange behavior trying to unishift more than one value to @ISA.
5.14 and 5.22 are both affected.
Code:
use strict; use warnings;
our @ISA;
push( @ISA\, "A"); # OK unshift(@ISA\, "B"); # OK push( @ISA\, "C"\, "D"); # OK unshift(@ISA\, "D"\, "E"); # Recursive inheritance detected in package 'main'
output
Use of uninitialized value within @ISA in unshift at /home/v.pushtaev/bug.pl line 9. Use of uninitialized value within @ISA in unshift at /home/v.pushtaev/bug.pl line 9. Use of uninitialized value within @ISA in unshift at /home/v.pushtaev/bug.pl line 9. [...] Use of uninitialized value within @ISA in unshift at /home/v.pushtaev/bug.pl line 9. Use of uninitialized value within @ISA in unshift at /home/v.pushtaev/bug.pl line 9. Use of uninitialized value within @ISA in unshift at /home/v.pushtaev/bug.pl line 9. Recursive inheritance detected in package 'main' at /home/v.pushtaev/bug.pl line 9.
perl -v
This is perl 5\, version 22\, subversion 0 (v5.22.0) built for x86_64-linux
Copyright 1987-2015\, Larry Wall
Perl may be copied only under the terms of either the Artistic License or the GNU General Public License\, which may be found in the Perl 5 source kit.
Complete documentation for Perl\, including FAQ lists\, should be found on this system using "man perl" or "perldoc perl". If you have access to the Internet\, point your browser at http://www.perl.org/\, the Perl Home Page.
The RT System itself - Status changed from 'new' to 'open'
Vadim Pushtaev wrote:
push( @ISA\, "C"\, "D"); # OK unshift(@ISA\, "D"\, "E"); # Recursive inheritance detected in package 'main'
This gives the impression that the repeating of a class name within @ISA might be relevant\, but that's a red herring. Shorter example:
$ perl -lwe 'unshift @ISA\, qw(A B)' 2>&1 | uniq -c 101 Use of uninitialized value in unshift at -e line 1. 1 Recursive inheritance detected in package 'main' at -e line 1.
-zefram
Yes\, sorry for that typo\, it is confusing.
Yes\, sorry for that typo\, it is confusing.
Hi Vadim\,
* Vadim Pushtaev \perlbug\-followup@​perl\.org [2015-09-17 15:15]:
unshift(@ISA\, "D"\, "E"); # Recursive inheritance detected in package 'main'
actually that error is probably irrelevant.
$ perl -we 'unshift @ISA\, ""' Recursive inheritance detected in package 'main' at -e line 1.
That is actually correct; there is no bug there.
I’d wager the undef warning points to the real problem. The recursive inheritance error is probably just the result of trying to coerce the undef to a string\, which gives the empty string\, which means the same as 'main'.
Further\,
$ perl -we 'push @ISA\, undef' 2>&1 | uniq -c 101 Use of uninitialized value $ISA[0] in unshift at -e line 1. 1 Recursive inheritance detected in package 'main' at -e line 1.
Why does trying to push undef generate 100 extra undef warnings?
So I wager that there are two bugs here - one is the loop that happens when you try to put undef in @ISA\, and one is that unshifting multiple values\, all defined\, somehow causes perl to try to unshift undef.
Regards\, -- Aristotle Pagaltzis // \<http://plasmasturm.org/>
On Thu Sep 17 10:37:16 2015\, aristotle wrote:
Further\,
$ perl -we 'push @ISA\, undef' 2>&1 | uniq -c 101 Use of uninitialized value $ISA[0] in unshift at -e line 1. 1 Recursive inheritance detected in package 'main' at -e line 1.
Why does trying to push undef generate 100 extra undef warnings?
I don't quite understand why it generates any warnings at all. Pushing (and unshifting) undef is totally legit.
* Vadim Pushtaev via RT \perlbug\-followup@​perl\.org [2015-09-18 09:30]:
I don't quite understand why it generates any warnings at all. Pushing (and unshifting) undef is totally legit.
How so? It only makes sense for @ISA to contain package name strings. What should inheriting from an undef package mean?
On Fri Sep 18 03:28:24 2015\, aristotle wrote:
* Vadim Pushtaev via RT \perlbug\-followup@​perl\.org [2015-09-18 09:30]:
I don't quite understand why it generates any warnings at all. Pushing (and unshifting) undef is totally legit.
How so? It only makes sense for @ISA to contain package name strings. What should inheriting from an undef package mean?
I mean\, there is a problem with inheritance\, yes\, but not with pushing value into array (even though it's a special array).
On Thu\, Sep 17\, 2015 at 7:36 PM\, Aristotle Pagaltzis \pagaltzis@​gmx\.de wrote:
So I wager that there are two bugs here - one is the loop that happens when you try to put undef in @ISA\, and one is that unshifting multiple values\, all defined\, somehow causes perl to try to unshift undef.
… yeah … unless behaviour under block eval consitutes a third bug:
eirik@purplehat[13:10:10]~$ perl -wle 'our(@ISA); $"="\, "; eval { push @ISA\, undef\, undef\, ""}; warn "\@ISA: [@ISA]\n"; warn main->foo' 2>&1 | uniq -c 101 Use of uninitialized value in push at -e line 1. 2 Use of uninitialized value in join or string at -e line 1. 1 @ISA: [\, \, ] 101 Use of uninitialized value in method with known name at -e line 1. 1 Recursive inheritance detected in package 'main' at -e line 1. eirik@purplehat[13:13:12]~$ $ perl -wle 'our(@ISA); $"="\, "; eval { unshift @ISA\, qw/ A B C D /}; warn "\@ISA: [@ISA]\n"; warn main->foo' 2>&1 | uniq -c 101 Use of uninitialized value in unshift at -e line 1. 3 Use of uninitialized value in join or string at -e line 1. 1 @ISA: [A\, \, \, ] 101 Use of uninitialized value in method with known name at -e line 1. 1 Recursive inheritance detected in package 'main' at -e line 1. eirik@purplehat[13:13:27]~$
Yikes.
Using block eval\, I _can_ push undef (without coercion) and even "" on @ISA. Somehow I was expecting either a fatal error or a roll-back to previous @ISA. Not sure if that in itself is a bug; it sure seems less than optimal.
Using block eval\, I _can_ unshift qw/ A B C D / on @ISA\, but it results in ("A"\, undef\, undef\, undef). Somehow. (There's a hint in the number of undefs there\, right?)
(In either case\, push/unshift runs a 101 loop\, and when @ISA is actually used\, it blows up again.)
Eirik
* Vadim Pushtaev via RT \perlbug\-followup@​perl\.org [2015-09-18 12:35]:
On Fri Sep 18 03:28:24 2015\, aristotle wrote:
* Vadim Pushtaev via RT \perlbug\-followup@​perl\.org [2015-09-18 09:30]:
I don't quite understand why it generates any warnings at all. Pushing (and unshifting) undef is totally legit.
How so? It only makes sense for @ISA to contain package name strings. What should inheriting from an undef package mean?
I mean\, there is a problem with inheritance\, yes\, but not with pushing value into array
But at some point perl will try to use an @ISA entry as a package name and at that point it must convert the undef to a string\, so then it must warn. Even if @ISA were not otherwise special\, it would still be better for that warning to be triggered the instant you put the useless value on the array\, instead of e.g. 5 source files later when you go to call a method from the package\, because that way it’s much easier to find how the nonsense value got into @ISA.
(even though it's a special array).
But it is a special array. As soon as you touch it\, perl updates various things behind the scenes related to the inheritance graph as a whole. I don’t see any benefit from trying to hide that @ISA is not the same as a regular array. If you need a regular array\, use a regular array.
Regards\, -- Aristotle Pagaltzis // \<http://plasmasturm.org/>
On Sep 18\, 2015\, at 12:27 PM\, Aristotle Pagaltzis \pagaltzis@​gmx\.de wrote:
* Vadim Pushtaev via RT \perlbug\-followup@​perl\.org [2015-09-18 09:30]:
I don't quite understand why it generates any warnings at all. Pushing (and unshifting) undef is totally legit.
How so? It only makes sense for @ISA to contain package name strings. What should inheriting from an undef package mean?
Exactly. undef is wrong. valid types for @INC are PV\, AVREF and CVREF. warning on wrong types is very good.
Reini Urban \reini\.urban@​gmail\.com writes:
On Sep 18\, 2015\, at 12:27 PM\, Aristotle Pagaltzis \pagaltzis@​gmx\.de wrote:
* Vadim Pushtaev via RT \perlbug\-followup@​perl\.org [2015-09-18 09:30]:
I don't quite understand why it generates any warnings at all. Pushing (and unshifting) undef is totally legit.
How so? It only makes sense for @ISA to contain package name strings. What should inheriting from an undef package mean?
Exactly. undef is wrong. valid types for @INC are PV\, AVREF and CVREF. warning on wrong types is very good.
Nobody is disputing that. Can we please get back to the actual problem: the second and subsequent values in unshift(@ISA\, …) become undef\, and then it warns about that 101 times before dying with "Recursive inheritance detected".
-- "I use RMS as a guide in the same way that a boat captain would use a lighthouse. It's good to know where it is\, but you generally don't want to find yourself in the same spot." - Tollef Fog Heen
On Fri\, 18 Sep 2015 16:14:34 +0100 ilmari@ilmari.org (Dagfinn Ilmari Mannsåker) wrote:
Nobody is disputing that. Can we please get back to the actual problem: the second and subsequent values in unshift(@ISA\, …) become undef\, and then it warns about that 101 times before dying with "Recursive inheritance detected".
Random guess: 'unshift' has to create multiple holes at the start of the array so it doesn't suffer O(n^2) behaviour. Maybe it's these holes that perl objects to\, checking each subsequent one after setting individual slots?
my @arr = (1\,2\,3); unshift @arr\, (4\,5\,6);
==> @arr = ( 1\, 2\, 3 ) @arr = ( undef\, undef\, undef\, 1\, 2\, 3 ) @arr = ( 4\, undef\, undef\, 1\, 2\, 3 ) @arr = ( 4\, 5\, undef\, 1\, 2\, 3 ) @arr = ( 4\, 5\, 6\, 1\, 2\, 3 )
-- Paul "LeoNerd" Evans
leonerd@leonerd.org.uk http://www.leonerd.org.uk/ | https://metacpan.org/author/PEVANS
On Fri Sep 18 08:24:21 2015\, leonerd@leonerd.org.uk wrote:
On Fri\, 18 Sep 2015 16:14:34 +0100 ilmari@ilmari.org (Dagfinn Ilmari Mannsåker) wrote:
Nobody is disputing that. Can we please get back to the actual problem: the second and subsequent values in unshift(@ISA\, …) become undef\, and then it warns about that 101 times before dying with "Recursive inheritance detected".
Random guess: 'unshift' has to create multiple holes at the start of the array so it doesn't suffer O(n^2) behaviour. Maybe it's these holes that perl objects to\, checking each subsequent one after setting individual slots?
my @arr = (1\,2\,3); unshift @arr\, (4\,5\,6);
==> @​arr = \( 1\, 2\, 3 \) @​arr = \( undef\, undef\, undef\, 1\, 2\, 3 \) @​arr = \( 4\, undef\, undef\, 1\, 2\, 3 \) @​arr = \( 4\, 5\, undef\, 1\, 2\, 3 \) @​arr = \( 4\, 5\, 6\, 1\, 2\, 3 \)
Look like this.
Unshifting actually works outside the "main" package:
perl -we 'package Test; our @ISA; unshift @ISA\, 1\, 2\, 3; print @ISA' Use of uninitialized value within @Test::ISA in unshift at -e line 1. Use of uninitialized value within @Test::ISA in unshift at -e line 1. Use of uninitialized value within @Test::ISA in unshift at -e line 1. 123
I still warns but @ISA contains (1\,2\,3) afterwards.
Paul "LeoNerd" Evans wrote:
Random guess: 'unshift' has to create multiple holes at the start of the array so it doesn't suffer O(n^2) behaviour.
Pretty much. pp_unshift() internally performs an av_unshift() followed by a bunch of av_store()s. av_unshift() doesn't take parameters for the values to unshift; it always sticks undefs in. (Actually null pointers internally.) The av_store() calls invoke magic on the array.
-zefram
"Paul \"LeoNerd\" Evans" \leonerd@​leonerd\.org\.uk writes:
On Fri\, 18 Sep 2015 16:14:34 +0100 ilmari@ilmari.org (Dagfinn Ilmari Mannsåker) wrote:
Nobody is disputing that. Can we please get back to the actual problem: the second and subsequent values in unshift(@ISA\, …) become undef\, and then it warns about that 101 times before dying with "Recursive inheritance detected".
Random guess: 'unshift' has to create multiple holes at the start of the array so it doesn't suffer O(n^2) behaviour. Maybe it's these holes that perl objects to\, checking each subsequent one after setting individual slots?
my @arr = (1\,2\,3); unshift @arr\, (4\,5\,6);
==> @​arr = \( 1\, 2\, 3 \) @​arr = \( undef\, undef\, undef\, 1\, 2\, 3 \) @​arr = \( 4\, undef\, undef\, 1\, 2\, 3 \) @​arr = \( 4\, 5\, undef\, 1\, 2\, 3 \) @​arr = \( 4\, 5\, 6\, 1\, 2\, 3 \)
Sounds plausible. If we do it in a package other than "main"\, so we don't get the recursive inheritance error\, we get the number of warnings we would expect from that:
$ perl -wE 'package Foo; unshift @ISA\, qw(A B C); say "@ISA"' 2>&1 | uniq -c 3 Use of uninitialized value in unshift at -e line 1. 1 A B C
$ perl -wE 'package Foo; @ISA = (undef\, undef\, undef);' 2>&1 | uniq -c 3 Use of uninitialized value in list assignment at -e line 1.
There's a separate bug in that storing undef in @main::ISA warns 101 times before dying with "Recursive inheritance detected". The latter is arguably correct\, since undef stringifies to ""\, which means main:
$ perl -wE 'push @ISA\, ""' Recursive inheritance detected in package 'main' at -e line 1.
-- - Twitter seems more influential [than blogs] in the 'gets reported in the mainstream press' sense at least. - Matt McLeod - That'd be because the content of a tweet is easier to condense down to a mainstream media article. - Calle Dybedahl
Vadim Pushtaev via RT wrote:
Unshifting actually works outside the "main" package:
The undefs\, when treated as class names\, are being coerced to the empty string\, which is an irregular name for the "main" package:
$ perl -lwe 'sub foo {"main::foo"} package Bar; @ISA = (undef); print Bar->foo' Use of uninitialized value in list assignment at -e line 1. main::foo
Hence the "recursive inheritance" when it's done in "main". That's another red herring. The problem at hand is really that the class system sees the undefs at all.
-zefram
On Fri\, 18 Sep 2015 16:38:11 +0100 ilmari@ilmari.org (Dagfinn Ilmari Mannsåker) wrote:
There's a separate bug in that storing undef in @main::ISA warns 101 times before dying with "Recursive inheritance detected".
Oops; sounds like the code to detect and warn against the chance of an infinite recursion bug itself suffers an infinite recursion bug.
recursion bug [n]: see 'recursion bug'
-- Paul "LeoNerd" Evans
leonerd@leonerd.org.uk http://www.leonerd.org.uk/ | https://metacpan.org/author/PEVANS
Zefram \zefram@​fysh\.org writes:
Vadim Pushtaev via RT wrote:
Unshifting actually works outside the "main" package:
The undefs\, when treated as class names\, are being coerced to the empty string\, which is an irregular name for the "main" package:
$ perl -lwe 'sub foo {"main::foo"} package Bar; @ISA = (undef); print Bar->foo' Use of uninitialized value in list assignment at -e line 1. main::foo
And the repeated warnings come from Perl_sv_2pv_flags() via SvPV_const(keysv\, klen) in hv_common(PL_stashcache\, namesv\, …) which is called by gv_stashsv(sv\, 0)\, which is called by S_mro_get_linear_isa_{dfs\,c3}\, which throw "Recursive inheritance" error after 100 levels of recursion.
-- "A disappointingly low fraction of the human race is\, at any given time\, on fire." - Stig Sandbeck Mathisen
Zefram \zefram@​fysh\.org writes:
Paul "LeoNerd" Evans wrote:
Random guess: 'unshift' has to create multiple holes at the start of the array so it doesn't suffer O(n^2) behaviour.
Pretty much. pp_unshift() internally performs an av_unshift() followed by a bunch of av_store()s. av_unshift() doesn't take parameters for the values to unshift; it always sticks undefs in. (Actually null pointers internally.) The av_store() calls invoke magic on the array.
Turns out there is a mechanism to delay the @ISA set magic until all the items have been assigned\, which pp_push() uses\, but not pp_unshift(). The attached patch applies it to the latter too.
I also noticed that pp_push() does:
SV *sv; if (*MARK) SvGETMAGIC(*MARK); sv = newSV(0); if (*MARK) sv_setsv_nomg(sv\, *MARK); av_store(ary\, AvFILLp(ary)+1\, sv);
while pp_unshift() just does:
SV * const sv = newSVsv(*++MARK); (void)av_store(ary\, i++\, sv);
Are they equivalent? If so\, can pp_push() be simplfied? If not\, does pp_unshift() need fixing?
-- "I use RMS as a guide in the same way that a boat captain would use a lighthouse. It's good to know where it is\, but you generally don't want to find yourself in the same spot." - Tollef Fog Heen
On Fri\, 18 Sep 2015 17:48:12 +0100 ilmari@ilmari.org (Dagfinn Ilmari Mannsåker) wrote:
+ PL_delaymagic = DM_DELAY; while (MARK \< SP) { SV * const sv = newSVsv(*++MARK); (void)av_store(ary\, i++\, sv); } + if (PL_delaymagic & DM_ARRAY_ISA) + mg_set(MUTABLE_SV(ary)); + + PL_delaymagic = 0;
Small thought - does that want to save/restore the old delay?
int old_delay = PL_delaymagic; PL_delaymagic = DM_DELAY;
...
PL_delaymagic = old_delay;
-- Paul "LeoNerd" Evans
leonerd@leonerd.org.uk http://www.leonerd.org.uk/ | https://metacpan.org/author/PEVANS
"Paul \"LeoNerd\" Evans" \leonerd@​leonerd\.org\.uk writes:
Small thought - does that want to save/restore the old delay?
int old_delay = PL_delaymagic; PL_delaymagic = DM_DELAY;
...
PL_delaymagic = old_delay;
Pl_delaymagic is only used in pp_push (and now pp_unshift) for delaying @ISA magic and in pp_aassign for delaying @ISA and uid/gid magic\, so I don't see why that would be necessary.
-- "A disappointingly low fraction of the human race is\, at any given time\, on fire." - Stig Sandbeck Mathisen
* Reini Urban \reini\.urban@​gmail\.com [2015-09-18 16:10]:
On Sep 18\, 2015\, at 12:27 PM\, Aristotle Pagaltzis \pagaltzis@​gmx\.de wrote:
* Vadim Pushtaev via RT \perlbug\-followup@​perl\.org [2015-09-18 09:30]:
I don't quite understand why it generates any warnings at all. Pushing (and unshifting) undef is totally legit.
How so? It only makes sense for @ISA to contain package name strings. What should inheriting from an undef package mean?
Exactly. undef is wrong. valid types for @INC are PV\, AVREF and CVREF. warning on wrong types is very good.
This ticket is about @ISA\, not @INC.
On Fri\, Sep 18\, 2015\, 12:59 Dagfinn Ilmari Mannsåker \ilmari@​ilmari\.org wrote:
"Paul \"LeoNerd\" Evans" \leonerd@​leonerd\.org\.uk writes:
Small thought - does that want to save/restore the old delay?
int old_delay = PL_delaymagic; PL_delaymagic = DM_DELAY;
...
PL_delaymagic = old_delay;
Pl_delaymagic is only used in pp_push (and now pp_unshift) for delaying @ISA magic and in pp_aassign for delaying @ISA and uid/gid magic\, so I don't see why that would be necessary.
-- "A disappointingly low fraction of the human race is\, at any given time\, on fire." - Stig Sandbeck
Mathisen
What about splice?
On Sep 19\, 2015\, at 1:38 AM\, Aristotle Pagaltzis \pagaltzis@​gmx\.de wrote:
* Reini Urban \reini\.urban@​gmail\.com [2015-09-18 16:10]:
On Sep 18\, 2015\, at 12:27 PM\, Aristotle Pagaltzis \pagaltzis@​gmx\.de wrote:
* Vadim Pushtaev via RT \perlbug\-followup@​perl\.org [2015-09-18 09:30]:
I don't quite understand why it generates any warnings at all. Pushing (and unshifting) undef is totally legit.
How so? It only makes sense for @ISA to contain package name strings. What should inheriting from an undef package mean?
Exactly. undef is wrong. valid types for @INC are PV\, AVREF and CVREF. warning on wrong types is very good.
This ticket is about @ISA\, not @INC.
Oops\, sorry. Mixed it up.
"Chas. Owens" \chas\.owens@​gmail\.com writes:
On Fri\, Sep 18\, 2015\, 12:59 Dagfinn Ilmari Mannsåker \ilmari@​ilmari\.org wrote:
Pl_delaymagic is only used in pp_push (and now pp_unshift) for delaying @ISA magic and in pp_aassign for delaying @ISA and uid/gid magic\, so I don't see why that would be necessary.
What about splice?
pp_splice does not use PL_delaymagic\, but also does not seem to suffer from the undef problem of pp_unshift. The code is too complex for me to figure out exactly why this is the case right now.
-- "A disappointingly low fraction of the human race is\, at any given time\, on fire." - Stig Sandbeck Mathisen
ilmari@ilmari.org (Dagfinn Ilmari Mannsåker) writes:
"Chas. Owens" \chas\.owens@​gmail\.com writes:
On Fri\, Sep 18\, 2015\, 12:59 Dagfinn Ilmari Mannsåker \ilmari@​ilmari\.org wrote:
Pl_delaymagic is only used in pp_push (and now pp_unshift) for delaying @ISA magic and in pp_aassign for delaying @ISA and uid/gid magic\, so I don't see why that would be necessary.
What about splice?
pp_splice does not use PL_delaymagic\, but also does not seem to suffer from the undef problem of pp_unshift. The code is too complex for me to figure out exactly why this is the case right now.
A bit more thorough read of the code reveals that it manipulates the contents of AvARRAY directly\, and then calls mg_set() at the end\, so it's from premature @ISA magic triggering from av_store().
-- "The surreality of the universe tends towards a maximum" -- Skud's Law "Never formulate a law or axiom that you're not prepared to live with the consequences of." -- Skud's Meta-Law
ilmari@ilmari.org (Dagfinn Ilmari Mannsåker) writes:
A bit more thorough read of the code reveals that it manipulates the contents of AvARRAY directly\, and then calls mg_set() at the end\, so it's from premature @ISA magic triggering from av_store(). ^ safe
-- - Twitter seems more influential [than blogs] in the 'gets reported in the mainstream press' sense at least. - Matt McLeod - That'd be because the content of a tweet is easier to condense down to a mainstream media article. - Calle Dybedahl
On Fri Sep 18 09:59:11 2015\, ilmari wrote:
"Paul \"LeoNerd\" Evans" \leonerd@​leonerd\.org\.uk writes:
Small thought - does that want to save/restore the old delay?
int old_delay = PL_delaymagic; PL_delaymagic = DM_DELAY;
...
PL_delaymagic = old_delay;
Pl_delaymagic is only used in pp_push (and now pp_unshift) for delaying @ISA magic and in pp_aassign for delaying @ISA and uid/gid magic\, so I don't see why that would be necessary.
While your patch does the same thing as pp_push\, I'm not sure if there are cases where zeroing PL_delaymagic rather than saving/restoring is incorrect.
If the value being pushed is tied\, and the FETCH handler does a push(@Some::ISA) that will clear PL_delaymagic and so it won't be delayed later.
With your patch the following warns for me:
use strict; use warnings;
my $x;
tie $x\, 'F';
unshift @X::ISA\, $x\, "Z";
package X;
package Y;
package Z;
sub foo { }
package F; use parent 'Tie::Scalar';
sub TIESCALAR { bless {}; }
sub FETCH { push @G::ISA\, "H"; "Y"; }
package G;
package H;
So it looks like the existing code in pp_push() is incorrect\, as well as the similar code in your patch\, and probably other code zeroing PL_delaymagic after use.
Also\, rather then Paul's save code\, we should probably use a SAVE*() macro\, so if magic croaks we can recover correctly.
Tony
"Tony Cook via RT" \perlbug\-followup@​perl\.org writes:
On Fri Sep 18 09:59:11 2015\, ilmari wrote:
"Paul \"LeoNerd\" Evans" \leonerd@​leonerd\.org\.uk writes:
Small thought - does that want to save/restore the old delay?
int old_delay = PL_delaymagic; PL_delaymagic = DM_DELAY;
...
PL_delaymagic = old_delay;
Pl_delaymagic is only used in pp_push (and now pp_unshift) for delaying @ISA magic and in pp_aassign for delaying @ISA and uid/gid magic\, so I don't see why that would be necessary.
While your patch does the same thing as pp_push\, I'm not sure if there are cases where zeroing PL_delaymagic rather than saving/restoring is incorrect.
If the value being pushed is tied\, and the FETCH handler does a push(@Some::ISA) that will clear PL_delaymagic and so it won't be delayed later.
Here's an updated patch that fixes that for both pp_push() and pp_unshift(). pp_aassign() needs fixing similarly\, but that's too convoluted for me to wrap my brain around at the moment.
With your patch the following warns for me:
use strict; use warnings;
my $x;
tie $x\, 'F';
unshift @X::ISA\, $x\, "Z";
package X;
package Y;
package Z;
sub foo { }
package F; use parent 'Tie::Scalar';
sub TIESCALAR { bless {}; }
sub FETCH { push @G::ISA\, "H"; "Y"; }
package G;
package H;
So it looks like the existing code in pp_push() is incorrect\, as well as the similar code in your patch\, and probably other code zeroing PL_delaymagic after use.
Also\, rather then Paul's save code\, we should probably use a SAVE*() macro\, so if magic croaks we can recover correctly.
Tony
--- via perlbug: queue: perl5 status: open https://rt-archive.perl.org/perl5/Ticket/Display.html?id=126082
-- - Twitter seems more influential [than blogs] in the 'gets reported in the mainstream press' sense at least. - Matt McLeod - That'd be because the content of a tweet is easier to condense down to a mainstream media article. - Calle Dybedahl
On Tue\, Sep 22\, 2015 at 12:06:11PM +0100\, Dagfinn Ilmari Mannsåker wrote:
"Tony Cook via RT" \perlbug\-followup@​perl\.org writes:
While your patch does the same thing as pp_push\, I'm not sure if there are cases where zeroing PL_delaymagic rather than saving/restoring is incorrect. Here's an updated patch that fixes that for both pp_push() and pp_unshift(). pp_aassign() needs fixing similarly\, but that's too convoluted for me to wrap my brain around at the moment.
+ ENTER; + SAVEI16(PL_delaymagic); [snip] + LEAVE;
Using the savestack has a quite a performance penalty. Using Porting/bench.pl to measure 'push @a\, 2' after a setup of 'my @a = 1'\, I got the following raw read\, write etc counts:
A: bleadperl with all PL_delaymagic code removed B: bleadperl C: bleadperl plus ENTER/SAVE(PL_delaymagic)/LEAVE
A B C -------- -------- -------- Ir 502.0 510.0 605.0 Dr 148.1 149.1 178.1 Dw 91.8 93.8 113.8 COND 77.3 78.3 87.3 IND 6.3 6.3 7.3
COND_m 4.3 4.1 3.8 IND_m 4.0 4.0 4.0
Ir_m1 0.1 0.2 0.1 Dr_m1 1.4 1.4 0.5 Dw_m1 0.7 0.7 0.7
Ir_mm 0.0 0.0 0.0 Dr_mm 0.0 0.0 0.0 Dw_mm 0.0 0.0 0.0
As you can see\, it added about a 20% overhead to the sum of padav(@a); const(1); push().
I wonder whether instead we could:
* in pp_push() etc just do
U16 = old_delay = PL_delaymagic; PL_delaymagic = ...; ... PL_delaymagic = old_delay;
* then add a 'saved_delaymagic' field to the jmpenv struct\, then make JMPENV_PUSH and JMPENV_POP save and restore PL_delaymagic.
That way the var gets restored on both normal and exception scope exits\, which not having a penalty in hot code like pp_hot and pp_aassign.
Or perhaps the whole PL_delaymagic thing needs rethinking\, and that perhaps there's a better way to do this. Not that I can think of one yet.
PS:
Ironically the PL_delaymagic code in pp_push seems to have been added purely as an efficiency measure\, so that 'push @ISA\, "X"\, "Y" doesn't have to recompute all the MRO stuff twice.
-- Counsellor Troi states something other than the blindingly obvious. -- Things That Never Happen in "Star Trek" #16
On Thu\, Oct 01\, 2015 at 11:50:19AM +0100\, Dave Mitchell wrote:
As you can see\, it added about a 20% overhead to the sum of padav(@a); const(1); push().
I wonder whether instead we could:
* in pp_push() etc just do
U16 = old\_delay = PL\_delaymagic; PL\_delaymagic = \.\.\.; \.\.\. PL\_delaymagic = old\_delay;
* then add a 'saved_delaymagic' field to the jmpenv struct\, then make JMPENV_PUSH and JMPENV_POP save and restore PL_delaymagic.
That way the var gets restored on both normal and exception scope exits\, which not having a penalty in hot code like pp_hot and pp_aassign.
I have now implemented that. Along with your patch\, I've just pushed it for smoking as smoke-me/davem/delaymg.
bench.pl shows that pp_push\, pp_unshift and pp_aassign are almost back at blead levels:
A = blead B = your patch: av_unshift fixed\, ENTER/SAVE/LEAVE added C = smoke-me/davem/delaymg: ENTER etc removed\, pp_aassign fixed
@a = (1\,2) A B C -------- -------- --------- Ir 1007.0 1007.0 1009.0 Dr 307.0 307.0 309.0 Dw 206.0 206.0 207.0 COND 137.0 137.0 137.0 IND 12.0 12.0 12.0
COND_m 2.0 1.8 2.0 IND_m 5.0 5.0 5.0
Ir_m1 0.0 0.0 0.1 Dr_m1 0.0 0.0 0.0 Dw_m1 0.0 0.0 0.0
Ir_mm 0.0 0.0 0.0 Dr_mm 0.0 0.0 0.0 Dw_mm 0.0 0.0 0.0
push @a\, 2 A B C -------- -------- --------- Ir 519.5 614.5 521.5 Dr 151.3 180.3 153.3 Dw 95.3 115.3 96.3 COND 80.2 89.2 80.2 IND 6.3 7.3 6.3
COND_m 4.5 4.3 4.9 IND_m 4.0 4.0 4.0
Ir_m1 0.1 -0.1 0.2 Dr_m1 0.5 0.4 0.2 Dw_m1 0.8 0.9 0.9
Ir_mm 0.0 0.0 0.0 Dr_mm 0.0 0.0 0.0 Dw_mm 0.0 0.0 0.0
unshift @a\, 2
A B C -------- -------- --------- Ir 500.7 601.7 508.7 Dr 147.1 177.1 150.1 Dw 91.6 113.6 94.6 COND 74.4 84.4 75.4 IND 6.3 7.3 6.3
COND_m 4.9 5.0 4.2 IND_m 4.1 4.1 4.1
Ir_m1 1.0 1.0 1.1 Dr_m1 1.2 0.7 0.9 Dw_m1 0.1 0.1 0.2
Ir_mm 0.0 0.0 0.0 Dr_mm 0.1 0.1 0.1 Dw_mm 0.0 0.0 0.0
-- Fire extinguisher (n) a device for holding open fire doors.
Dave Mitchell \davem@​iabyn\.com writes:
On Thu\, Oct 01\, 2015 at 11:50:19AM +0100\, Dave Mitchell wrote:
As you can see\, it added about a 20% overhead to the sum of padav(@a); const(1); push().
I wonder whether instead we could:
* in pp_push() etc just do
U16 = old\_delay = PL\_delaymagic; PL\_delaymagic = \.\.\.; \.\.\. PL\_delaymagic = old\_delay;
* then add a 'saved_delaymagic' field to the jmpenv struct\, then make JMPENV_PUSH and JMPENV_POP save and restore PL_delaymagic.
That way the var gets restored on both normal and exception scope exits\, which not having a penalty in hot code like pp_hot and pp_aassign.
I have now implemented that. Along with your patch\, I've just pushed it for smoking as smoke-me/davem/delaymg.
Thanks for doing the work to fix the performance regression caused by my naïve approach (I know hardly anything about scope/exception handling in C/XS space).
bench.pl shows that pp_push\, pp_unshift and pp_aassign are almost back at blead levels:
Looks good to me.
-- "The surreality of the universe tends towards a maximum" -- Skud's Law "Never formulate a law or axiom that you're not prepared to live with the consequences of." -- Skud's Meta-Law
On Tue\, Oct 13\, 2015 at 08:10:00PM +0100\, Dagfinn Ilmari Mannsåker wrote:
Dave Mitchell \davem@​iabyn\.com writes:
On Thu\, Oct 01\, 2015 at 11:50:19AM +0100\, Dave Mitchell wrote:
As you can see\, it added about a 20% overhead to the sum of padav(@a); const(1); push().
I wonder whether instead we could:
* in pp_push() etc just do
U16 = old\_delay = PL\_delaymagic; PL\_delaymagic = \.\.\.; \.\.\. PL\_delaymagic = old\_delay;
* then add a 'saved_delaymagic' field to the jmpenv struct\, then make JMPENV_PUSH and JMPENV_POP save and restore PL_delaymagic.
That way the var gets restored on both normal and exception scope exits\, which not having a penalty in hot code like pp_hot and pp_aassign.
I have now implemented that. Along with your patch\, I've just pushed it for smoking as smoke-me/davem/delaymg.
Thanks for doing the work to fix the performance regression caused by my naïve approach (I know hardly anything about scope/exception handling in C/XS space).
Well\, you took the 'correct' approach\, just not the fastest :-)
Your commit and my follow-up now merged into blead as
a68090f optimise save/restore of PL_delaymagic. 3953914 Delay @ISA magic while unshifting
-- O Unicef Clearasil! Gibberish and Drivel! -- "Bored of the Rings"
@iabyn - Status changed from 'open' to 'pending release'
Thank you for submitting this report. You have helped make Perl better.
With the release of Perl 5.24.0 on May 9\, 2016\, this and 149 other issues have been resolved.
Perl 5.24.0 may be downloaded via https://metacpan.org/release/RJBS/perl-5.24.0
@khwilliamson - Status changed from 'pending release' to 'resolved'
Migrated from rt.perl.org#126082 (status was 'resolved')
Searchable as RT126082$