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

Array-dereferencing fails silently in Autoloaded functions while direct reference access works #22842

Open
prismado opened this issue Dec 5, 2024 · 4 comments

Comments

@prismado
Copy link

prismado commented Dec 5, 2024

Module: AutoLoader

Description
I discovered a reproducible issue where array dereferencing behaves unexpectedly within autoloaded functions, while working perfectly fine in regular module functions.

Specifically, when using localtime() in an autoloaded function, accessing the array elements via direct assignment fails silently - the variables remain undefined. However, accessing the same values through a foreach loop with the array reference works correctly.

Steps to Reproduce
In autoloaded function (e.g., auto/MyModule/test.al):

    sub test {
     my $self = shift;
    
    # This works - prints correct time elements:
    foreach (@{ localtime(time()) }) {
        print "$_\n";
    }
    
    # This fails - all variables remain undefined:
    my @time_parts = localtime(time());
    my $y = $time_parts[5];  # undefined
    my $m = $time_parts[4];  # undefined
    my $d = $time_parts[3];  # undefined
    
    # The same code works perfectly in regular module functions
    }

Expected behavior
Workaround:

    # Working solution using explicit copying:
    my @elements;
    foreach my $val (@{ localtime(time()) }) {
       push @elements, $val;
    }
    my $y = $elements[5];  # now works correctly

Perl configuration

Summary of my perl5 (revision 5 version 36 subversion 0) configuration:

  Platform:
    osname=linux
    osvers=4.19.0
    archname=x86_64-linux-gnu-thread-multi
    uname='linux localhost 4.19.0 #1 smp debian 4.19.0 x86_64 gnulinux '
    config_args='-Dmksymlinks -Dusethreads -Duselargefiles -Dcc=x86_64-linux-gnu-gcc -Dcpp=x86_64-linux-gnu-cpp -Dld=x86_64-linux-gnu-gcc -Dccflags=-DDEBIAN -Wdate-time -D_FORTIFY_SOURCE=2 -g -O2 -ffile-prefix-map=/dummy/build/dir=. -fstack-protector-strong -Wformat -Werror=format-security -Dldflags= -Wl,-z,relro -Dlddlflags=-shared -Wl,-z,relro -Dcccdlflags=-fPIC -Darchname=x86_64-linux-gnu -Dprefix=/usr -Dprivlib=/usr/share/perl/5.36 -Darchlib=/usr/lib/x86_64-linux-gnu/perl/5.36 -Dvendorprefix=/usr -Dvendorlib=/usr/share/perl5 -Dvendorarch=/usr/lib/x86_64-linux-gnu/perl5/5.36 -Dsiteprefix=/usr/local -Dsitelib=/usr/local/share/perl/5.36.0 -Dsitearch=/usr/local/lib/x86_64-linux-gnu/perl/5.36.0 -Dman1dir=/usr/share/man/man1 -Dman3dir=/usr/share/man/man3 -Dsiteman1dir=/usr/local/man/man1 -Dsiteman3dir=/usr/local/man/man3 -Duse64bitint -Dman1ext=1 -Dman3ext=3perl -Dpager=/usr/bin/sensible-pager -Uafs -Ud_csh -Ud_ualarm -Uusesfio -Uusenm -Ui_libutil -Ui_xlocale -Uversiononly -DDEBUGGING=-g -Doptimize=-O2 -dEs -Duseshrplib -Dlibperl=libperl.so.5.36.0'
    hint=recommended
    useposix=true
    d_sigaction=define
    useithreads=define
    usemultiplicity=define
    use64bitint=define
    use64bitall=define
    uselongdouble=undef
    usemymalloc=n
    default_inc_excludes_dot=define
  Compiler:
    cc='x86_64-linux-gnu-gcc'
    ccflags ='-D_REENTRANT -D_GNU_SOURCE -DDEBIAN -fwrapv -fno-strict-aliasing -pipe -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64'
    optimize='-O2 -g'
    cppflags='-D_REENTRANT -D_GNU_SOURCE -DDEBIAN -fwrapv -fno-strict-aliasing -pipe -I/usr/local/include'
    ccversion=''
    gccversion='12.2.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='x86_64-linux-gnu-gcc'
    ldflags =' -fstack-protector-strong -L/usr/local/lib'
    libpth=/usr/local/lib /usr/lib/x86_64-linux-gnu /usr/lib /lib/x86_64-linux-gnu /lib
    libs=-lgdbm -lgdbm_compat -ldb -ldl -lm -lpthread -lc -lcrypt
    perllibs=-ldl -lm -lpthread -lc -lcrypt
    libc=/lib/x86_64-linux-gnu/libc.so.6
    so=so
    useshrplib=true
    libperl=libperl.so.5.36
    gnulibc_version='2.36'
  Dynamic Linking:
    dlsrc=dl_dlopen.xs
    dlext=so
    d_dlsymun=undef
    ccdlflags='-Wl,-E'
    cccdlflags='-fPIC'
    lddlflags='-shared -L/usr/local/lib -fstack-protector-strong'


Characteristics of this binary (from libperl):
  Compile-time options:
    HAS_TIMES
    MULTIPLICITY
    PERLIO_LAYERS
    PERL_COPY_ON_WRITE
    PERL_DONT_CREATE_GVSV
    PERL_MALLOC_WRAP
    PERL_OP_PARENT
    PERL_PRESERVE_IVUV
    USE_64_BIT_ALL
    USE_64_BIT_INT
    USE_ITHREADS
    USE_LARGE_FILES
    USE_LOCALE
    USE_LOCALE_COLLATE
    USE_LOCALE_CTYPE
    USE_LOCALE_NUMERIC
    USE_LOCALE_TIME
    USE_PERLIO
    USE_PERL_ATOF
    USE_REENTRANT_API
    USE_THREAD_SAFE_LOCALE
  Locally applied patches:
    DEBPKG:debian/cpan_definstalldirs - Provide a sensible INSTALLDIRS default for modules installed from CPAN.
    DEBPKG:debian/db_file_ver - https://bugs.debian.org/340047 Remove overly restrictive DB_File version check.
    DEBPKG:debian/doc_info - Replace generic man(1) instructions with Debian-specific information.
    DEBPKG:debian/enc2xs_inc - https://bugs.debian.org/290336 Tweak enc2xs to follow symlinks and ignore missing @INC directories.
    DEBPKG:debian/errno_ver - https://bugs.debian.org/343351 Remove Errno version check due to upgrade problems with long-running processes.
    DEBPKG:debian/libperl_embed_doc - https://bugs.debian.org/186778 Note that libperl-dev package is required for embedded linking
    DEBPKG:fixes/respect_umask - Respect umask during installation
    DEBPKG:debian/writable_site_dirs - Set umask approproately for site install directories
    DEBPKG:debian/extutils_set_libperl_path - EU:MM: set location of libperl.a under /usr/lib
    DEBPKG:debian/no_packlist_perllocal - Don't install .packlist or perllocal.pod for perl or vendor
    DEBPKG:debian/fakeroot - Postpone LD_LIBRARY_PATH evaluation to the binary targets.
    DEBPKG:debian/instmodsh_doc - Debian policy doesn't install .packlist files for core or vendor.
    DEBPKG:debian/ld_run_path - Remove standard libs from LD_RUN_PATH as per Debian policy.
    DEBPKG:debian/libnet_config_path - Set location of libnet.cfg to /etc/perl/Net as /usr may not be writable.
    DEBPKG:debian/perlivp - https://bugs.debian.org/510895 Make perlivp skip include directories in /usr/local
    DEBPKG:debian/squelch-locale-warnings - https://bugs.debian.org/508764 Squelch locale warnings in Debian package maintainer scripts
    DEBPKG:debian/patchlevel - https://bugs.debian.org/567489 List packaged patches for 5.36.0-7+deb12u1 in patchlevel.h
    DEBPKG:fixes/document_makemaker_ccflags - https://bugs.debian.org/628522 [rt.cpan.org #68613] Document that CCFLAGS should include $Config{ccflags}
    DEBPKG:debian/find_html2text - https://bugs.debian.org/640479 Configure CPAN::Distribution with correct name of html2text
    DEBPKG:debian/perl5db-x-terminal-emulator.patch - https://bugs.debian.org/668490 Invoke x-terminal-emulator rather than xterm in perl5db.pl
    DEBPKG:debian/cpan-missing-site-dirs - https://bugs.debian.org/688842 Fix CPAN::FirstTime defaults with nonexisting site dirs if a parent is writable
    DEBPKG:fixes/memoize_storable_nstore - [rt.cpan.org #77790] https://bugs.debian.org/587650 Memoize::Storable: respect 'nstore' option not respected
    DEBPKG:debian/makemaker-pasthru - https://bugs.debian.org/758471 Pass LD settings through to subdirectories
    DEBPKG:debian/makemaker-manext - https://bugs.debian.org/247370 Make EU::MakeMaker honour MANnEXT settings in generated manpage headers
    DEBPKG:debian/kfreebsd-softupdates - https://bugs.debian.org/796798 Work around Debian Bug#796798
    DEBPKG:fixes/memoize-pod - [rt.cpan.org #89441] Fix POD errors in Memoize
    DEBPKG:debian/hurd-softupdates - https://bugs.debian.org/822735 Fix t/op/stat.t failures on hurd
    DEBPKG:fixes/math_complex_doc_great_circle - https://bugs.debian.org/697567 [rt.cpan.org #114104] Math::Trig: clarify definition of great_circle_midpoint
    DEBPKG:fixes/math_complex_doc_see_also - https://bugs.debian.org/697568 [rt.cpan.org #114105] Math::Trig: add missing SEE ALSO
    DEBPKG:fixes/math_complex_doc_angle_units - https://bugs.debian.org/731505 [rt.cpan.org #114106] Math::Trig: document angle units
    DEBPKG:fixes/cpan_web_link - https://bugs.debian.org/367291 CPAN: Add link to main CPAN web site
    DEBPKG:debian/hppa_op_optimize_workaround - https://bugs.debian.org/838613 Temporarily lower the optimization of op.c on hppa due to gcc-6 problems
    DEBPKG:debian/installman-utf8 - https://bugs.debian.org/840211 Generate man pages with UTF-8 characters
    DEBPKG:debian/hppa_opmini_optimize_workaround - https://bugs.debian.org/869122 Lower the optimization level of opmini.c on hppa
    DEBPKG:debian/sh4_op_optimize_workaround - https://bugs.debian.org/869373 Also lower the optimization level of op.c and opmini.c on sh4
    DEBPKG:debian/perldoc-pager - https://bugs.debian.org/870340 [rt.cpan.org #120229] Fix perldoc terminal escapes when sensible-pager is less
    DEBPKG:debian/prune_libs - https://bugs.debian.org/128355 Prune the list of libraries wanted to what we actually need.
    DEBPKG:debian/mod_paths - Tweak @INC ordering for Debian
    DEBPKG:debian/deprecate-with-apt - https://bugs.debian.org/747628 Point users to Debian packages of deprecated core modules
    DEBPKG:debian/disable-stack-check - https://bugs.debian.org/902779 [GH #16607] Disable debugperl stack extension checks for binary compatibility with perl
    DEBPKG:debian/perlbug-editor - https://bugs.debian.org/922609 Use "editor" as the default perlbug editor, as per Debian policy
    DEBPKG:debian/eu-mm-perl-base - https://bugs.debian.org/962138 Suppress an ExtUtils::MakeMaker warning about our non-default @INC
    DEBPKG:fixes/io_socket_ip_ipv6 - Disable getaddrinfo(3) AI_ADDRCONFIG for localhost and IPv4 numeric addresses
    DEBPKG:debian/usrmerge-lib64 - https://bugs.debian.org/914128 Configure / libpth.U: Do not adjust glibpth when /usr/lib64 is present.
    DEBPKG:debian/usrmerge-realpath - https://bugs.debian.org/914128 Configure / libpth.U: use realpath --no-symlinks on Debian
    DEBPKG:debian/configure-regen - https://bugs.debian.org/762638 Regenerate Configure et al. after probe unit changes
    DEBPKG:fixes/x32-io-msg-skip - https://bugs.debian.org/922609 Skip io/msg.t on x32 due to broken System V message queues
    DEBPKG:debian/hurd-eumm-workaround - https://bugs.debian.org/1018289 Work around a MakeMaker regression breaking GNU/Hurd hint files
    DEBPKG:fixes/json-pp-warnings - https://bugs.debian.org/1019757 Call unimport first to silence warnings
    DEBPKG:fixes/readline-stream-errors - [80c1f1e] [GH #6799] https://bugs.debian.org/1016369 only clear the stream error state in readline() for glob()
    DEBPKG:fixes/readline-stream-errors-test - [0b60216] [GH #6799] https://bugs.debian.org/1016369 test that <> doesn't clear the stream error state
    DEBPKG:fixes/lto-test-fix - [69b4fa3] [GH #20518] https://bugs.debian.org/1015579 skip checking categorization of libperl symbols for LTO builds
    DEBPKG:fixes/CVE-2023-47038 - [7047915] https://bugs.debian.org/1056746 Fix read/write past buffer end: perl-security#140
  Built under linux
  Compiled at Nov 25 2023 20:59:54
  @INC:
    /etc/perl
    /usr/local/lib/x86_64-linux-gnu/perl/5.36.0
    /usr/local/share/perl/5.36.0
    /usr/lib/x86_64-linux-gnu/perl5/5.36
    /usr/share/perl5
    /usr/lib/x86_64-linux-gnu/perl-base
    /usr/lib/x86_64-linux-gnu/perl/5.36
    /usr/share/perl/5.36
    /usr/local/lib/site_perl
@haarg
Copy link
Contributor

haarg commented Dec 6, 2024

I can't reproduce this using only the code you have shown.

Are you using a module like Time::localtime?

Can you show a complete example of a broken module, rather than just a fragment?

@mauke
Copy link
Contributor

mauke commented Dec 6, 2024

However, accessing the same values through a foreach loop with the array reference works correctly.

That's not the same values. The core localtime returns a list, so these work:

my @parts = localtime();
foreach my $val (localtime()) { }

If you're using a module that overrides localtime to return an array reference, you need to dereference it:

my @parts = @{ localtime() };
foreach my $val (@{ localtime() }) { }

(However, if you're using Time::localtime, that would be breaking the abstraction. You're supposed to use named accessors to get the fields.)

Not sure what any of this has to do with autoloading.

@haarg
Copy link
Contributor

haarg commented Dec 6, 2024

The only thing likely to be relevant to AutoLoader is that it means all of your code runs with strict off, so it will hide some problems.

@prismado
Copy link
Author

prismado commented Dec 9, 2024

Thank you very much for your valued feedback. The problem has been with me for several weeks. As a brief general explanation, the code ran unchanged for many years, was used excessively (as timestamp queries) and never caused any problems.

My main Perl module had the following structure, whereby the connection to the database should be irrelevant.

package ScreenPoint::Core;

use Exporter;
use AutoLoader;
@ISA = qw(Exporter AutoLoader);

use strict;
########################################################################
# Core
########################################################################
my $package = __PACKAGE__;
our $VERSION = '1.0001';
our %dbh;
$| = 1;

use Apache2::Cookie;
use DBI;

sub new {
    my $type = shift;
    my $self = {};

    $self->{R} = shift;
    $self->{M} = shift;
    $self->{PATH} = shift; 
    $self->{MODE} = shift;

    $self->{CGI} = $self->{M}->cgi_object;

    $dbh{$ENV{'db_name'}} ||= &connect_db( $self );

    unless ($dbh{$ENV{'db_name'}}) {
            print STDERR "ERROR: No db connection!\n";
            bless $self, $type;
            return;
    }

    $self->{dbh} = $dbh{$ENV{db_name}};

    my $sth = $self->{dbh}->prepare('SELECT `key`, val FROM config');
       $sth->execute();
    my %config = my @debug_info = ();
    while(my $r = $sth->fetch()) { $config{$r->[0]} = $r->[1]; }
    $self->{CONFIG} = \%config;
    $self->{DEBUG_INFO} = \@debug_info;

    bless $self, $type;
}

The autoloaded function had the following content:

#!/usr/bin/perl -w
package ScreenPoint::Core;
use strict;
sub now {
      my $self = shift;
      my $offset = shift || 0; # -- Seconds
      my $tstamp = time() + $offset;
      my ($y, $m, $d, $ss, $mm, $hh) = (localtime($tstamp))[5,4,3,0,1,2];
      $y += 1900; $m += 1;
      return sprintf('%d-%02d-%02d %02d:%02d:%02d', $y, $m, $d, $hh, $mm, $ss);
}

After instantiation of the Module with the object variable "$C" I called an autoloaded function "$C->now(1)" via autoload-Funktion (File ".../auto/ScreenPoint/Core/now.al"):

Instead of the expected timestamp, I often got a zero value back through “localtime(time)”:

  my $timestamp = $C->now(1); # -- expected: e.g. 2024-12-09 08:47:00 but got sometimes 1900-00-00 00:00:00.6442311

What currently always works as an emergency solution is to move the identical code to my main module ScreenPoint::Core.pm. The code runs in Apache / Perl / Mason environment.

Thank you all for your tips.

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

4 participants