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

Carp.pm useless warning "Use of uninitialized value $error[1] in join or string" #16815

Open
p5pRT opened this issue Jan 19, 2019 · 19 comments
Open

Comments

@p5pRT
Copy link

p5pRT commented Jan 19, 2019

Migrated from rt.perl.org#133776 (status was 'open')

Searchable as RT133776$

@p5pRT
Copy link
Author

p5pRT commented Jan 19, 2019

From wagnerc@plebeian.com

Message RFC822:
From: wagnerc@plebeian.com
Reply-To: wagnerc@plebeian.com
Subject: Carp.pm useless warning "Use of uninitialized value $error[1] in
join or string"
To: perlbug@perl.org
Message-ID: 5.22.4_13508_1547759937@applejack
CC: wagnerc@plebeian.com
X-RT-Original-Encoding: ascii
Content-Type: text/plain; charset="ascii"
Content-Length: 5281

This is a bug report for perl from wagnerc@plebeian.com,
generated with the help of perlbug 1.40 running under perl 5.22.4.


The Carp 1.50 main functions will print a useless and confusing warning about the use of an uninitialized value if one of the arguments to the given function is undef. This breaks the encapsulation principle of Carp to "report the caller's errors, not the ones it might happen to tickle while doing so."

Examples:
$ perl -MCarp -e 'Carp::carp "foo", undef, "bar";'
Use of uninitialized value $error[1] in join or string at /usr/lib/perl5/site_perl/5.22/Carp.pm line 588.
foobar at -e line 1.

$ perl -MCarp -e 'sub{Carp::confess "foo", undef, "bar"}->();'
Use of uninitialized value $error[1] in join or string at /usr/lib/perl5/site_perl/5.22/Carp.pm line 588.
foobar at -e line 1.
main::ANON() called at -e line 1

$ perl -MCarp -e 'package X; sub{Carp::croak "foo", undef, "bar"}->();'
Use of uninitialized value $error[1] in join or string at /usr/lib/perl5/site_perl/5.22/Carp.pm line 588.
foobar at -e line 1.
X::ANON() called at -e line 1

$ perl -MCarp -e 'package X; sub{Carp::cluck "foo", undef, "bar"}->();'
Use of uninitialized value $error[1] in join or string at /usr/lib/perl5/site_perl/5.22/Carp.pm line 588.
foobar at -e line 1.
X::ANON() called at -e line 1

Fix:
This can be fixed by adding a defined check to the two spots that read the Carp arguments/messages.

