What am I not grokking about $SIG{__WARN__}?

I'm using a stock, unthreaded perl-5.32.0 installed via perlbrew.

#####
$ perl -v | head -2 | tail -1
This is perl 5, version 32, subversion 0 (v5.32.0) built for x86_64-linux
#####

Consider this first file:

#####
$ cat qq1.pl
#!/usr/bin/env perl
use Test::More ( tests => 1 );
is ("\x4i", chr (4) . 'i', '\x4i');
#####

Note that I am *not* running with warnings.  Running this, I get:

#####
$ perl qq1.pl
1..1
ok 1 - \x4i
#####

Now, I activate warnings by adding '-w' to the shebang line.

#####
$ cat qq2.pl
#!/usr/bin/env perl -w
use Test::More ( tests => 1 );
is ("\x4i", chr (4) . 'i', '\x4i');
#####

Running this, I get:

#####
$ perl qq2.pl
1..1
Non-hex character 'i' terminates \x early.  Resolved as "\x04i" at 
qq2.pl line 3.
ok 1 - \x4i
#####

(This warning is expected, given that this program is adapted from 
t/opbasic/qq.t in the core distro, and that file has a comment 
indicating that the test in question will warn.)

Now suppose that I want to capture that warning -- perhaps to compose a 
regex that I would test with Test::More::like() -- and that I am limited 
to code that comes with the core distribution.

Based on past experience and 'perldoc perlvar', I would expect to be 
able to capture the warning with $SIG{__WARN__} and assign it to a 
variable for use in testing.  I would expect the following to DWIM:

#####
$ cat qq3.pl
#!/usr/bin/env perl -w
use Test::More ( tests => 1 );
{
     my $thiswarn = '';
     local $SIG{__WARN__} = sub { $thiswarn = $_[0]; };
     is ("\x4i", chr (4) . 'i', '\x4i');
     print "XXX: thiswarn: $thiswarn\n";
}
#####

But when I run this, the warning is not captured.  Rather, it is emitted 
as in the previous example.

#####
$ perl qq3.pl
1..1
Non-hex character 'i' terminates \x early.  Resolved as "\x04i" at 
qq3.pl line 6.
ok 1 - \x4i
XXX: thiswarn:
#####

What am I not grokking about this?  Why is $SIG{__WARN__} not capturing 
the warning?

Thank you very much.
Jim Keenan
0
jkeenan
6/30/2020 1:17:01 PM
perl.perl5.porters 48119 articles. 1 followers. Follow

5 Replies
3 Views

Similar Articles

[PageSpeed] 11

Looks like this is a compile-time warning, from S_fold_<whatever>, so
the desired effect can be achieved with

#!/usr/bin/env perl -w
use Test::More ( tests =3D> 1 );

BEGIN {
    $SIG{__WARN__} =3D sub { $thiswarn =3D $_[0]; };
}

{
     my $thiswarn =3D '';
     is ("\x4i", chr (4) . 'i', '\x4i');
     print "XXX: thiswarn: $thiswarn\n";
}

Best regards,
Sergey Aleynikov

