Skip to content

Do not call DB::sub when overload::("" happens from DB:: namespace as it is documented in perldebguts  #24001

Closed

Description

@KES777

Module: core

Description
I tried to debug "Config.pm:59":

die "$0: Perl lib version (5.41.2) doesn't match executable '$^X' version ($])"
    unless $^V; # line 59

When line 59 is reached the debugger falls into infinite loop.

Steps to Reproduce

$ cat t.pl
1;

$ cat DB.pm
package Tt;

sub t { print "YES" }

package DB;

sub DB { print "next\n" }
sub sub {
	print "$DB::sub called\n";
	Tt::t();                       # This does not cause `DB::sub` to be called
	my $tmp =  "$^V";              # This too should not cause `DB::sub` to be called
	return &$DB::sub;
}

1;

PERL5DB="use DB" perl -I. -d t.pl
UNIVERSAL::import called
YESversion::("" called
...
YESversion::("" called
Segmentation fault

Expected behavior
Stringification of "$^V" ( call to version::("" from DB::sub ) should not cause recursive loop.

Because we are inside "DB::sub":

When execution of the program reaches a subroutine call, a call to &DB::sub(args) is made instead, with $DB::sub set to identify the called subroutine. (This doesn't happen if the calling subroutine was compiled in the DB package.)

https://perldoc.perl.org/perldebguts

Perl configuration

Details
perl -V
Summary of my perl5 (revision 5 version 41 subversion 2) configuration:
   
  Platform:
    osname=linux
    osvers=6.5.0-1027-oem
    archname=x86_64-linux
    uname='linux work 6.5.0-1027-oem #28-ubuntu smp preempt_dynamic thu jul 25 13:32:46 utc 2024 x86_64 x86_64 x86_64 gnulinux '
    config_args='-de -Dprefix=/home/kes/perl5/perlbrew/perls/perl-5.41.2 -Dusedevel -Aeval:scriptdir=/home/kes/perl5/perlbrew/perls/perl-5.41.2/bin'
    hint=recommended
    useposix=true
    d_sigaction=define
    useithreads=undef
    usemultiplicity=undef
    use64bitint=define
    use64bitall=define
    uselongdouble=undef
    usemymalloc=n
    default_inc_excludes_dot=define
  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='13.1.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='cc'
    ldflags =' -fstack-protector-strong -L/usr/local/lib'
    libpth=/usr/local/lib /usr/lib/x86_64-linux-gnu /usr/lib /usr/lib64
    libs=-lpthread -ldl -lm -lcrypt -lutil -lc
    perllibs=-lpthread -ldl -lm -lcrypt -lutil -lc
    libc=/lib/x86_64-linux-gnu/libc.so.6
    so=so
    useshrplib=false
    libperl=libperl.a
    gnulibc_version='2.35'
  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'


Characteristics of this binary (from libperl): 
  Compile-time options:
    HAS_LONG_DOUBLE
    HAS_STRTOLD
    HAS_TIMES
    PERLIO_LAYERS
    PERL_COPY_ON_WRITE
    PERL_DONT_CREATE_GVSV
    PERL_HASH_FUNC_SIPHASH13
    PERL_HASH_USE_SBOX32
    PERL_MALLOC_WRAP
    PERL_OP_PARENT
    PERL_PRESERVE_IVUV
    PERL_USE_DEVEL
    PERL_USE_SAFE_PUTENV
    USE_64_BIT_ALL
    USE_64_BIT_INT
    USE_LARGE_FILES
    USE_LOCALE
    USE_LOCALE_COLLATE
    USE_LOCALE_CTYPE
    USE_LOCALE_NUMERIC
    USE_LOCALE_TIME
    USE_PERLIO
    USE_PERL_ATOF
  Built under linux
  Compiled at Aug 17 2024 19:35:18
  %ENV:
    PERLBREW="command perlbrew"
    PERLBREW_HOME="/home/kes/.perlbrew"
    PERLBREW_MANPATH="/home/kes/perl5/perlbrew/perls/perl-5.41.2/man"
    PERLBREW_PATH="/home/kes/perl5/perlbrew/bin:/home/kes/perl5/perlbrew/perls/perl-5.41.2/bin"
    PERLBREW_PERL="perl-5.41.2"
    PERLBREW_ROOT="/home/kes/perl5/perlbrew"
    PERLBREW_SHELLRC_VERSION="0.98"
    PERLBREW_VERSION="0.98"
  @INC:
    /home/kes/perl5/perlbrew/perls/perl-5.41.2/lib/site_perl/5.41.2/x86_64-linux
    /home/kes/perl5/perlbrew/perls/perl-5.41.2/lib/site_perl/5.41.2
    /home/kes/perl5/perlbrew/perls/perl-5.41.2/lib/5.41.2/x86_64-linux
    /home/kes/perl5/perlbrew/perls/perl-5.41.2/lib/5.41.2

Activity

  1. KES777 commented on Dec 12, 2025

    @KES777
    ContributorAuthor

    Slightly changed reproduction steps:

    $ cat t.pl
    Tt::t();
    
    $ cat DB.pm
    package Tt;
    
    sub t { print "YES" }
    
    package DB;
    
    sub DB { print join ' ', caller(), "\n" }
    sub sub {
    	print "$DB::sub called\n";
    	Tt::t();
    	# my $tmp =  "$^V";
    	return &$DB::sub;
    }
    
    1;
    
    $ perlbrew use perl-5.41.2
    $ PERL5DB="use DB" perl -I. -d t.pl
    UNIVERSAL::import called
    YESmain t.pl 1 
    Tt::t called
    Tt DB.pm 3 
    YESTt DB.pm 3 
    YES
    
    $ perlbrew use perl-5.22.3
    main t.pl 1 
    Tt::t called
    Tt DB.pm 3 
    YESTt DB.pm 3 
    YES

    Because DB::sub is compiled in DB:: package the call to Tt::t from it do not cause DB::sub call.

    The same should happen for version::("" call from DB::sub. (DB::sub should not be triggered).

    Probably issue is that access to $^V is separate call to perl subroutine which switches context from DB:: to version:: and then the call to version::("" is already subject for DB::sub.

    My suggestion is that stringification of $^V should be done inside one subroutine.

  2. KES777 commented on Dec 12, 2025

    @KES777
    ContributorAuthor

    I think this is related https://perldoc.perl.org/overload#Overloadable-Operations:

    The subroutines for '""', '0+', and 'bool' can return any arbitrary Perl value. If the corresponding operation for this value is overloaded too, the operation will be called again with this value.

    I suppose something like this is happening: DB::sub --> overload::XXX --> overload::YYY. The call to overload::YYY causes recursion to DB::sub.
    I suppose calls should look like this: DB::sub --> overload::XXX --> returning to DB:: namespace --> overload::YYY. In this case the call to overload::YYY will not cause recursion to DB::sub because it is done from DB:: namespace.

  3. KES777 commented on Dec 12, 2025

    @KES777
    ContributorAuthor

    Description of more wider problem:

    When we want to track passed/returned values into/from subs and do dumps of them from DB::sub the overloaded functions are called implicitly. In the case above it is stringification version::("".

    Because of this implicity we under debugger with tracking arguments enabled will get Segmentation faults. As workaround we can return early from DB::sub if it was call to overload::, but then it will not allow us to debug functions at that namespace.

  4. Leont commented on Dec 12, 2025

    @Leont
    Contributor

    Possibly, the debugger needs a no overloading; to deal with this sort of thing.

  5. KES777 commented on Dec 12, 2025

    @KES777
    ContributorAuthor

    I changed this part:

    sub sub {
    	print "$DB::sub called\n";
    
    	no overloading;
    	print "$^V";
    
    	return &$DB::sub;
    }
    

    @Leont Ok. This prevents Segmentation fault. Output becomes: version=HASH(0x5612e83ea678).

    But this does not feels like the correct solution, because DB::sub should not be called for a call to version::("" from DB::sub (DB:: namespace) as it was documented in perldebguts.

  6. changed the title [-]Stringification of $^V causes `Segmentation fault` under debugger[/-] [+]Do not call `DB::sub` when `overload::(""` happens from `DB::` namespace as it is documented in `perldebguts` [/+] on Dec 12, 2025
  7. Leont commented on Dec 13, 2025

    @Leont
    Contributor

    But this does not feels like the correct solution, because DB::sub should not be called for a call to version::("" from DB::sub (DB:: namespace) as it was documented in perldebguts.

    I'm not sure what you meant precisely with "as it was documented in perldebguts".

  8. KES777 commented on Dec 13, 2025

    @KES777
    ContributorAuthor

    @Leont
    I mean that stringification of "$^V" ( call to version::("" ) happens from DB:: namespace. Because of this call to DB::sub should not happen.

    https://perldoc.perl.org/perldebguts states that:

    When execution of the program reaches a subroutine call, a call to &DB::sub(args) is made instead, with $DB::sub set to identify the called subroutine. (This doesn't happen if the calling subroutine was compiled in the DB package.)

    The call to version::("" should behave the same way as the call to Tt::t.

    package DB;
    sub sub {
    	print "$DB::sub called\n";
    	Tt::t();                       # This does not cause `DB::sub` to be called
    	my $tmp =  "$^V";              # This too should not cause `DB::sub` to be called
    	return &$DB::sub;
    }
    
  9. Leont commented on Dec 13, 2025

    @Leont
    Contributor

    Thanks, yeah that does make things a lot clearer.

  10. KES777 commented on Dec 14, 2025

    @KES777
    ContributorAuthor

    Sorry, sometimes it is not clear to me to understand what is going wrong in this or that situation. And then took time to create a clear explanation. Usually a few approaches are required. Feel free to ask additional questions if you have any.

  11. tonycoz commented on Dec 16, 2025

    @tonycoz
    Contributor

    At the point of call PL_curstash isn't equal to PL_debstash so the OP generated in amagic_call() has the "breakable" flag (OPpENTERSUB_DB) set on it.

    Breaking on some other OP in the DB::sub sub shows the same.

    PL_curstash is generally a compile-time thing, so I suspect the check against it is erroneous (though call_sv() does the same test).

    On a quick scan of pp_entersub and pp_nextstate I didn't see anything updating PL_curstash, which I'd expect if it was meant to track the stash of the current line being executed.

    Perhaps it should be checking CopSTASH(PL_curcop) instead.

  12. KES777 commented on Jul 16, 2026

    @KES777
    ContributorAuthor

    @tonycoz Thank you very much for the fix.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions