Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perl's caller() function returning incorrect line number

Tags:

perl

I've got the following script running on Perl 5.10.1:

#!/usr/bin/perl
use strict;
use warnings;

foreach( my $x =0 ; $x < 1; $x++) {   # Line 5
  print_line();                       # Line 6
} 

sub print_line {
  print "Function call from line: " . [caller(0)]->[2] . "\n";
}

Despite the call to the subroutine coming from line 6, the script outputs the line number of the start of the C-style for statement:

Function call from line: 5

What's really weird is if I throw a random statement into one of the blank line in the C-style for loop, caller returns the correct line number:

#!/usr/bin/perl
use strict;
use warnings;

foreach( my $x =0 ; $x < 1; $x++) {
  my $x = 3;
  print_line();  # Line 7
}

sub print_line {
  print "Function call from line: " . [caller(0)]->[2] . "\n";
}

The above script correctly outputs:

Function call from line: 7

Is this some kind of bug or is there something I can do to get caller to accurately report the line number?

like image 563
StevieD Avatar asked Feb 21 '15 23:02

StevieD


2 Answers

I think potentially it is a bug, because the same behavior doesn't occur if you replace

foreach (my $x = 0 ; $x < 1 ; $x++) {

with

foreach my $x (0 .. 0) {

I don't understand exactly what's happening, but by comparing the optrees of the two different versions, I think that a nextstate op is getting improperly optimized out. My version has

<;> nextstate(main 4 lineno.pl:11) v:*,&,x*,x&,x$,$ ->8

as the left sibling of the entersub op that calls print_line, while yours has

<0> ex-nextstate v ->8

which has been taken out of the flow of execution.

It wouldn't hurt to write this up as a perlbug.

like image 187
hobbs Avatar answered Sep 28 '22 18:09

hobbs


$ perl -MO=Concise a.pl
j  <@> leave[1 ref] vKP/REFC ->(end)
1     <0> enter ->2
2     <;> nextstate(main 6 a.pl:5) v:*,&,{,x*,x&,x$,$ ->3
5     <2> sassign vKS/2 ->6
3        <$> const[IV 0] s ->4
4        <0> padsv[$x:3,5] sRM*/LVINTRO ->5
6     <0> unstack v* ->7
i     <2> leaveloop vK/2 ->j
7        <{> enterloop(next->b last->i redo->8) v ->e
-        <1> null vK/1 ->i
h           <|> and(other->8) vK/1 ->i
g              <2> lt sK/2 ->h
e                 <0> padsv[$x:3,5] s ->f
f                 <$> const[IV 1] s ->g
-              <@> lineseq vK ->-
-                 <@> scope vK ->b                       <---
-                    <0> ex-nextstate v ->8              <---
a                    <1> entersub[t5] vKS/TARG,2 ->b
-                       <1> ex-list K ->a
8                          <0> pushmark s ->9
-                          <1> ex-rv2cv sK/2 ->-
9                             <#> gv[*print_line] s/EARLYCV ->a
c                 <1> preinc[t2] vK/1 ->d
b                    <0> padsv[$x:3,5] sRM ->c
d                 <0> unstack v ->e
a.pl syntax OK

There's some optimization going on. The scope was deemed unnecessary and optimized away. (Notice the "-" meaning it's never reached.)

But at the same time, that removed the nextstate op, which is what sets the line number for warnings and for caller.

So, it's a bug that results from an improper optimization.

like image 40
ikegami Avatar answered Sep 28 '22 19:09

ikegami