Skip Menu |

This queue is for tickets about the Getopt-Long CPAN distribution.

Report information
The Basics
Id: 120562
Status: resolved
Priority: 0/
Queue: Getopt-Long

People
Owner: Nobody in particular
Requestors: sblondeel [...] yahoo.com
Cc:
AdminCc:

Bug Information
Severity: (no value)
Broken in: (no value)
Fixed in: (no value)



Subject: please circumvent a core Perl bug in Getopt::Long
Date: Thu, 9 Mar 2017 07:21:13 +0000 (UTC)
To: "bug-Getopt-Long [...] rt.cpan.org" <bug-Getopt-Long [...] rt.cpan.org>
From: Sébastien Blondeel <sblondeel [...] yahoo.com>
Getopt-Long-2.42 Perl v5.20.2 Linux 3.16.0-4-amd64 #1 SMP Debian 3.16.7-ckt25-2+deb8u3 (2016-07-02) x86_64 GNU/Linux What follows is probably related to   https://rt.perl.org/Public/Bug/Display.html?id=77706 with a discussion and a short bug trigger in   https://rt.perl.org/Public/Bug/Display.html?id=114372 the short bug trigger being   $ perl -e '@x=(1,2); @h{@x=sort}=@x'   panic: attempt to copy freed scalar e45e78 at -e line 1. If this fails:   my @L = (1);   sub a { my ($l) = @_; shift @$l while @$l; }   sub b { a(\@L); my $a = shift; }   b(@L); Then surely this must fail:   sub a { my ($l) = @_; shift @$l while @$l; }   sub main {     a(\@ARGV);     my $a = shift;   }   main(@ARGV); This is why this fails:   sub GetOptionsFromArray {     my ($argv, @optionlist) = @_;     while (@$argv > 0) {       shift(@$argv);     }   }   sub main {    GetOptionsFromArray(\@ARGV);    my $arg = shift;   }   main(@ARGV); Which makes @ARGV rather unusable after a call to Getoptions: https://stackoverflow.com/questions/26508899/error-panic-attempt-to-copy-freed-scalar-when-using-getoptlong   use Getopt::Long qw(GetOptions);   sub main {     GetOptions();     my $arg=shift;   }   main(@ARGV); In other words, pretty please, use the following bugware in Getopt::Long while this long-standing, hard to fix, far and deep reaching, core Perl bug exists. What follows should be enough and not hurt performance too much; maybe add comments to explain why we must use a reference to a copy of @ARGV, not a reference to @ARGV itself: --- Long.pm.orig        2017-03-09 08:07:20.000000000 +0100 +++ Long.pm     2017-03-09 08:07:49.000000000 +0100 @@ -177,7 +177,7 @@  sub getoptions {      my ($self) = shift; -    return $self->getoptionsfromarray(\@ARGV, @_); +    return $self->getoptionsfromarray([@ARGV], @_);  }  sub getoptionsfromarray { @@ -255,7 +255,7 @@  sub GetOptions(@) {      # Shift in default array. -    unshift(@_, \@ARGV); +    unshift(@_, [@ARGV]);      # Try to keep caller() and Carp consistent.      goto &GetOptionsFromArray;  }
Subject: Re: [rt.cpan.org #120562] please circumvent a core Perl bug in Getopt::Long
Date: Thu, 9 Mar 2017 10:45:42 +0100
To: bug-Getopt-Long [...] rt.cpan.org
From: Johan Vromans <jvromans [...] squirrel.nl>
By using a (reference to a) copy of @ARGV, GetOptions can no longer modify it. @ARGV = ( "--foo", "xx" ); GetOptions( "foo" ); # @ARGV is now ( "xx" ) As far as I can see it is the weird way you call GetOptions that trigger the bug, not GetOptions itself. Eliminate the weirdness (trivial) and the bug disappears. Do you have examples of bug triggering that can not easily be avoided?
On Thu Mar 09 02:21:31 2017, sblondeel@yahoo.com wrote: Show quoted text
> Which makes @ARGV rather unusable after a call to Getoptions: > > https://stackoverflow.com/questions/26508899/error-panic-attempt-to- > copy-freed-scalar-when-using-getoptlong > >   use Getopt::Long qw(GetOptions); >   sub main { >     GetOptions(); >     my $arg=shift; >   } >   main(@ARGV);
The reason you are getting a freed scalar (as I am sure you are aware) is that the elements of @_ are aliased to the elements of @ARGV without holding a reference count. If you take a reference to \@_ from inside the main sub before calling GetOptions, it will ‘reify’ @_ and make it hold reference counts on its elements, thereby circumventing the bug. However, I don’t think it will do what you want. Getopt::Long is designed specifically to remove the options it parses from @ARGV, so that all you have left are the command line arguments that come after the options. For example, if you write a ‘tail’ program in perl, then GetOptions will remove the -f in ‘tail -f foo’ and leave you just the foo, which is what most programs want. If you want to make @_ an alias to @ARGV, so that you can use shift, etc., inside a sub without having to say @ARGV explicitly, you can alias it like this: *_ = \@ARGV; &main; # no parentheses The &foo-style call leaves @_ alone; i.e., whatever array @_ pointed to outside the sub call is visible in the sub, which in this case is the same as @ARGV.
Subject: Re: [rt.cpan.org #120562] please circumvent a core Perl bug in Getopt::Long
Date: Thu, 16 Mar 2017 20:53:08 +0000 (UTC)
To: "bug-Getopt-Long [...] rt.cpan.org" <bug-Getopt-Long [...] rt.cpan.org>
From: Sébastien Blondeel <sblondeel [...] yahoo.com>
Thank you for your kind answers. I had failed to realize Getopt::Long meant to tweak @ARGV with side effects, and this had a nasty interaction with my habit of using C-like entry points in Perl scripts (in order to incite future maintainers to not hide active code at top level or such nasty ideas). Recent Enlightenment made me realize the other practical thorn in the foot I had with respect to this core Perl bug probably boiled down to the same cause: $ cat /tmp/cr.pl use Carp qw( carp ); use Getopt::Long qw( GetOptions ); sub main {   GetOptions();   carp("Hello"); } exit main(@ARGV); $ perl /tmp/cr.pl jkjkl jkljlk panic: attempt to copy freed scalar 12521c0 to 12f1b08 at /usr/share/perl/5.20/Carp.pm line 228. I understand the core Perl bug is nasty and tricky and takes a lot of efforts to fix. Let's hope it does not get buried and forgotten. In the mean time, I will remember to tell people to not use "global" ("top level"?) variables (such as the @L in my first example) and avoid using GetOptions(), but rather use GetOptionsFromArray() (and passing it a reference to a copy of @ARGV or whatever). On Thursday, March 9, 2017 8:00 PM, Father Chrysostomos via RT <bug-Getopt-Long@rt.cpan.org> wrote: <URL: https://rt.cpan.org/Ticket/Display.html?id=120562 > On Thu Mar 09 02:21:31 2017, sblondeel@yahoo.com wrote: Show quoted text
> Which makes @ARGV rather unusable after a call to Getoptions: > > https://stackoverflow.com/questions/26508899/error-panic-attempt-to- > copy-freed-scalar-when-using-getoptlong > >   use Getopt::Long qw(GetOptions); >   sub main { >     GetOptions(); >     my $arg=shift; >   } >   main(@ARGV);
The reason you are getting a freed scalar (as I am sure you are aware) is that the elements of @_ are aliased to the elements of @ARGV without holding a reference count. If you take a reference to \@_ from inside the main sub before calling GetOptions, it will ‘reify’ @_ and make it hold reference counts on its elements, thereby circumventing the bug.  However, I don’t think it will do what you want. Getopt::Long is designed specifically to remove the options it parses from @ARGV, so that all you have left are the command line arguments that come after the options.  For example, if you write a ‘tail’ program in perl, then GetOptions will remove the -f in ‘tail -f foo’ and leave you just the foo, which is what most programs want. If you want to make @_ an alias to @ARGV, so that you can use shift, etc., inside a sub without having to say @ARGV explicitly, you can alias it like this: *_ = \@ARGV; &main; # no parentheses The &foo-style call leaves @_ alone; i.e., whatever array @_ pointed to outside the sub call is visible in the sub, which in this case is the same as @ARGV.
Subject: Re: [rt.cpan.org #120562] please circumvent a core Perl bug in Getopt::Long
Date: Thu, 27 Apr 2017 07:13:26 +0000 (UTC)
To: "bug-Getopt-Long [...] rt.cpan.org" <bug-Getopt-Long [...] rt.cpan.org>
From: Sébastien Blondeel <sblondeel [...] yahoo.com>
The following is an easy fix I used in my framework. I guess it could be backported to Getopt::Long, it should not have too many side effects or performance issues. $ cat /tmp/cr2.pl use Carp qw( carp ); use Getopt::Long qw( GetOptionsFromArray ); sub myGetOptions {   my (@args) = @_;   my @argv = @ARGV;   GetOptionsFromArray(\@argv, @args);   @ARGV = @argv; } sub main {   myGetOptions();   carp("Hello"); } exit main(@ARGV); $ perl /tmp/cr2.pl  jkl jlk Hello at /tmp/cr2.pl line 13.         main::main("jkl", "jlk") called at /tmp/cr2.pl line 16
Subject: Re: [rt.cpan.org #120562] please circumvent a core Perl bug in Getopt::Long
Date: Sun, 16 Dec 2018 07:19:11 +0000 (UTC)
To: "bug-Getopt-Long [...] rt.cpan.org" <bug-Getopt-Long [...] rt.cpan.org>
From: Sébastien Blondeel <sblondeel [...] yahoo.com>
The problem lied in Carp (and beyond that, in DB/Perl core, the infamous RT 77706).It is not necessary to use @ARGV or any predefined variables to trigger it as the following code shows: #! /usr/bin/perl use Carp qw( carp ); my @toto = (qw(a b c d)); sub main {   carp('Hello');   @toto = @toto x 1000;   carp('Bye'); } exit main(@ARGV); $ perl a.pl ...at least it fails on 5.24.1 (but not on 5.20.2!). As I was about to report that on Carp I noticed the problem had gone in 5.28.0 (as of Carp 1.47).The comment is not too reassuring (it does not guarantee 100% protection) so I will use the following extra steps in my code (all tested and sufficient by themselves): 1/ use exit main(@[@ARGV])2/ use GetOptionsFromArray([@ARRAY], \%h, ...) instead of GetOptions(\%h, ...)3/ use a locally patched Carp.pm (called Carp2) while not migrated to 5.28 (or 5.28's). This seems to work in the particular case of @ARGV: replace             @args = @DB::args; with             if (scalar caller ($i+1)) {               @args = @DB::args;             } else {               @args = @ARGV;             } HTH,
Seems to be fixed in newer perl versions.