views:

303

answers:

5

There are two cases where my code won't seg fault:

  1. When I use Smart::Comments in at least one place
  2. run through the debugger.

I've tracked it down to this call:

$action->{breakdown} 
    = join( ' '
          ,  each_pair { 
                my ( $name, $length ) = @_;
                return "x$length" if $name eq 'FILLER';
                push @$field_list_ref, $name;
                return "A$length";

            } @$field_def_ref
    );

where each_pair is defined in another module as:

sub each_pair (&@) { 
    my $block   = shift;
    return unless @_;
    my $caller  = caller();
    my $aref    = qualify( 'a', $caller );
    my $bref    = qualify( 'b', $caller );
    my @results;
    my $pairs   = 0;

    for ( my $index = 0; $index < $#_; $index += 2 ) { 
        $pairs++;
        my @pair                 = @_[$index..($index+1)];
        no strict 'refs';
        local ( $$aref, $$bref ) = @pair;
        push @results, $block->( @pair );
    }
    return wantarray || $pairs != 1 ? @results : shift @results;
}
  • Now I know that I can just replace each_pair with List::MoreUtils::natatime (although I hear that has some bugs), they have just recently allowed this module into our environment, and I'm still interested in why this call is causing a seg fault--or what other perl programmers due to debug seg faults.

I've lost a bit of time on this.


EDIT

I have other modules using this function, some expect to be able to use $a and $b, also it's working elsewhere in the same module, for another list. I can change this invocation of it, I can change it for this file, but changing it for every place that uses it successfully, is probably more changes than I would be allowed to make at this late hour.

+2  A: 

Well, I can't figure out why your each_pair() is doing this:

my $caller  = caller();
my $aref    = qualify( 'a', $caller );
my $bref    = qualify( 'b', $caller );

or this:

    no strict 'refs';
    local ( $$aref, $$bref ) = @pair;

and referencing operations that require you to turn off strict refs seem immediately suspect in a segfaulting situation.

What happens if you disable all that?

chaos
So how would a debugger or more debugging-related code make or break that?
Axeman
Sometimes debugging code moves stuff around so that bugs don't get triggered. That's the nature of the heisenbug. http://catb.org/jargon/html/H/heisenbug.html
chaos
He's trying to make `$a` and `$b` aliases for the pairs (like `sort` does), put them in the caller's namespace for use in the block, and localize them to avoid collisions with any other use of those variables. Disabling `strict 'refs'` just allows the use of symbolic references. I wouldn't normally suspect if of being related to a segfault. However `qualify` (which I'm not familiar with) might, as I suspect there's deep XS magic going on there.
Michael Carman
+3  A: 

I will echo chaos' concern with the each_pair function. What happens if you use the following implementation?

#!/usr/bin/perl

use strict;
use warnings;

use Data::Dumper;

sub each_pair(&@);

my $field_def_ref  = [ qw( FILLER 5 NOTFILLER 6 ) ];
my $field_list_ref;

print join(' ' => each_pair {
    my ($name, $length) = @_;
    return "x$length" if $name eq 'FILLER';
    push @$field_list_ref, $name;
    return "A$length";
} @$field_def_ref ), "\n";

print Dumper $field_list_ref;

sub each_pair( &@ ) {
    my $code = shift;
    my @results;

    for my $i ( 0 .. $#_/2 ) {
        push @results, $code->( shift, shift );
    }

    return @results;
}
__END__
Sinan Ünür
+3  A: 

As to general debugging steps, you could always run the Perl interpreter under gdb. The chances of seeing anything educational aren't necessarily that hot, but I've done it a couple times, and it may have even helped once.

chaos
You need to use gdb and valgrind. Valgrind will make your program die closer to the actual error.
jrockway
+4  A: 

Segmentation faults are exceptionally rare in Perl. I can't recall the last time I encountered one.

Debuggers are intrusive enough that it's not particularly surprising that the code would behave differently there, though its certainly frustrating. Smart::Comments uses source filters which (as we all know) are evil. Poking into the source for Smart::Comments, I see that it uses List::Util which normally uses an XS implementation. It's possible that List::Util is what "fixes" your problem. Try using List::Util directly but not Smart::Comments. That won't solve anything, but it might take the uncertainty of a source filter out of the equation.

Unfortunately, your problem seems to be not with the code itself but with unexpected interactions between different things. You can't really trigger a segfault directly in Perl. The root must be in either perl itself or XS code. If you can reduce it to a small but complete sample others might be able to reproduce and isolate the problem.

Michael Carman
I checked my diff of dumps I took of %INC, List::Util appeared in both lists. Thanks all the same.
Axeman
+2  A: 

Segfaults can come from memory bugs in C written external modules bound with XS.

I recommend running your script in valgrind to spot the error:

valgrind perl ./yourfaultyscript.pl
jeje
Looks interesting, but it doesn't look like it runs on AIX.
Axeman
Yep, linux only I'm afraid.Do you experience the same issue on a linux box?
jeje