sub ret_backtrace {
my ( $i, @error ) = @_;
my $mess;

  • my $err = join '', grep defined, @error;
    $i++;

sub ret_summary {
my ( $i, @error ) = @_;

  • my $err = join '', grep defined, @error;
    $i++;

It might still be desirable to report about the undef argument but it should report from the caller's location about the caller's use of an undef to a function that "shouldn't" have undef arguments.

Thanks.

[Please do not change anything below this line]


Flags:
category=library
severity=low
module=Carp

Site configuration information for perl 5.22.4:

Configured by ASSI at Sat Jul 15 20:06:49 CEST 2017.

Summary of my perl5 (revision 5 version 22 subversion 4) configuration:

Platform:
osname=cygwin, osvers=2.8.1(0.31253), archname=cygwin-thread-multi
uname='cygwin_nt-6.3 cygwin 2.8.1(0.31253) 2017-07-03 14:11 x86_64 cygwin '
config_args='-des -Dprefix=/usr -Dmksymlinks -Darchname=x86_64-cygwin-threads -Dlibperl=cygperl5_22.dll -Dcc=gcc -Dld=g++ -Accflags=-ggdb -O2 -pipe -Wimplicit-function-declaration -fdebug-prefix-map=/mnt/share/maint/perl.x86_64/build=/usr/src/debug/perl-5.22.4-1 -fdebug-prefix-map=/mnt/share/maint/perl.x86_64/src/perl-5.22.4=/usr/src/debug/perl-5.22.4-1 -fwrapv'
hint=recommended, useposix=true, d_sigaction=define
useithreads=define, usemultiplicity=define
use64bitint=define, use64bitall=define, uselongdouble=undef
usemymalloc=n, bincompat5005=undef
Compiler:
cc='gcc', ccflags ='-DPERL_USE_SAFE_PUTENV -D_GNU_SOURCE -U__STRICT_ANSI__ -ggdb -O2 -pipe -Wimplicit-function-declaration -fdebug-prefix-map=/mnt/share/maint/perl.x86_64/build=/usr/src/debug/perl-5.22.4-1 -fdebug-prefix-map=/mnt/share/maint/perl.x86_64/src/perl-5.22.4=/usr/src/debug/perl-5.22.4-1 -fwrapv -fno-strict-aliasing -fstack-protector-strong -D_FORTIFY_SOURCE=2',
optimize='-O3',
cppflags='-DPERL_USE_SAFE_PUTENV -D_GNU_SOURCE -U__STRICT_ANSI__ -ggdb -O2 -pipe -Wimplicit-function-declaration -fdebug-prefix-map=/mnt/share/maint/perl.x86_64/build=/usr/src/debug/perl-5.22.4-1 -fdebug-prefix-map=/mnt/share/maint/perl.x86_64/src/perl-5.22.4=/usr/src/debug/perl-5.22.4-1 -fwrapv -fno-strict-aliasing -fstack-protector-strong'
ccversion='', gccversion='5.4.0', gccosandvers=''
intsize=4, longsize=8, ptrsize=8, doublesize=8, byteorder=12345678, doublekind=3
d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=16, longdblkind=3
ivtype='long', ivsize=8, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8
alignbytes=8, prototype=define
Linker and Libraries:
ld='g++', ldflags =' -Wl,--enable-auto-import -Wl,--export-all-symbols -Wl,--enable-auto-image-base -fstack-protector-strong'
libpth=/usr/lib
libs=-lpthread -lgdbm -ldb -ldl -lcrypt -lgdbm_compat
perllibs=-lpthread -ldl -lcrypt
libc=/usr/lib/libcygwin.a, so=dll, useshrplib=true, libperl=cygperl5_22.dll
gnulibc_version=''
Dynamic Linking:
dlsrc=dl_dlopen.xs, dlext=dll, d_dlsymun=undef, ccdlflags=' '
cccdlflags=' ', lddlflags=' --shared -Wl,--enable-auto-import -Wl,--export-all-symbols -Wl,--enable-auto-image-base -fstack-protector-strong'


@inc for perl 5.22.4:
/usr/lib/perl5/site_perl/5.22/x86_64-cygwin-threads
/usr/lib/perl5/site_perl/5.22
/usr/lib/perl5/vendor_perl/5.22/x86_64-cygwin-threads
/usr/lib/perl5/vendor_perl/5.22
/usr/lib/perl5/5.22/x86_64-cygwin-threads
/usr/lib/perl5/5.22


Environment for perl 5.22.4:
LANG=en_US.UTF-8
LANGUAGE (unset)
LD_LIBRARY_PATH (unset)
LOGDIR (unset)
PERL_BADLANG (unset)
SHELL=/bin/bash

@p5pRT
Copy link
Author

p5pRT commented Jan 19, 2019

From wagnerc@plebeian.com

Created by wagnerc@plebeian.com

This is a bug report for perl from wagnerc@​plebeian.com,
generated with the help of perlbug 1.40 running under perl 5.22.4.

-----------------------------------------------------------------
The Carp 1.50 main functions will print a useless and confusing warning about the use of an uninitialized value if one of the arguments to the given function is undef. This breaks the encapsulation principle of Carp to "report the caller's errors, not the ones it might happen to tickle while doing so."

Examples​:
$ perl -MCarp -e 'Carp​::carp "foo", undef, "bar";'
Use of uninitialized value $error[1] in join or string at /usr/lib/perl5/site_perl/5.22/Carp.pm line 588.
foobar at -e line 1.

$ perl -MCarp -e 'sub{Carp​::confess "foo", undef, "bar"}->();'
Use of uninitialized value $error[1] in join or string at /usr/lib/perl5/site_perl/5.22/Carp.pm line 588.
foobar at -e line 1.
  main​::__ANON__() called at -e line 1

$ perl -MCarp -e 'package X; sub{Carp​::croak "foo", undef, "bar"}->();'
Use of uninitialized value $error[1] in join or string at /usr/lib/perl5/site_perl/5.22/Carp.pm line 588.
foobar at -e line 1.
  X​::__ANON__() called at -e line 1

$ perl -MCarp -e 'package X; sub{Carp​::cluck "foo", undef, "bar"}->();'
Use of uninitialized value $error[1] in join or string at /usr/lib/perl5/site_perl/5.22/Carp.pm line 588.
foobar at -e line 1.
  X​::__ANON__() called at -e line 1

Fix​:
This can be fixed by adding a defined check to the two spots that read the Carp arguments/messages.

sub ret_backtrace {
  my ( $i, @​error ) = @​_;
  my $mess;
- my $err = join '', @​error;
+ my $err = join '', grep defined, @​error;
  $i++;

sub ret_summary {
  my ( $i, @​error ) = @​_;
- my $err = join '', @​error;
+ my $err = join '', grep defined, @​error;
  $i++;

It might still be desirable to report about the undef argument but it should report from the caller's location about the caller's use of an undef to a function that "shouldn't" have undef arguments.

Thanks.

Perl Info

Flags:
    category=library
    severity=low
    module=Carp

Site configuration information for perl 5.22.4:

Configured by ASSI at Sat Jul 15 20:06:49 CEST 2017.

Summary of my perl5 (revision 5 version 22 subversion 4) configuration:
   
  Platform:
    osname=cygwin, osvers=2.8.1(0.31253), archname=cygwin-thread-multi
    uname='cygwin_nt-6.3 cygwin 2.8.1(0.31253) 2017-07-03 14:11 x86_64 cygwin '
    config_args='-des -Dprefix=/usr -Dmksymlinks -Darchname=x86_64-cygwin-threads -Dlibperl=cygperl5_22.dll -Dcc=gcc -Dld=g++ -Accflags=-ggdb -O2 -pipe -Wimplicit-function-declaration -fdebug-prefix-map=/mnt/share/maint/perl.x86_64/build=/usr/src/debug/perl-5.22.4-1 -fdebug-prefix-map=/mnt/share/maint/perl.x86_64/src/perl-5.22.4=/usr/src/debug/perl-5.22.4-1 -fwrapv'
    hint=recommended, useposix=true, d_sigaction=define
    useithreads=define, usemultiplicity=define
    use64bitint=define, use64bitall=define, uselongdouble=undef
    usemymalloc=n, bincompat5005=undef
  Compiler:
    cc='gcc', ccflags ='-DPERL_USE_SAFE_PUTENV -D_GNU_SOURCE -U__STRICT_ANSI__ -ggdb -O2 -pipe -Wimplicit-function-declaration -fdebug-prefix-map=/mnt/share/maint/perl.x86_64/build=/usr/src/debug/perl-5.22.4-1 -fdebug-prefix-map=/mnt/share/maint/perl.x86_64/src/perl-5.22.4=/usr/src/debug/perl-5.22.4-1 -fwrapv -fno-strict-aliasing -fstack-protector-strong -D_FORTIFY_SOURCE=2',
    optimize='-O3',
    cppflags='-DPERL_USE_SAFE_PUTENV -D_GNU_SOURCE -U__STRICT_ANSI__ -ggdb -O2 -pipe -Wimplicit-function-declaration -fdebug-prefix-map=/mnt/share/maint/perl.x86_64/build=/usr/src/debug/perl-5.22.4-1 -fdebug-prefix-map=/mnt/share/maint/perl.x86_64/src/perl-5.22.4=/usr/src/debug/perl-5.22.4-1 -fwrapv -fno-strict-aliasing -fstack-protector-strong'
    ccversion='', gccversion='5.4.0', gccosandvers=''
    intsize=4, longsize=8, ptrsize=8, doublesize=8, byteorder=12345678, doublekind=3
    d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=16, longdblkind=3
    ivtype='long', ivsize=8, nvtype='double', nvsize=8, Off_t='off_t', lseeksize=8
    alignbytes=8, prototype=define
  Linker and Libraries:
    ld='g++', ldflags =' -Wl,--enable-auto-import -Wl,--export-all-symbols -Wl,--enable-auto-image-base -fstack-protector-strong'
    libpth=/usr/lib
    libs=-lpthread -lgdbm -ldb -ldl -lcrypt -lgdbm_compat
    perllibs=-lpthread -ldl -lcrypt
    libc=/usr/lib/libcygwin.a, so=dll, useshrplib=true, libperl=cygperl5_22.dll
    gnulibc_version=''
  Dynamic Linking:
    dlsrc=dl_dlopen.xs, dlext=dll, d_dlsymun=undef, ccdlflags=' '
    cccdlflags=' ', lddlflags=' --shared  -Wl,--enable-auto-import -Wl,--export-all-symbols -Wl,--enable-auto-image-base -fstack-protector-strong'



@INC for perl 5.22.4:
    /usr/lib/perl5/site_perl/5.22/x86_64-cygwin-threads
    /usr/lib/perl5/site_perl/5.22
    /usr/lib/perl5/vendor_perl/5.22/x86_64-cygwin-threads
    /usr/lib/perl5/vendor_perl/5.22
    /usr/lib/perl5/5.22/x86_64-cygwin-threads
    /usr/lib/perl5/5.22


Environment for perl 5.22.4:
    LANG=en_US.UTF-8
    LANGUAGE (unset)
    LD_LIBRARY_PATH (unset)
    LOGDIR (unset)
    PERL_BADLANG (unset)
    SHELL=/bin/bash

@p5pRT
Copy link
Author

p5pRT commented Jan 19, 2019

From @jkeenan

On 1/18/19 10​:31 PM, Chris Wagner (via RT) wrote​:

This is a bug report for perl from wagnerc@​plebeian.com,
generated with the help of perlbug 1.40 running under perl 5.22.4.

The Carp 1.50 main functions will print a useless and confusing warning about the use of an uninitialized value if one of the arguments to the given function is undef. This breaks the encapsulation principle of Carp to "report the caller's errors, not the ones it might happen to tickle while doing so."

Are you quoting "report the caller's errors ..." from some
documentation, or paraphrasing?

I ask because I don't find that phrasing in Carp's documentation, even
though I tend to agree with it.

Examples​:
$ perl -MCarp -e 'Carp​::carp "foo", undef, "bar";'
Use of uninitialized value $error[1] in join or string at /usr/lib/perl5/site_perl/5.22/Carp.pm line 588.
foobar at -e line 1.

$ perl -MCarp -e 'sub{Carp​::confess "foo", undef, "bar"}->();'
Use of uninitialized value $error[1] in join or string at /usr/lib/perl5/site_perl/5.22/Carp.pm line 588.
foobar at -e line 1.
main​::__ANON__() called at -e line 1

$ perl -MCarp -e 'package X; sub{Carp​::croak "foo", undef, "bar"}->();'
Use of uninitialized value $error[1] in join or string at /usr/lib/perl5/site_perl/5.22/Carp.pm line 588.
foobar at -e line 1.
X​::__ANON__() called at -e line 1

$ perl -MCarp -e 'package X; sub{Carp​::cluck "foo", undef, "bar"}->();'
Use of uninitialized value $error[1] in join or string at /usr/lib/perl5/site_perl/5.22/Carp.pm line 588.
foobar at -e line 1.
X​::__ANON__() called at -e line 1

Fix​:
This can be fixed by adding a defined check to the two spots that read the Carp arguments/messages.

sub ret_backtrace {
my ( $i, @​error ) = @​_;
my $mess;
- my $err = join '', @​error;
+ my $err = join '', grep defined, @​error;
$i++;

sub ret_summary {
my ( $i, @​error ) = @​_;
- my $err = join '', @​error;
+ my $err = join '', grep defined, @​error;
$i++;

Would we be better off simply suppressing the uninitialized value
warning within these two internal subroutines?

It might still be desirable to report about the undef argument but it should report from the caller's location about the caller's use of an undef to a function that "shouldn't" have undef arguments.

Thank you very much.
Jim Keenan

@p5pRT
Copy link
Author

p5pRT commented Jan 19, 2019

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

@p5pRT
Copy link
Author

p5pRT commented Jan 19, 2019

From @jkeenan

On Sat, 19 Jan 2019 15​:34​:22 GMT, jkeenan@​pobox.com wrote​:

On 1/18/19 10​:31 PM, Chris Wagner (via RT) wrote​:

This is a bug report for perl from wagnerc@​plebeian.com,
generated with the help of perlbug 1.40 running under perl 5.22.4.

The Carp 1.50 main functions will print a useless and confusing
warning about the use of an uninitialized value if one of the
arguments to the given function is undef. This breaks the
encapsulation principle of Carp to "report the caller's errors, not
the ones it might happen to tickle while doing so."

Are you quoting "report the caller's errors ..." from some
documentation, or paraphrasing?

I ask because I don't find that phrasing in Carp's documentation, even
though I tend to agree with it.

Examples​:
$ perl -MCarp -e 'Carp​::carp "foo", undef, "bar";'
Use of uninitialized value $error[1] in join or string at
/usr/lib/perl5/site_perl/5.22/Carp.pm line 588.
foobar at -e line 1.

$ perl -MCarp -e 'sub{Carp​::confess "foo", undef, "bar"}->();'
Use of uninitialized value $error[1] in join or string at
/usr/lib/perl5/site_perl/5.22/Carp.pm line 588.
foobar at -e line 1.
main​::__ANON__() called at -e line 1

$ perl -MCarp -e 'package X; sub{Carp​::croak "foo", undef, "bar"}-

();'
Use of uninitialized value $error[1] in join or string at
/usr/lib/perl5/site_perl/5.22/Carp.pm line 588.
foobar at -e line 1.
X​::__ANON__() called at -e line 1

$ perl -MCarp -e 'package X; sub{Carp​::cluck "foo", undef, "bar"}-

();'
Use of uninitialized value $error[1] in join or string at
/usr/lib/perl5/site_perl/5.22/Carp.pm line 588.
foobar at -e line 1.
X​::__ANON__() called at -e line 1

Fix​:
This can be fixed by adding a defined check to the two spots that
read the Carp arguments/messages.

sub ret_backtrace {
my ( $i, @​error ) = @​_;
my $mess;
- my $err = join '', @​error;
+ my $err = join '', grep defined, @​error;
$i++;

sub ret_summary {
my ( $i, @​error ) = @​_;
- my $err = join '', @​error;
+ my $err = join '', grep defined, @​error;
$i++;

Would we be better off simply suppressing the uninitialized value
warning within these two internal subroutines?

OTOH, filtering out the arguments which are undefined values would be consistent with the 'warn' and 'die' built-ins which 'carp' and 'croak' emulate.

#####
$ perl -e 'warn("alpha", undef, "beta") unless 1 == 0;'
alphabeta at -e line 1.

$ perl -e 'die("alpha", undef, "beta") unless 1 == 0;'
alphabeta at -e line 1.
#####

It might still be desirable to report about the undef argument but it
should report from the caller's location about the caller's use of an
undef to a function that "shouldn't" have undef arguments.

Thank you very much.
Jim Keenan

--
James E Keenan (jkeenan@​cpan.org)

@p5pRT
Copy link
Author

p5pRT commented Jan 20, 2019

From wagnerc@plebeian.com

On Sat, 19 Jan 2019 07​:34​:22 -0800, jkeenan@​pobox.com wrote​:

Are you quoting "report the caller's errors ..." from some
documentation, or paraphrasing?

I ask because I don't find that phrasing in Carp's documentation, even
though I tend to agree with it.

That comes from caller_info() in Carp.pm

  # poke around inside the stack. Inside of Carp.pm it makes little
  # sense reporting these bugs, as Carp's job is to report the callers
  # errors, not the ones it might happen to tickle while doing so.
  # See​: https://rt.perl.org/Public/Bug/Display.html?id=131046
  # and​: https://rt.perl.org/Public/Bug/Display.html?id=52610
  # for more details and discussion. - Yves

@p5pRT
Copy link
Author

p5pRT commented Jan 20, 2019

From wagnerc@plebeian.com

On Sat, 19 Jan 2019 08​:03​:37 -0800, jkeenan wrote​:

OTOH, filtering out the arguments which are undefined values would be
consistent with the 'warn' and 'die' built-ins which 'carp' and
'croak' emulate.

#####
$ perl -e 'warn("alpha", undef, "beta") unless 1 == 0;'
alphabeta at -e line 1.

$ perl -e 'die("alpha", undef, "beta") unless 1 == 0;'
alphabeta at -e line 1.
#####

Eh, warn() and die() are not that nice. :)
$ perl -w
warn("alpha", undef, "beta");
Use of uninitialized value in warn at - line 1.
alphabeta at - line 1.

$ perl -w
die("alpha", undef, "beta");
Use of uninitialized value in die at - line 1.
alphabeta at - line 1.

I say we just add the defined check because undef()'s just smash down to blank anyway.

We "could"​:
sub ret_backtrace {
  my ( $i, @​error ) = @​_;
  my $mess;
- my $err = join '', @​error;
+ if (warnings​::enabled("uninitialized") && scalar grep {!defined} @​error) {
+ carp "Use of unititialized....";
+ }
+ my $err = join '', grep defined, @​error;
  $i++;

Thanks.

@p5pRT
Copy link
Author

p5pRT commented Jan 21, 2019

From @tonycoz

On Sun, 20 Jan 2019 14​:48​:35 -0800, wagnerc@​plebeian.com wrote​:

On Sat, 19 Jan 2019 08​:03​:37 -0800, jkeenan wrote​:

OTOH, filtering out the arguments which are undefined values would be
consistent with the 'warn' and 'die' built-ins which 'carp' and
'croak' emulate.

#####
$ perl -e 'warn("alpha", undef, "beta") unless 1 == 0;'
alphabeta at -e line 1.

$ perl -e 'die("alpha", undef, "beta") unless 1 == 0;'
alphabeta at -e line 1.
#####

Eh, warn() and die() are not that nice. :)
$ perl -w
warn("alpha", undef, "beta");
Use of uninitialized value in warn at - line 1.
alphabeta at - line 1.

$ perl -w
die("alpha", undef, "beta");
Use of uninitialized value in die at - line 1.
alphabeta at - line 1.

I say we just add the defined check because undef()'s just smash down
to blank anyway.

We "could"​:
sub ret_backtrace {
my ( $i, @​error ) = @​_;
my $mess;
- my $err = join '', @​error;
+ if (warnings​::enabled("uninitialized") && scalar grep {!defined}
@​error) {
+ carp "Use of unititialized....";
+ }
+ my $err = join '', grep defined, @​error;
$i++;

This makes sense to me.

Tony

@p5pRT
Copy link
Author

p5pRT commented Jan 21, 2019

From @jkeenan

On Mon, 21 Jan 2019 00​:52​:46 GMT, tonyc wrote​:

On Sun, 20 Jan 2019 14​:48​:35 -0800, wagnerc@​plebeian.com wrote​:

On Sat, 19 Jan 2019 08​:03​:37 -0800, jkeenan wrote​:

OTOH, filtering out the arguments which are undefined values would be
consistent with the 'warn' and 'die' built-ins which 'carp' and
'croak' emulate.

#####
$ perl -e 'warn("alpha", undef, "beta") unless 1 == 0;'
alphabeta at -e line 1.

$ perl -e 'die("alpha", undef, "beta") unless 1 == 0;'
alphabeta at -e line 1.
#####

Eh, warn() and die() are not that nice. :)
$ perl -w
warn("alpha", undef, "beta");
Use of uninitialized value in warn at - line 1.
alphabeta at - line 1.

$ perl -w
die("alpha", undef, "beta");
Use of uninitialized value in die at - line 1.
alphabeta at - line 1.

I say we just add the defined check because undef()'s just smash down
to blank anyway.

We "could"​:
sub ret_backtrace {
my ( $i, @​error ) = @​_;
my $mess;
- my $err = join '', @​error;
+ if (warnings​::enabled("uninitialized") && scalar grep {!defined}
@​error) {
+ carp "Use of unititialized....";
+ }
+ my $err = join '', grep defined, @​error;
$i++;

This makes sense to me.

Tony

Please evaluate the patch attached, which is available for smoke-testing in the smoke-me/jkeenan/133776-carp-uninit-value-warning branch.

Thank you very much.

--
James E Keenan (jkeenan@​cpan.org)

@p5pRT
Copy link
Author

p5pRT commented Jan 21, 2019

From @jkeenan

0001-Suppress-uninitialized-value-warning-if-one-argument.patch
From 78baa69d418e2a5fc200846cd48a1618dec29913 Mon Sep 17 00:00:00 2001
From: James E Keenan <jkeenan@cpan.org>
Date: Sun, 20 Jan 2019 21:29:02 -0500
Subject: [PATCH] Suppress uninitialized value warning if one argument is
 'undef'.

As suggested by Chris Wagner.  For: RT #133776
---
 dist/Carp/lib/Carp.pm                        | 10 +++-
 dist/Carp/t/rt133776-no-warn-on-undef-args.t | 49 ++++++++++++++++++++
 2 files changed, 57 insertions(+), 2 deletions(-)
 create mode 100644 dist/Carp/t/rt133776-no-warn-on-undef-args.t

diff --git a/dist/Carp/lib/Carp.pm b/dist/Carp/lib/Carp.pm
index 109b7fec77..d53308ac3e 100644
--- a/dist/Carp/lib/Carp.pm
+++ b/dist/Carp/lib/Carp.pm
@@ -585,7 +585,10 @@ BEGIN {
 sub ret_backtrace {
     my ( $i, @error ) = @_;
     my $mess;
-    my $err = join '', @error;
+    if (warnings::enabled("uninitialized") && scalar grep {!defined} @error) {
+        carp "Use of uninitialized value in error message";
+    }
+    my $err = join '', grep defined, @error;
     $i++;
 
     my $tid_msg = '';
@@ -627,7 +630,10 @@ sub ret_backtrace {
 
 sub ret_summary {
     my ( $i, @error ) = @_;
-    my $err = join '', @error;
+    if (warnings::enabled("uninitialized") && scalar grep {!defined} @error) {
+        carp "Use of uninitialized value in error message";
+    }
+    my $err = join '', grep defined, @error;
     $i++;
 
     my $tid_msg = '';
diff --git a/dist/Carp/t/rt133776-no-warn-on-undef-args.t b/dist/Carp/t/rt133776-no-warn-on-undef-args.t
new file mode 100644
index 0000000000..6a3da81309
--- /dev/null
+++ b/dist/Carp/t/rt133776-no-warn-on-undef-args.t
@@ -0,0 +1,49 @@
+use strict;
+use warnings;
+use Carp;
+use Test::More tests =>  4;
+use Data::Dumper; $Data::Dumper::Indent=1;
+our $Level;
+
+sub __capture {
+    push @::__capture, join "", @_;
+}
+
+sub capture_warnings {
+    my $code = shift;
+
+    local @::__capture;
+    local $SIG {__WARN__} = \&__capture;
+    local $Level = 1;
+    &$code;
+    return @::__capture;
+}
+
+{
+    my @warnings = capture_warnings( sub { eval { Carp::carp("foo", undef, "bar"); }; 1; } );
+    my $str = join("\n" => @warnings);
+    unlike($str, qr/Use of uninitialized value \$error\[1\] in join or string/s,
+        "No uninitialized value warning for 'undef' arg to carp");
+}
+
+{
+    my @warnings = capture_warnings( sub { eval { Carp::croak("foo", undef, "bar"); }; 1; } );
+    my $str = join("\n" => @warnings);
+    unlike($str, qr/Use of uninitialized value \$error\[1\] in join or string/s,
+        "No uninitialized value warning for 'undef' arg to croak");
+}
+
+{
+    my @warnings = capture_warnings( sub { eval { Carp::cluck("foo", undef, "bar"); }; 1; } );
+    my $str = join("\n" => @warnings);
+    unlike($str, qr/Use of uninitialized value \$error\[1\] in join or string/s,
+        "No uninitialized value warning for 'undef' arg to cluck");
+}
+
+{
+    my @warnings = capture_warnings( sub { eval { Carp::confess("foo", undef, "bar"); }; 1; } );
+    my $str = join("\n" => @warnings);
+    unlike($str, qr/Use of uninitialized value \$error\[1\] in join or string/s,
+        "No uninitialized value warning for 'undef' arg to confess");
+}
+
-- 
2.17.1

@p5pRT
Copy link
Author

p5pRT commented Jan 21, 2019

From wagnerc@plebeian.com

Although, if we do rewarn about the undef if might be better to do it as a warn(shortmess(@​_)) in case someone replaced carp() in such a way as to prevent the main backtrace from completing.

e.g.
package Foobar;
*Carp​::carp = sub { die @​_ } if $just_die;
if (&blah) {
  @​list = ("foo", undef, "bar");
  croak "&blah is all sigoggalin", @​list;
}

In this case the user informative croak message would never print because the carp() about the undef was changed to a die. Sure, it's a stretch...

The question is of course how far to go with preempting edge cases.

Chris

@p5pRT
Copy link
Author

p5pRT commented Jan 21, 2019

From wagnerc@plebeian.com

I should have put the expression form of grep in the warnings check since that is faster than the block form.

scalar grep !defined, @​error

Chris

@p5pRT
Copy link
Author

p5pRT commented Jan 21, 2019

From @jkeenan

On Mon, 21 Jan 2019 04​:08​:12 GMT, wagnerc@​plebeian.com wrote​:

Although, if we do rewarn about the undef if might be better to do it
as a warn(shortmess(@​_)) in case someone replaced carp() in such a way
as to prevent the main backtrace from completing.

e.g.
package Foobar;
*Carp​::carp = sub { die @​_ } if $just_die;
if (&blah) {
@​list = ("foo", undef, "bar");
croak "&blah is all sigoggalin", @​list;
}

In this case the user informative croak message would never print
because the carp() about the undef was changed to a die. Sure, it's a
stretch...

The question is of course how far to go with preempting edge cases.

Chris

Chris, before we go down that rabbit hole, can you (and anyone else) please review the smoke-me/jkeenan/133776-carp-uninit-value-warning branch as of commit f7528e1?

The changes so far are causing warnings to be thrown during the running of dist/Carp/t/stash_deletion.t that I don't see in blead.

#####
$ cd t;./perl harness -v ../dist/Carp/t/stash_deletion.t; cd -

ok 1
ok 2
ok 3
ok 4
Use of uninitialized value $called in hash element at ../../lib/Carp.pm line 678.
ok 5
Use of uninitialized value $pkg in hash element at ../../lib/Carp.pm line 499.
Use of uninitialized value $pkg in anonymous hash ({}) at ../../lib/Carp.pm line 499.
Use of uninitialized value $class in concatenation (.) or string at ../../lib/Carp.pm line 737.
Use of uninitialized value $pkg in hash element at ../../lib/Carp.pm line 500.
Use of uninitialized value $parent in exists at ../../lib/Carp.pm line 730.
ok 6
...
#####

Thank you very much.
--
James E Keenan (jkeenan@​cpan.org)

@p5pRT
Copy link
Author

p5pRT commented Jan 21, 2019

From @tonycoz

On Mon, Jan 21, 2019 at 12​:43​:34PM -0800, James E Keenan via RT wrote​:

Chris, before we go down that rabbit hole, can you (and anyone else) please review the smoke-me/jkeenan/133776-carp-uninit-value-warning branch as of commit f7528e1?

You test that the warnings that started the ticket are no longer
produced, but you don't test that the warnings you added in the patch
are produced.

There might be some problems with warnings​::enabled() and carp()
reporting in context, but adding tests will detect that if they're a
problem.

Tony

@p5pRT
Copy link
Author

p5pRT commented Jan 22, 2019

From @jkeenan

On Mon, 21 Jan 2019 20​:43​:34 GMT, jkeenan wrote​:

On Mon, 21 Jan 2019 04​:08​:12 GMT, wagnerc@​plebeian.com wrote​:

Although, if we do rewarn about the undef if might be better to do it
as a warn(shortmess(@​_)) in case someone replaced carp() in such a
way
as to prevent the main backtrace from completing.

e.g.
package Foobar;
*Carp​::carp = sub { die @​_ } if $just_die;
if (&blah) {
@​list = ("foo", undef, "bar");
croak "&blah is all sigoggalin", @​list;
}

In this case the user informative croak message would never print
because the carp() about the undef was changed to a die. Sure, it's
a
stretch...

The question is of course how far to go with preempting edge cases.

Chris

Chris, before we go down that rabbit hole, can you (and anyone else)
please review the smoke-me/jkeenan/133776-carp-uninit-value-warning
branch as of commit f7528e1?

The changes so far are causing warnings to be thrown during the
running of dist/Carp/t/stash_deletion.t that I don't see in blead.

#####
$ cd t;./perl harness -v ../dist/Carp/t/stash_deletion.t; cd -

ok 1
ok 2
ok 3
ok 4
Use of uninitialized value $called in hash element at
../../lib/Carp.pm line 678.
ok 5
Use of uninitialized value $pkg in hash element at ../../lib/Carp.pm
line 499.
Use of uninitialized value $pkg in anonymous hash ({}) at
../../lib/Carp.pm line 499.
Use of uninitialized value $class in concatenation (.) or string at
../../lib/Carp.pm line 737.
Use of uninitialized value $pkg in hash element at ../../lib/Carp.pm
line 500.
Use of uninitialized value $parent in exists at ../../lib/Carp.pm line
730.
ok 6
...
#####

Thank you very much.

The warnings are all coming from this block in dist/Carp/t/stash_deletion.t​:

#####
{
  my $sub = eval <<'EVAL';
package Confess;
sub {
#line 1 foo
  Carp​::confess("blah");
}
EVAL
  ok(!$@​);
  eval { $sub->() };
  like($@​, qr/^blah at foo line 1/);
  {
  no strict 'refs';
  delete ${'​::'}{'Confess​::'};
  }
  eval { $sub->() };
  like($@​, qr/^blah at foo line 1/);
}
#####

--
James E Keenan (jkeenan@​cpan.org)

@p5pRT
Copy link
Author

p5pRT commented Jan 22, 2019

From @jkeenan

On Mon, 21 Jan 2019 22​:44​:41 GMT, tonyc wrote​:

On Mon, Jan 21, 2019 at 12​:43​:34PM -0800, James E Keenan via RT wrote​:

Chris, before we go down that rabbit hole, can you (and anyone else)
please review the smoke-me/jkeenan/133776-carp-uninit-value-warning
branch as of commit f7528e1?

You test that the warnings that started the ticket are no longer
produced, but you don't test that the warnings you added in the patch
are produced.

Acknowledged, but no one else had suggested any tests for the changes in code and it took me a long time to even write those tests. The problem with new warnings in dist/Carp/t/stash_deletion.t makes me wonder whether the effort we're going through is worth it.

There might be some problems with warnings​::enabled() and carp()
reporting in context, but adding tests will detect that if they're a
problem.

Tony

--
James E Keenan (jkeenan@​cpan.org)

@p5pRT
Copy link
Author

p5pRT commented Jan 23, 2019

From wagnerc@plebeian.com

So I've been analyzing these spurious warnings.

I've narrowed it down to this one line in stash_deletion.t.

40​: delete ${'​::'}{'Confess​::'};

Commenting it out eliminates the warnings. Also, removing the warnings​::enabled("uninitialized") call also eliminates the warnings. It's strange because none of the other package deletes trigger the warnings. I also tried a different package name besides Confess​::. No difference.

Bascially warnings​::enabled() causes a call to short_error_loc() in order to know where to grab the caller's warning vector. In the test file, that happens after the test has deleted the package and called confess(). So in the course of one exception sequence, there are competing calls to long_error_loc() by longmess_heavy and short_error_loc() by warnings​::enabled(). My best guess now is that caller() itself is confused by this and $called is left undefined in short_error_loc; There are no defined checks on $called like there is on $caller. It's quite possible that this use case has exposed a new bug in Carp itself.

Totally narrowing it down would probably take some debugger tracing or other instrumentation. But I'll see if I can come up with some code to deal with $called being undefined.

Thanks,
Chris

@p5pRT
Copy link
Author

p5pRT commented Jan 26, 2019

From wagnerc@plebeian.com

I created RT#133800 (Carp croak() fails on anon sub and package deletion) to cover the problems in short_error_loc(). I think that needs to be fixed before we can fix the uninitialized warnings.

Thanks.

@jkeenan
Copy link
Contributor

jkeenan commented Oct 29, 2023

From wagnerc@plebeian.com

I created RT#133800 (Carp croak() fails on anon sub and package deletion) to cover the problems in short_error_loc(). I think that needs to be fixed before we can fix the uninitialized warnings.

Thanks.

RT#133800 now appears as #16827

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants