local %SIG = (%SIG, $signame => ...) not working as expected?

Hi all, I noticed "local %SIG = (%SIG, PIPE => sub { ... })"
wasn't restoring the old PIPE handler as I expected when I left
that scope, but "local $SIG{PIPE} = sub { ... }" restores the
old handler fine.

I've relied on a similar thing "local %ENV = (%ENV, k => $v)"
for ages, so is this anomaly for %SIG documented/expected?

Example here:
----------8<---------
use strict;
use warnings;
use Data::Dumper;
$Data::Dumper::Deparse = 1;

# this works as expected
print 'outside before ', Dumper($SIG{PIPE});
{
	local $SIG{PIPE} = sub { print "SIGPIPE\n" };
	print 'inside #1', Dumper($SIG{PIPE});
}
print 'outside middle expect and is undef', Dumper($SIG{PIPE});

# this does not work as expected
{
	local %SIG = (%SIG, PIPE => sub { print "SIGPIPE\n" });
	print 'inside #2 is sub', Dumper($SIG{PIPE});
}
print 'outside after expect undef, is sub?: ', Dumper($SIG{PIPE});
kill 'PIPE', $$;
select undef, undef, undef, 0.1; # wait for SIGPIPE to hit
# "SIGPIPE\n" printed, why?
----------8<---------
Thanks for any answer you can provide.

Perl 5.32.0 on FreeBSD 11.x, but happens on 5.28.1 on Debian 10, too
0
p5p
1/12/2021 7:31:45 PM
perl.perl5.porters 48287 articles. 1 followers. Follow

9 Replies
427 Views

Similar Articles

[PageSpeed] 15
Get it on Google Play
Get it on Apple App Store

Hi Eric!

On Tue, Jan 12, 2021 at 1:32 PM Eric Wong <p5p@yhbt.net> wrote:
>
> I've relied on a similar thing "local %ENV = (%ENV, k => $v)"
> for ages, so is this anomaly for %SIG documented/expected?

I wonder if you could be running into an entry in %ENV with a undef
value?  In that case we could end up with an odd number of
hash-elements and worse.  Perl will ignore the undef values from
hashes "exploded" within parens, e.g. within the ... part of @x = (
.... ).  When we come to assign the resulting list back into a new hash
we then get "misalignments".

> Thanks for any answer you can provide.

TIA for clarifying where this suggestion turned out to be wrong or unhelpful :)

Regards!
Corwin
0
corwin
1/12/2021 8:40:26 PM
On 1/12/21 3:40 PM, Corwin Brust wrote:
> Hi Eric!
>
> On Tue, Jan 12, 2021 at 1:32 PM Eric Wong <p5p@yhbt.net> wrote:
>> I've relied on a similar thing "local %ENV = (%ENV, k => $v)"
>> for ages, so is this anomaly for %SIG documented/expected?
> I wonder if you could be running into an entry in %ENV with a undef
> value?  In that case we could end up with an odd number of
> hash-elements and worse.  Perl will ignore the undef values from
> hashes "exploded" within parens, e.g. within the ... part of @x = (
> ... ).  When we come to assign the resulting list back into a new hash
> we then get "misalignments".

i wonder why he copies %ENV. he should be able to just do:

     local( $SIG{$signame} ) = blah ;

the is faster and doesn't have the odd number thing you mention

uri

0
uri
1/12/2021 8:44:09 PM
--89c5961940bd44f290dd2d7f196e512d
Content-Type: text/plain

On Tue, Jan 12, 2021, at 3:40 PM, Corwin Brust wrote:
> I wonder if you could be running into an entry in %ENV with a undef
> value?  In that case we could end up with an odd number of
> hash-elements and worse.  Perl will ignore the undef values from
> hashes "exploded" within parens, e.g. within the ... part of @x = (
> ... ).  When we come to assign the resulting list back into a new hash
> we then get "misalignments".

That is incorrect.

use v5.30.0;

my %hash  = (a => undef, b => 1);
my @array = %hash;
my %other = @array;

use Data::Dumper;
print Dumper(\%other);

Output:
$VAR1 = {
          'a' => undef,
          'b' => 1
        };

You may be thinking of the common mistake where someone puts a subroutine call into a hash assignment:

%hash = (
  a => subroutine(),
  b => 1,
);

In that case, subroutine() may return something other than a single element, which could be surprising.  If it returns an even number of elements, it also throws b from the key position to the value position.  In that case, you generally want to put "scalar" before subroutine.

undef is already a scalar value.  It does not cause this problem.

-- 
rjbs
--89c5961940bd44f290dd2d7f196e512d
Content-Type: text/html
Content-Transfer-Encoding: quoted-printable

<!DOCTYPE html><html><head><title></title><style type=3D"text/css">p.Mso=
Normal,p.MsoNoSpacing{margin:0}</style></head><body><div>On Tue, Jan 12,=
 2021, at 3:40 PM, Corwin Brust wrote:<br></div><blockquote type=3D"cite=
" id=3D"qt" style=3D""><div>I wonder if you could be running into an ent=
ry in %ENV with a undef<br></div><div>value?&nbsp; In that case we could=
 end up with an odd number of<br></div><div>hash-elements and worse.&nbs=
p; Perl will ignore the undef values from<br></div><div>hashes "exploded=
" within parens, e.g. within the ... part of @x =3D (<br></div><div>... =
).&nbsp; When we come to assign the resulting list back into a new hash<=
br></div><div>we then get "misalignments".<br></div></blockquote><div><b=
r></div><div>That is incorrect.<br></div><div><br></div><pre style=3D"bo=
rder-top-width:1px;border-right-width:1px;border-bottom-width:1px;border=
-left-width:1px;border-top-style:solid;border-right-style:solid;border-b=
ottom-style:solid;border-left-style:solid;border-top-color:rgb(204, 204,=
 204);border-right-color:rgb(204, 204, 204);border-bottom-color:rgb(204,=
 204, 204);border-left-color:rgb(204, 204, 204);border-image-source:init=
ial;border-image-slice:initial;border-image-width:initial;border-image-o=
utset:initial;border-image-repeat:initial;border-top-left-radius:3px;bor=
der-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-le=
ft-radius:3px;background-image:initial;background-position-x:initial;bac=
kground-position-y:initial;background-size:initial;background-repeat-x:i=
nitial;background-repeat-y:initial;background-attachment:initial;backgro=
und-origin:initial;background-clip:initial;background-color:rgb(246, 246=
, 246);font-family:menlo, consolas, monospace;font-size:90%;margin-top:7=
px;margin-right:0px;margin-bottom:7px;margin-left:0px;padding-top:7px;pa=
dding-right:10px;padding-bottom:7px;padding-left:10px;white-space:pre-wr=
ap;overflow-wrap:break-word;">use v5.30.0;

my %hash  =3D (a =3D&gt; undef, b =3D&gt; 1);
my @array =3D %hash;
my %other =3D @array;

use Data::Dumper;
print Dumper(\%other);<br></pre><div><br></div><div>Output:<br></div><pr=
e style=3D"border-top-width:1px;border-right-width:1px;border-bottom-wid=
th:1px;border-left-width:1px;border-top-style:solid;border-right-style:s=
olid;border-bottom-style:solid;border-left-style:solid;border-top-color:=
rgb(204, 204, 204);border-right-color:rgb(204, 204, 204);border-bottom-c=
olor:rgb(204, 204, 204);border-left-color:rgb(204, 204, 204);border-imag=
e-source:initial;border-image-slice:initial;border-image-width:initial;b=
order-image-outset:initial;border-image-repeat:initial;border-top-left-r=
adius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;bor=
der-bottom-left-radius:3px;background-image:initial;background-position-=
x:initial;background-position-y:initial;background-size:initial;backgrou=
nd-repeat-x:initial;background-repeat-y:initial;background-attachment:in=
itial;background-origin:initial;background-clip:initial;background-color=
:rgb(246, 246, 246);font-family:menlo, consolas, monospace;font-size:90%=
;margin-top:7px;margin-right:0px;margin-bottom:7px;margin-left:0px;paddi=
ng-top:7px;padding-right:10px;padding-bottom:7px;padding-left:10px;white=
-space:pre-wrap;overflow-wrap:break-word;">$VAR1 =3D {
          'a' =3D&gt; undef,
          'b' =3D&gt; 1
        };<br></pre><div><br></div><div>You may be thinking of the commo=