=D0=B2=D1=82, 30 =D0=B8=D1=8E=D0=BD. 2020 =D0=B3. =D0=B2 16:17, James E Kee=
nan <jkeenan@pobox.com>:
>
> I'm using a stock, unthreaded perl-5.32.0 installed via perlbrew.
>
> #####
> $ perl -v | head -2 | tail -1
> This is perl 5, version 32, subversion 0 (v5.32.0) built for x86_64-linux
> #####
>
> Consider this first file:
>
> #####
> $ cat qq1.pl
> #!/usr/bin/env perl
> use Test::More ( tests =3D> 1 );
> is ("\x4i", chr (4) . 'i', '\x4i');
> #####
>
> Note that I am *not* running with warnings.  Running this, I get:
>
> #####
> $ perl qq1.pl
> 1..1
> ok 1 - \x4i
> #####
>
> Now, I activate warnings by adding '-w' to the shebang line.
>
> #####
> $ cat qq2.pl
> #!/usr/bin/env perl -w
> use Test::More ( tests =3D> 1 );
> is ("\x4i", chr (4) . 'i', '\x4i');
> #####
>
> Running this, I get:
>
> #####
> $ perl qq2.pl
> 1..1
> Non-hex character 'i' terminates \x early.  Resolved as "\x04i" at
> qq2.pl line 3.
> ok 1 - \x4i
> #####
>
> (This warning is expected, given that this program is adapted from
> t/opbasic/qq.t in the core distro, and that file has a comment
> indicating that the test in question will warn.)
>
> Now suppose that I want to capture that warning -- perhaps to compose a
> regex that I would test with Test::More::like() -- and that I am limited
> to code that comes with the core distribution.
>
> Based on past experience and 'perldoc perlvar', I would expect to be
> able to capture the warning with $SIG{__WARN__} and assign it to a
> variable for use in testing.  I would expect the following to DWIM:
>
> #####
> $ cat qq3.pl
> #!/usr/bin/env perl -w
> use Test::More ( tests =3D> 1 );
> {
>      my $thiswarn =3D '';
>      local $SIG{__WARN__} =3D sub { $thiswarn =3D $_[0]; };
>      is ("\x4i", chr (4) . 'i', '\x4i');
>      print "XXX: thiswarn: $thiswarn\n";
> }
> #####
>
> But when I run this, the warning is not captured.  Rather, it is emitted
> as in the previous example.
>
> #####
> $ perl qq3.pl
> 1..1
> Non-hex character 'i' terminates \x early.  Resolved as "\x04i" at
> qq3.pl line 6.
> ok 1 - \x4i
> XXX: thiswarn:
> #####
>
> What am I not grokking about this?  Why is $SIG{__WARN__} not capturing
> the warning?
>
> Thank you very much.
> Jim Keenan
0
sergey
6/30/2020 1:24:57 PM
On 6/30/20 9:24 AM, Sergey Aleynikov wrote:
> Looks like this is a compile-time warning, from S_fold_<whatever>, so
> the desired effect can be achieved with
>=20
> #!/usr/bin/env perl -w
> use Test::More ( tests =3D> 1 );
>=20
> BEGIN {
>      $SIG{__WARN__} =3D sub { $thiswarn =3D $_[0]; };
> }
>=20
> {
>       my $thiswarn =3D '';
>       is ("\x4i", chr (4) . 'i', '\x4i');
>       print "XXX: thiswarn: $thiswarn\n";
> }
>=20
> Best regards,
> Sergey Aleynikov
>=20
> =D0=B2=D1=82, 30 =D0=B8=D1=8E=D0=BD. 2020 =D0=B3. =D0=B2 16:17, James E=
 Keenan <jkeenan@pobox.com>:
>>
>> I'm using a stock, unthreaded perl-5.32.0 installed via perlbrew.
>>
>> #####
>> $ perl -v | head -2 | tail -1
>> This is perl 5, version 32, subversion 0 (v5.32.0) built for x86_64-li=
nux
>> #####
>>
>> Consider this first file:
>>
>> #####
>> $ cat qq1.pl
>> #!/usr/bin/env perl
>> use Test::More ( tests =3D> 1 );
>> is ("\x4i", chr (4) . 'i', '\x4i');
>> #####
>>
>> Note that I am *not* running with warnings.  Running this, I get:
>>
>> #####
>> $ perl qq1.pl
>> 1..1
>> ok 1 - \x4i
>> #####
>>
>> Now, I activate warnings by adding '-w' to the shebang line.
>>
>> #####
>> $ cat qq2.pl
>> #!/usr/bin/env perl -w
>> use Test::More ( tests =3D> 1 );
>> is ("\x4i", chr (4) . 'i', '\x4i');
>> #####
>>
>> Running this, I get:
>>
>> #####
>> $ perl qq2.pl
>> 1..1
>> Non-hex character 'i' terminates \x early.  Resolved as "\x04i" at
>> qq2.pl line 3.
>> ok 1 - \x4i
>> #####
>>
>> (This warning is expected, given that this program is adapted from
>> t/opbasic/qq.t in the core distro, and that file has a comment
>> indicating that the test in question will warn.)
>>
>> Now suppose that I want to capture that warning -- perhaps to compose =
a
>> regex that I would test with Test::More::like() -- and that I am limit=
ed
>> to code that comes with the core distribution.
>>
>> Based on past experience and 'perldoc perlvar', I would expect to be
>> able to capture the warning with $SIG{__WARN__} and assign it to a
>> variable for use in testing.  I would expect the following to DWIM:
>>
>> #####
>> $ cat qq3.pl
>> #!/usr/bin/env perl -w
>> use Test::More ( tests =3D> 1 );
>> {
>>       my $thiswarn =3D '';
>>       local $SIG{__WARN__} =3D sub { $thiswarn =3D $_[0]; };
>>       is ("\x4i", chr (4) . 'i', '\x4i');
>>       print "XXX: thiswarn: $thiswarn\n";
>> }
>> #####
>>
>> But when I run this, the warning is not captured.  Rather, it is emitt=
ed
>> as in the previous example.
>>
>> #####
>> $ perl qq3.pl
>> 1..1
>> Non-hex character 'i' terminates \x early.  Resolved as "\x04i" at
>> qq3.pl line 6.
>> ok 1 - \x4i
>> XXX: thiswarn:
>> #####
>>
>> What am I not grokking about this?  Why is $SIG{__WARN__} not capturin=
g
>> the warning?
>>
>> Thank you very much.
>> Jim Keenan

Sergey, thanks for your response.  However, that doesn't appear to work=20
for me.  Consider:

#####
$ cat qq4.pl
#!/usr/bin/env perl -w
my $thiswarn =3D '';
use Test::More ( tests =3D> 1 );
BEGIN { local $SIG{__WARN__} =3D sub { $thiswarn =3D $_[0]; }; }
{
     is ("\x4i", chr (4) . 'i', '\x4i');
     print "XXX: thiswarn: $thiswarn\n";
}
#####

It outputs:

#####
$ perl qq4.pl
1..1
Non-hex character 'i' terminates \x early.  Resolved as "\x04i" at=20
qq4.pl line 6.
ok 1 - \x4i
XXX: thiswarn:
#####

The warning continues to be directly emitted, not captured.

Thank you very much.
Jim Keenan
0
jkeenan
6/30/2020 1:38:16 PM
On Tue, 30 Jun 2020 09:38:16 -0400
James E Keenan <jkeenan@pobox.com> wrote:

> BEGIN { local $SIG{__WARN__} = sub { $thiswarn = $_[0]; }; }

The local scope ends as soon as the BEGIN block ends. Thus that didn't
ever catch anything.

It's really nontrivial to `local`y capture warnings at compiletime. You
can't use `local` inside a BEGIN block, because of this.

-- 
Paul "LeoNerd" Evans

leonerd@leonerd.org.uk      |  https://metacpan.org/author/PEVANS
http://www.leonerd.org.uk/  |  https://www.tindie.com/stores/leonerd/
0
leonerd
6/30/2020 1:44:12 PM
=D0=B2=D1=82, 30 =D0=B8=D1=8E=D0=BD. 2020 =D0=B3. =D0=B2 16:38, James E Kee=
nan <jkeenan@pobox.com>:
> BEGIN { local $SIG{__WARN__} =3D sub { $thiswarn =3D $_[0]; }; }

LeoNerd answered about the 'local' behaviour here, but if you really
need it - you can put a second BEGIN block at the end of the file,
clearing/restoring __WARN__ handler.

Best regards,
Sergey Aleynikov
0
sergey
6/30/2020 1:54:42 PM
--00000000000046891b05a95d6b82
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

Alternatively, instead of hooking the signal earlier (by adding a BEGIN
block), you can delay the delay the warning to runtime (by using C<< eval
EXPR >>).


On Tue., Jun. 30, 2020, 9:54 a.m. Sergey Aleynikov, <
sergey.aleynikov@gmail.com> wrote:

> =D0=B2=D1=82, 30 =D0=B8=D1=8E=D0=BD. 2020 =D0=B3. =D0=B2 16:38, James E K=
eenan <jkeenan@pobox.com>:
> > BEGIN { local $SIG{__WARN__} =3D sub { $thiswarn =3D $_[0]; }; }
>
> LeoNerd answered about the 'local' behaviour here, but if you really
> need it - you can put a second BEGIN block at the end of the file,
> clearing/restoring __WARN__ handler.
>
> Best regards,
> Sergey Aleynikov
>

--00000000000046891b05a95d6b82
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"auto">Alternatively, instead of hooking the signal earlier (by =
adding a BEGIN block), you can delay the delay the warning to runtime (by u=
sing C&lt;&lt; eval EXPR &gt;&gt;).<div dir=3D"auto"><br></div></div><br><d=
iv class=3D"gmail_quote"><div dir=3D"ltr" class=3D"gmail_attr">On Tue., Jun=
.. 30, 2020, 9:54 a.m. Sergey Aleynikov, &lt;<a href=3D"mailto:sergey.aleyni=
kov@gmail.com">sergey.aleynikov@gmail.com</a>&gt; wrote:<br></div><blockquo=
te class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #ccc so=
lid;padding-left:1ex">=D0=B2=D1=82, 30 =D0=B8=D1=8E=D0=BD. 2020 =D0=B3. =D0=
=B2 16:38, James E Keenan &lt;<a href=3D"mailto:jkeenan@pobox.com" target=
=3D"_blank" rel=3D"noreferrer">jkeenan@pobox.com</a>&gt;:<br>
&gt; BEGIN { local $SIG{__WARN__} =3D sub { $thiswarn =3D $_[0]; }; }<br>
<br>
LeoNerd answered about the &#39;local&#39; behaviour here, but if you reall=
y<br>
need it - you can put a second BEGIN block at the end of the file,<br>
clearing/restoring __WARN__ handler.<br>
<br>
Best regards,<br>
Sergey Aleynikov<br>
</blockquote></div>

--00000000000046891b05a95d6b82--
0
ikegami
7/1/2020 8:52:48 AM
Reply: