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

panic: attempt to copy freed scalar via @ARGV on stack, Getopt::Long + Carp::longmess #15959

Open
p5pRT opened this issue Apr 22, 2017 · 4 comments

Comments

@p5pRT
Copy link

p5pRT commented Apr 22, 2017

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

Searchable as RT131192$

@p5pRT
Copy link
Author

p5pRT commented Apr 22, 2017

From @nthykier

Created by @nthykier

Hi,

I discovered that after a change to a project of mine, perl started
throwing Bizarre Copy errors. I eventually reproduced it to the
following test case (included below). As I reduced the test case, the
error eventually turned into "panic​: attempt to copy freed scalar"
(although, tweaks to the test case sometimes flip it back to a Bizarre
copy).

Some observations​:

* @​ARGV must be passed to a sub and @​ARGV must be non-empty
* That sub (or something it calls) must call Getopt​::Long​::GetOptions
* Carp​::longmess() is required to trigger the bug
* Originally discovered on Debian stretch's perl 5.24, but is also
  reproducible in blead.

Running the test case​:

  """
  ./perl -Ilib run.pl --state-dir foo
  panic​: attempt to copy freed scalar 55a956c38168 to 55a956c59510 at lib/Carp.pm line 229.
  """

The definition of run.pl​:

"""
#!/usr/bin/perl -w

use strict;
use warnings;
use Carp qw(longmess);

use Getopt​::Long();
use Errno qw(ENOENT);

my %OPT;
# If the %OPT_HASH is changed, I some times see
my %OPT_HASH= (
  'state-dir=s' => \$OPT{'state-dir'},
  'mirror-path=s' => \$OPT{'mirror-path'},
  # Comma-separated lists
  'distributions=s@​' =>
  sub { push(@​{$OPT{'distributions'}}, split(m/,/, $_[1])); },
  'mirror-areas=s@​' =>
  sub { push(@​{$OPT{'mirror-areas'}}, split(m/,/, $_[1])); },
  'architectures=s@​' =>
  sub { push(@​{$OPT{'architectures'}}, split(m/,/, $_[1])); },
  'desired-version=s' => \$OPT{'desired-version'},
  'lintian-lab=s' => \$OPT{'lintian-lab'},
  'reschedule-all' => \$OPT{'reschedule-all'},
  'help|h' => \&usage,
  'debug|d' => \$OPT{'debug'},
  'dry-run' => \$OPT{'dry-run'},
);

sub tool_main {
  # We have to call GetOptions to reproduce the issue - plus we need
  # at least one argument consumed.
  die("Usage​: $0 --state-dir does-not-matter\n") if not @​ARGV;
  Getopt​::Long​::config('bundling', 'no_getopt_compat', 'no_auto_abbrev');
  Getopt​::Long​::GetOptions(%OPT_HASH) or die("error parsing options\n");
  load_state_cache();
  exit(0);
}

sub load_state_cache {
  my ($state_dir) = @​_;
  my $state_file = "./file-that-does-not-exist";
  my $fd;
  if (not open($fd, '<​:raw', $state_file)) {
  my $err = $!;
  # Originally reproduced with autodie, but it was reproducible by
  # simply calling longmess (which autodie does to collect a stack
  # trace for its exception)
  Carp​::longmess(); # <-- Triggers a "attempt to copy freed scalar"
  # OR a Bizarre copy of X
  die("open ($state_file)​: $err") if $err != ENOENT;
  # Not present; presume empty
  return;
  }
  # We wanted to get here because of ENOENT
  ...;
  close($fd);
  return;
}

sub usage {
  print <<EOF;
Random usage message
EOF

  exit(0);
}

tool_main(@​ARGV); # Has to be here to trigger the error

# Local Variables​:
# indent-tabs-mode​: nil
# cperl-indent-level​: 4
# End​:
# vim​: syntax=perl sw=4 sts=4 sr et

"""