n mistake where someone puts a subroutine call into a hash assignment:<b=
r></div><div><br></div><pre style=3D"border-top-width:1px;border-right-w=
idth:1px;border-bottom-width:1px;border-left-width:1px;border-top-style:=
solid;border-right-style:solid;border-bottom-style:solid;border-left-sty=
le:solid;border-top-color:rgb(204, 204, 204);border-right-color:rgb(204,=
 204, 204);border-bottom-color:rgb(204, 204, 204);border-left-color:rgb(=
204, 204, 204);border-image-source:initial;border-image-slice:initial;bo=
rder-image-width:initial;border-image-outset:initial;border-image-repeat=
:initial;border-top-left-radius:3px;border-top-right-radius:3px;border-b=
ottom-right-radius:3px;border-bottom-left-radius:3px;background-image:in=
itial;background-position-x:initial;background-position-y:initial;backgr=
ound-size:initial;background-repeat-x:initial;background-repeat-y:initia=
l;background-attachment:initial;background-origin:initial;background-cli=
p:initial;background-color:rgb(246, 246, 246);font-family:menlo, consola=
s, monospace;font-size:90%;margin-top:7px;margin-right:0px;margin-bottom=
:7px;margin-left:0px;padding-top:7px;padding-right:10px;padding-bottom:7=
px;padding-left:10px;white-space:pre-wrap;overflow-wrap:break-word;">%ha=
sh =3D (
  a =3D&gt; subroutine(),
  b =3D&gt; 1,
);<br></pre><div><br></div><div>In that case, subroutine() may return so=
mething other than a single element, which could be surprising.&nbsp; If=
 it returns an even number of elements, it also throws b from the key po=
sition to the value position.&nbsp; In that case, you generally want to =
put "scalar" before subroutine.<br></div><div><br></div><div>undef is al=
ready a scalar value.&nbsp; It does not cause this problem.</div><div><b=
r></div><div>--&nbsp;<br></div><div>rjbs</div></body></html>
--89c5961940bd44f290dd2d7f196e512d--
0
perl
1/12/2021 8:46:33 PM
Uri Guttman <uri@stemsystems.com> wrote:
> i wonder why he copies %ENV. he should be able to just do:
> 
>     local( $SIG{$signame} ) = blah ;
> 
> the is faster and doesn't have the odd number thing you mention

Laziness :)  I'm getting a hash(ref) of SIG overrides either as
a return value from another sub.  My workaround is something
like this:

	my %sig = $self->some_callback;
	local $SIG{$_} = $sig->{$_} for keys %sig;
	...

My original (broken) code was this:

	local %SIG = (%SIG, $self->some_callback);
0
p5p
1/12/2021 9:11:15 PM
--c2bceaafa74749ff9e6de5585b812872
Content-Type: text/plain;charset=utf-8
Content-Transfer-Encoding: quoted-printable

On Tue, Jan 12, 2021, at 4:11 PM, Eric Wong wrote:
> Uri Guttman <uri@stemsystems.com> wrote:
> > i wonder why he copies %ENV. he should be able to just do:
> >=20
> >     local( $SIG{$signame} ) =3D blah ;
> >=20
> > the is faster and doesn't have the odd number thing you mention
>=20
> Laziness :)  I'm getting a hash(ref) of SIG overrides either as
> a return value from another sub.  My workaround is something
> like this:
>=20
> my %sig =3D $self->some_callback;
> local $SIG{$_} =3D $sig->{$_} for keys %sig;

"something like" can cover a lot of ground here, but are you sure that y=
our workaround isn't so close to this that, like this, it just doesn't w=
ork?

X for Y is equivalent to "for (Y) { X }" including the enclosing scope, =
which delimits the effect of local.

use v5.30.0;
use Data::Dumper;

our %hash =3D (a =3D> 1, b =3D> 1);

{
  local $hash{$_} =3D 2 for keys %hash;

  print Dumper(\%hash);
}

{
  local %hash =3D %hash;
  $hash{$_} =3D 2 for keys %hash;

  print Dumper(\%hash);
}

print Dumper(\%hash);

=E2=80=A6which outputs=E2=80=A6

$VAR1 =3D {
          'a' =3D> 1,
          'b' =3D> 1
        };
$VAR1 =3D {
          'a' =3D> 2,
          'b' =3D> 2
        };
$VAR1 =3D {
          'a' =3D> 1,
          'b' =3D> 1
        };

--=20
rjbs
--c2bceaafa74749ff9e6de5585b812872
Content-Type: text/html;charset=utf-8
Content-Transfer-Encoding: quoted-printable

<!DOCTYPE html><html><head><title></title><style type=3D"text/css">p.Mso=
Normal,p.MsoNoSpacing{margin:0}</style></head><body><div>On Tue, Jan 12,=
 2021, at 4:11 PM, Eric Wong wrote:<br></div><blockquote type=3D"cite" i=
d=3D"qt" style=3D""><div>Uri Guttman &lt;<a href=3D"mailto:uri@stemsyste=
ms.com">uri@stemsystems.com</a>&gt; wrote:<br></div><div>&gt; i wonder w=
hy he copies %ENV. he should be able to just do:<br></div><div>&gt;&nbsp=
;<br></div><div>&gt; &nbsp;&nbsp;&nbsp; local( $SIG{$signame} ) =3D blah=
 ;<br></div><div>&gt;&nbsp;<br></div><div>&gt; the is faster and doesn't=
 have the odd number thing you mention<br></div><div><br></div><div>Lazi=
ness :)&nbsp; I'm getting a hash(ref) of SIG overrides either as<br></di=
v><div>a return value from another sub.&nbsp; My workaround is something=
<br></div><div>like this:<br></div><div><br></div><div>my %sig =3D $self=
-&gt;some_callback;<br></div><div>local $SIG{$_} =3D $sig-&gt;{$_} for k=
eys %sig;<br></div></blockquote><div><br></div><div>"something like" can=
 cover a lot of ground here, but are you sure that your workaround isn't=
 so close to this that, like this, it just doesn't work?<br></div><div><=
br></div><div>X for Y is equivalent to "for (Y) { X }" including the enc=
losing scope, which delimits the effect of local.<br></div><div><br></di=
v><pre style=3D"border-top-width:1px;border-right-width:1px;border-botto=
m-width:1px;border-left-width:1px;border-top-style:solid;border-right-st=
yle:solid;border-bottom-style:solid;border-left-style:solid;border-top-c=
olor:rgb(204, 204, 204);border-right-color:rgb(204, 204, 204);border-bot=
tom-color:rgb(204, 204, 204);border-left-color:rgb(204, 204, 204);border=
-image-source:initial;border-image-slice:initial;border-image-width:init=
ial;border-image-outset:initial;border-image-repeat:initial;border-top-l=
eft-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3p=
x;border-bottom-left-radius:3px;background-image:initial;background-posi=
tion-x:initial;background-position-y:initial;background-size:initial;bac=
kground-repeat-x:initial;background-repeat-y:initial;background-attachme=
nt:initial;background-origin:initial;background-clip:initial;background-=
color:rgb(246, 246, 246);font-family:menlo, consolas, monospace;font-siz=
e:90%;margin-top:7px;margin-right:0px;margin-bottom:7px;margin-left:0px;=
padding-top:7px;padding-right:10px;padding-bottom:7px;padding-left:10px;=
white-space:pre-wrap;overflow-wrap:break-word;">use v5.30.0;
use Data::Dumper;

our %hash =3D (a =3D&gt; 1, b =3D&gt; 1);

{
  local $hash{$_} =3D 2 for keys %hash;

  print Dumper(\%hash);
}

{
  local %hash =3D %hash;
  $hash{$_} =3D 2 for keys %hash;

  print Dumper(\%hash);
}

print Dumper(\%hash);<br></pre><div><br></div><div>=E2=80=A6which output=
s=E2=80=A6<br></div><div><br></div><pre style=3D"border-top-width:1px;bo=
rder-right-width:1px;border-bottom-width:1px;border-left-width:1px;borde=
r-top-style:solid;border-right-style:solid;border-bottom-style:solid;bor=
der-left-style:solid;border-top-color:rgb(204, 204, 204);border-right-co=
lor:rgb(204, 204, 204);border-bottom-color:rgb(204, 204, 204);border-lef=
t-color:rgb(204, 204, 204);border-image-source:initial;border-image-slic=
e:initial;border-image-width:initial;border-image-outset:initial;border-=
image-repeat:initial;border-top-left-radius:3px;border-top-right-radius:=
3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;backgro=
und-image:initial;background-position-x:initial;background-position-y:in=
itial;background-size:initial;background-repeat-x:initial;background-rep=
eat-y:initial;background-attachment:initial;background-origin:initial;ba=
ckground-clip:initial;background-color:rgb(246, 246, 246);font-family:me=
nlo, consolas, monospace;font-size:90%;margin-top:7px;margin-right:0px;m=
argin-bottom:7px;margin-left:0px;padding-top:7px;padding-right:10px;padd=
ing-bottom:7px;padding-left:10px;white-space:pre-wrap;overflow-wrap:brea=
k-word;">$VAR1 =3D {
          'a' =3D&gt; 1,
          'b' =3D&gt; 1
        };
