develooper Front page | perl.perl5.porters | Postings from January 2022

Re: Broken stack traces from use statements.

Thread Previous | Thread Next
From:
Dave Mitchell
Date:
January 21, 2022 16:19
Subject:
Re: Broken stack traces from use statements.
Message ID:
YerdF583Nb8AZhYx@iabyn.com
On Sun, Jan 16, 2022 at 02:40:09PM -0500, Ricardo Signes wrote:
> Hello, I am joining this thread way up at the top, because the bottom
> looks like it's gotten pretty sticky.

Hello, thought I'd join you up here where the air is clear and the views
spectacular!

> On the other hand, I think everybody basically agrees that the "fixed"
> behavior is preferable

ribasushi, shadowcat-mst and Vincent Pit in the ticket for 'BBC breaks
DBIx:Class' (#17663), all seemed to think my patch was in some way
philosophically wrong, but to varying degrees agreed to work around it if
we insisted on (eventually) un-reverting it.

So I think we could do with a bit more discussion, which I will seed
below. But my opinion so far is that my patch is correct and should be
applied, but directly after 5.36.0 is released, to give distro owners max
time to fix things up.

First off, much of the discussion in that ticket is very confused/ing, but
various issues are being conflated.

First there is a very specific bug, which makes stack traces into garbage,
whereby if there are nested BEGIN/requires (a.k.a use's) then if the code
croaks within the innermost nested file, the stack backtrace shows *all*
the nested requires etc as having been done in the *lower-most* Foo.pm file,
destroying most of the information that should be contained in the
backtrace, and making it very confusing even for experienced coders.

i.e. the stacktrack looks (in part) like

    require called at C.pm line 7
    require called at C.pm line 7
    require called at C.pm line 7

when you'd expect it to look (in part) like

    require called at A.pm line 245
    require called at B.pm line 35
    require called at C.pm line 7

Technically speaking, this is due to same COP being used for all requires,
so when the current COP gets its file/line number set, all the things up
the stack see the same change.  I don't think (at least I hope) that
anyone disagrees that this is a bug.

My fix for this also changed the general behaviour of how BEGIN reports
its caller - this is the bit which upset various people and broke various
distributions. This is the second issue. I happen to think that my fix was
correct here too, and indeed allows us to close ticket .

To an extent this is a philosophical issue: caller(0) identifies the call
site of who who called us; i.e. in

    sub foo { @c = caller(0); print "@c" }
    ...
    foo(); # call site

we rightly expect caller(0) to identify the file and line containing the
'foo()' call, and identify what package name was in force when that line
was compiled (and also what hints, warnings, hints hash etc were active at
the same time).

The trouble comes from when the sub is a BEGIN - who is the caller of the
sub? What file and line number? What package? What hints and warnings were
in scope?

This can be demonstrated with some simple code, first with the output from
normal perl, and second with perl including my patch:

p:
    #!/usr/bin/perl
    package X;
    use Foo; # equivalent to BEGIN { require Foo.pm }

Foo.pm
    package Foo;
    use Carp;
    confess("in Foo");


$ perl5340 ~/tmp/p
    in Foo at /tmp/lib/Foo.pm line 3.
            require Foo.pm called at /home/davem/tmp/p line 3
            X::BEGIN() called at /tmp/lib/Foo.pm line 0
            eval {...} called at /tmp/lib/Foo.pm line 0

$ patched-perl  ~/tmp/p
    in Foo at /tmp/lib/Foo.pm line 3.
            require Foo.pm called at /home/davem/tmp/p line 3
            X::BEGIN() called at /home/davem/tmp/p line 3
            eval {...} called at /home/davem/tmp/p line 3


To me, it seems trivially clear that current perl is wrong and my patch
fixes it. But the argument that mst and others made (which I didn't
entirely follow) seems to be that, whereas I see the call site for the
BEGIN to reside in the source file at the line at the end of BEGIN, they
see it as being wherever perl was last executing (I think?), which they
seemed to think was the require/eval. But that confused me, because BEGIN
isn't always associated with a require - so what do we do then? Or do they
think that in that case, the 'line 0' stuff is in fact correct?

While most of the modules listed as broken were described in the #17663
BBC ticket, there was another BBC report attached to #15109, for
Devel::CompileLevel, whose breakage was more confusing - the module was
modifying ${^WARNING_BITS} at compile time, then failing to find those
modification where it expected on the stack.  I haven't looked into that
again yet (if ever) because it's taken me long enough today just to
remind myself of what the main issues were in ticket #17663. But I kind
of trust my former self who said it was a bug in the module.


-- 
1 - number of times I have needed to use the cap lock key
10000 - number of times I have CCIDENTLY HIT THE CAPS KEY WHEN TYPING 'A'

Thread Previous | Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About