Perl Info

Flags:
    category=core
    severity=low

Site configuration information for perl 5.26.0:

Configured by moon at Sat Apr 22 10:20:49 CEST 2017.

Summary of my perl5 (revision 5 version 26 subversion 0) configuration:
  Commit id: 78d5fac03632a8c05a3e3e954b0cb9dfa0be4f36
  Platform:
    osname=linux
    osvers=4.9.0-2-amd64
    archname=x86_64-linux
    uname='linux hostname 4.9.0-2-amd64 #1 smp debian 4.9.18-1 (2017-03-30) x86_64 gnulinux '
    config_args='-des -DDEBUG'
    hint=recommended
    useposix=true
    d_sigaction=define
    useithreads=undef
    usemultiplicity=undef
    use64bitint=define
    use64bitall=define
    uselongdouble=undef
    usemymalloc=n
    default_inc_excludes_dot=define
    bincompat5005=undef
  Compiler:
    cc='cc'
    ccflags ='-fwrapv -fno-strict-aliasing -pipe -fstack-protector-strong -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64'
    optimize='-O2'
    cppflags='-fwrapv -fno-strict-aliasing -pipe -fstack-protector-strong -I/usr/local/include'
    ccversion=''
    gccversion='6.3.0 20170406'
    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='cc'
    ldflags =' -fstack-protector-strong -L/usr/local/lib'
    libpth=/usr/local/lib /usr/lib/gcc/x86_64-linux-gnu/6/include-fixed /usr/include/x86_64-linux-gnu /usr/lib /lib/x86_64-linux-gnu /lib/../lib /usr/lib/x86_64-linux-gnu /usr/lib/../lib /lib
    libs=-lpthread -lnsl -ldl -lm -lcrypt -lutil -lc
    perllibs=-lpthread -lnsl -ldl -lm -lcrypt -lutil -lc
    libc=libc-2.24.so
    so=so
    useshrplib=false
    libperl=libperl.a
    gnulibc_version='2.24'
  Dynamic Linking:
    dlsrc=dl_dlopen.xs
    dlext=so
    d_dlsymun=undef
    ccdlflags='-Wl,-E'
    cccdlflags='-fPIC'
    lddlflags='-shared -O2 -L/usr/local/lib -fstack-protector-strong'



@INC for perl 5.26.0:
    lib
    /usr/local/lib/perl5/site_perl/5.26.0/x86_64-linux
    /usr/local/lib/perl5/site_perl/5.26.0
    /usr/local/lib/perl5/5.26.0/x86_64-linux
    /usr/local/lib/perl5/5.26.0


Environment for perl 5.26.0:
    HOME=/home/user
    LANG=en_DK.UTF-8
    LANGUAGE=en_GB:en
    LC_NUMERIC=C.UTF-8
    LD_LIBRARY_PATH (unset)
    LOGDIR (unset)
    PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
    PERL_BADLANG (unset)
    SHELL=/bin/bash

@p5pRT
Copy link
Author

p5pRT commented Apr 23, 2017

From zefram@fysh.org

niels@​thykier.net wrote​:

* @​ARGV must be passed to a sub and @​ARGV must be non-empty
* That sub (or something it calls) must call Getopt​::Long​::GetOptions

It's another stack-not-refcounted bug. GetOptions() mutates @​ARGV,
causing deletion of some of its elements that are on the stack.

-zefram

@p5pRT
Copy link
Author

p5pRT commented Apr 23, 2017

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

@p5pRT
Copy link
Author

p5pRT commented Apr 23, 2017

From slade@openmailbox.org

Workaround​: Replace `tool_main(@​ARGV)` with `tool_main(@​ARGV = @​ARGV)`.
I'm not quite sure why this works (or if indeed it works in all cases
where one passes @​ARGV to a sub that mutates it), but it's the most
concise fix I've found.

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

No branches or pull requests

2 participants