$VAR1 =3D {
          'a' =3D&gt; 2,
          'b' =3D&gt; 2
        };
$VAR1 =3D {
          'a' =3D&gt; 1,
          'b' =3D&gt; 1
        };<br></pre><div><br></div><div>--&nbsp;<br></div><div>rjbs</div=
></body></html>
--c2bceaafa74749ff9e6de5585b812872--
0
perl
1/12/2021 9:27:00 PM
Eric Wong <p5p@yhbt.net> wrote:
:I'm getting a hash(ref) of SIG overrides either as
:a return value from another sub.  My workaround is something
:like this:
:
:	my %sig = $self->some_callback;
:	local $SIG{$_} = $sig->{$_} for keys %sig;
:	...

I wouldn't expect that to work, but you can use a hash slice instead:
  local @SIG{keys %sig} = values %sig;

I do this sort of thing a lot when I want to localize a variable subset
of elements, using a hash slice or array slice as relevant.

Hugo
0
hv
1/12/2021 10:32:45 PM
On Tue, Jan 12, 2021 at 8:32 PM Eric Wong <p5p@yhbt.net> wrote:
>
> Hi all, I noticed "local %SIG = (%SIG, PIPE => sub { ... })"
> wasn't restoring the old PIPE handler as I expected when I left
> that scope, but "local $SIG{PIPE} = sub { ... }" restores the
> old handler fine.
>
> I've relied on a similar thing "local %ENV = (%ENV, k => $v)"
> for ages, so is this anomaly for %SIG documented/expected?
>
> Example here:
> ----------8<---------
> use strict;
> use warnings;
> use Data::Dumper;
> $Data::Dumper::Deparse = 1;
>
> # this works as expected
> print 'outside before ', Dumper($SIG{PIPE});
> {
>         local $SIG{PIPE} = sub { print "SIGPIPE\n" };
>         print 'inside #1', Dumper($SIG{PIPE});
> }
> print 'outside middle expect and is undef', Dumper($SIG{PIPE});
>
> # this does not work as expected
> {
>         local %SIG = (%SIG, PIPE => sub { print "SIGPIPE\n" });
>         print 'inside #2 is sub', Dumper($SIG{PIPE});
> }
> print 'outside after expect undef, is sub?: ', Dumper($SIG{PIPE});
> kill 'PIPE', $$;
> select undef, undef, undef, 0.1; # wait for SIGPIPE to hit
> # "SIGPIPE\n" printed, why?
> ----------8<---------
> Thanks for any answer you can provide.
>
> Perl 5.32.0 on FreeBSD 11.x, but happens on 5.28.1 on Debian 10, too

Yeah, this is a bug. I think it has been reported before. %SIG magic
is a mess in general.

I think I know how to fix it though. The problem is that restoring
%SIG affects the Perl-level handlers (the SV in the hash) but not the
C-level signal disposition (sigaction).

Leon
0
fawaka
1/12/2021 10:45:47 PM
hv@crypt.org wrote:
> Eric Wong <p5p@yhbt.net> wrote:
> :I'm getting a hash(ref) of SIG overrides either as
> :a return value from another sub.  My workaround is something
> :like this:
> :
> :	my %sig = $self->some_callback;
> :	local $SIG{$_} = $sig->{$_} for keys %sig;
> :	...
> 
> I wouldn't expect that to work, but you can use a hash slice instead:

Right (not to mention the extra '->' :x)

>   local @SIG{keys %sig} = values %sig;
> 
> I do this sort of thing a lot when I want to localize a variable subset
> of elements, using a hash slice or array slice as relevant.

Cool, thanks, I will use that.  I did not realize keys and
values ordering would be consistent there.
0
p5p
1/12/2021 11:08:20 PM
On 1/12/21 6:08 PM, Eric Wong wrote:
> local @SIG{keys %sig} = values %sig;
>> I do this sort of thing a lot when I want to localize a variable subset
>> of elements, using a hash slice or array slice as relevant.
> Cool, thanks, I will use that.  I did not realize keys and
> values ordering would be consistent there.

that is documented and used all the time by me and many others. they use 
the same internal iterator in the hash so the ordering is always the same.

uri


0
uri
1/12/2021 11:11:52 PM
Reply: