I'm getting a strange warning against some Perl code and I'm hoping the SO-brain can help.
The code in question is:
sub add_observation {
my $self = shift;
my $observation = shift;
my $result = $observation->get_datum_result($self->{datum_name});
if(!(defined $result)) {
croak("Datum '$self->{datum_name}' not defined for this observation: ". Dumper($observation));
}
$self->{result} |= $result;
my $observation_time = $observation->get_time();
if($self->{result} == 0){
$self->set_start_time($observation_time);
}
if($result != 0) {
$self->set_end_time($observation_time);
$self->{end_threshold} = $observation_time->epoch() + $self->{timeout};
}
elsif($observation_time->epoch() > $self->{end_threshold}) {
$self->{complete} = 1;
}
return $self->{result};
}
When I run my code, I get the following warning:
Use of uninitialized value in numeric gt (>) at Performance/BadSpan.pm line 67 (#1)
Line 67 equates to the if($result != 0) {
line.
My problem is twofold:
$result
is undefined, when there's some guard code preceding it that ensures that it is defined!=
is 'optimized' to a >
and a <
?What is the version of perl
?
Given
use strict; use warnings;
my $x;
if ( $x ) {
print "here\n";
}
elsif ( $x > 1 ) {
print "there\n";
}
perl
5.10.1 correctly outputs:
Use of uninitialized value $x in numeric gt (>) at C:\Temp\t.pl line 8.
Given that elsif
does not stand alone, but is part of the if
statement, there might have been a bug in earlier versions which reported the line number of the enclosing if
statement.
This post and this entry in perltodo
seem relevant:
eliminate incorrect line numbers in warnings
This code
1. use warnings; 2. my $undef; 3. 4. if ($undef == 3) { 5. } elsif ($undef == 0) { 6. }
used to produce this output:
Use of uninitialized value in numeric eq (==) at wrong.pl line 4. Use of uninitialized value in numeric eq (==) at wrong.pl line 4.
where the line of the second warning was misreported - it should be line 5. Rafael fixed this - the problem arose because there was no nextstate OP between the execution of the if and the
elsif
, hencePL_curcop
still reports that the currently executing line is line 4. The solution was to inject a nextstate OPs for eachelsif
, although it turned out that the nextstate OP needed to be a nulled OP, rather than a live nextstate OP, else other line numbers became misreported. (Jenga!)The problem is more general than
elsif
(although theelsif
case is the most common and the most confusing). Ideally this code1. use warnings; 2. my $undef; 3. 4. my $a = $undef + 1; 5. my $b 6. = $undef 7. + 1;
would produce this output
Use of uninitialized value $undef in addition (+) at wrong.pl line 4. Use of uninitialized value $undef in addition (+) at wrong.pl line 7.
(rather than lines 4 and 5), but this would seem to require every OP to carry (at least) line number information.
What might work is to have an optional line number in memory just before the BASEOP structure, with a flag bit in the op to say whether it's present. Initially during compile every OP would carry its line number. Then add a late pass to the optimiser (potentially combined with repack the optree) which looks at the two ops on every edge of the graph of the execution path. If the line number changes, flags the destination OP with this information. Once all paths are traced, replace every op with the flag with a nextstate-light op (that just updates
PL_curcop
), which in turn then passes control on to the true op. All ops would then be replaced by variants that do not store the line number. (Which, logically, why it would work best in conjunction with repack the optree, as that is already copying/reallocating all the OPs)(Although I should note that we're not certain that doing this for the general case is worth it)
Here is the actual commit. Given that the commit happened in April 2008, I am assuming the fix was included in the 5.8.9 release (see perlhist).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With