http://www.perlmonks.org?node_id=1225829

LanX has asked for the wisdom of the Perl Monks concerning the following question:

Hi

I'm not sure but it seems like B::Xref is buggy, after running perl -MO=Xref,-r,-d tst_b_xref.pl

with 5.24 Activestate on

D:\tmp>perl -c tst_b_xref.pl tst_b_xref.pl syntax OK D:\tmp>more tst_b_xref.pl use strict; my $sth; my $lines; while ( my @row = $sth->fetchrow_array ) { #5 print "@row.\n"; #7 push @{$lines},+{status => $row[0]}; #9 }

I'm getting

tst_b_xref.pl (main) 2 (lexical) $ sth + intro tst_b_xref.pl (main) 2 (lexical) $ lines + intro tst_b_xref.pl (main) 7 main $ " + used tst_b_xref.pl (main) 7 (lexical) @ row + used tst_b_xref.pl (main) 9 (lexical) $ lines + used tst_b_xref.pl (main) 9 (lexical) @$ lines + used tst_b_xref.pl (main) 9 (lexical) $ sth + used tst_b_xref.pl (main) 9 (lexical) $ sth + subused tst_b_xref.pl (main) 9 (lexical) @ row + intro

please note that @row was "intro"-duced in line 5 inside while and "used" in line 7 and 9,

But the output says used in 7 and introduced in 9, which doesn't really make sense.

(I'm taking no issues (yet) on the "$ sth subused" line which is reporting the ->fetchrow method call.)

update
Reproduced with 5.18 under Ubuntu
$ cat /tmp/xref.out tst_b_xref.pl (main) 2 (lexical) $ sth + intro tst_b_xref.pl (main) 3 (lexical) $ lines + intro tst_b_xref.pl (main) 7 main $ " + used tst_b_xref.pl (main) 7 (lexical) @ row + used tst_b_xref.pl (main) 9 (lexical) $ lines + used tst_b_xref.pl (main) 9 (lexical) @$ lines + used tst_b_xref.pl (main) 9 (lexical) $ sth + used tst_b_xref.pl (main) 9 (lexical) $ sth + subused tst_b_xref.pl (main) 9 (lexical) @ row + intro

Cheers Rolf
(addicted to the Perl Programming Language :)
Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

update

Added line numbers

update

Perl seems to optimise to my ($sth,$lines);', that's why '$lines is reported at line 2 not 3.

Replies are listed 'Best First'.
Re: B::Xref buggy?
by dave_the_m (Monsignor) on Nov 15, 2018 at 11:58 UTC
    Line number reporting in perl is a bit dodgy. The only place in the optree where the src line number is recorded is in 'nextstate' ops which are prepended to each statement. Whether B::Xref is doing even worse than is merited even by the poor quality data available to it, I don't know - I haven't looked closely enough at your example.

    Dave.

      It's probably dodgy if you have two statements in the same line.

      But Xref is ignoring the whole part inside while (...) and the linenumber is present, I used B::Concise to check.

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

        Looking at the src code for B::Xref, it appears to scan the op tree in execution (op_next) order, noting the current line and file number any time it sees an OP_NEXTSTATE. When it comes to an op that has more than one possible next op (such as loops etc) it recursively follows each branch, without restoring the old file/line number on each return. Thus giving silly results.

        Dave.

Re: B::Xref buggy?
by ikegami (Patriarch) on Nov 16, 2018 at 20:57 UTC

    The line number to be used by warnings is set by an nextstate op that's placed at the start of each statement. These are the lines numbers used by B::Xref.

    A while loop statement starts with an enterloop op that should only be executed when the loop is entered, not every pass of the loop. As such, the bottom of the loop continues directly to the loop condition rather than the start of the statement. This bypasses the opcode that sets the line number.

    Therefore, according to the way the ops are stored, the condition is considered part of the while loop statement, as well as part of the last statement of the loop.

    It might be possible for B::Xref to be smarter, but it's really a problem with Perl itself.

    use strict; use warnings; my $c = 0; while ( warn("x"), ++$c<2 ) { my $dummy; }
    x at a.pl line 5. x at a.pl line 6.

    It seems to me this could be solved by placing a nextstate at the start of the while loop condition. I don't know why this isn't done.