Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight
 
PerlMonks  

Binary search the cause of a Segmentation Fault (searching automatically the cause of a segfault)

by spx2 (Chaplain)
on Apr 02, 2013 at 04:29 UTC ( #1026578=perlquestion: print w/ replies, xml ) Need Help??
spx2 has asked for the wisdom of the Perl Monks concerning the following question:

Hello dear monks,

It's been a while, but I'm back :)

I'm working on a C utility which parses log files. The C utility has some segfaults caused by the fact that it needs more safety checks on length of fields and some other things.

So basically I'm trying to iron out the bugs. It segfaults now more and more rarely.

Btw, I'm talking 500mb log gzipped log files, so processing takes some time.

Anyway, so sometimes I have a segfault and I want to find out exactly the log line that caused that segfault, so I wrote something that does binary search.

Everything works well, except I have a hackish way of finding out that it segfaulted. So I came here to ask what's the best way to do that.

So in order to check if one of the halves of the input segfaulted is that I check $? to see if it's 139. This is the value I should get but for a different binary called filter I get 35584 upon SEGFAULT. So what should I check for ? Maybe just $? > 0 ?

So my question is: What return value should I expect upon a segfault ? How do I robustly check if a segmentation fault occured.

tl;dr => How do I robustly and properly check in Perl, for a segfault that occured upon running a child process ?

Let me show you a small C program that I wrote that takes 2 parameters and intentionally segfaults if 30 is in the interval of these 2 parameters:

#include<stdio.h> #include<stdlib.h> /** * * This binary receives 2 numbers, an L and an R * * It will intentionally hit Segmentation Fault(actually SIGSEGV) + whenever 30 is in the interval [L,R] * * It will be used to test the binary search segfault finder * */ int main(int argc, int **argv) { char exists; char *Q[3000]; int i; int L = atoi((char*)argv[1]); int R = atoi((char*)argv[2]); printf("L=%d R=%d",L,R); /*exit(0);*/ for(i=0;i<3000;i++) Q[i] = &exists; Q[30] = NULL; // <==== I want to cause a SIGSEGV through this ! for(i=L;i<=R;i++) { int T = *Q[i]; // <== will segfault when i == 30 because I sai +d so :) }; };

So compile this with gcc f.c

Now you get an `a.out` which you can use below in the script.

Now here's the script which is the binary search that I wrote:

#!/usr/bin/env perl use strict; use warnings; my $segfaulting_file = "s"; my $L = 0; my $R = 7266786; #`cat $segfaulting_file | wc -l`; my $M; my $binary = "./filter"; while ($L < $R) { $M = int(($L+$R)/2); # head argument for right side my $HL = $M; # tail argument for right side my $TL = $M-$L; # head argument for left side my $HR = $R; # tail argument for left side my $TR = $R-$M; print "M=$M L=$L R=$R\n"; my $go_left ; my $go_right; my $cmd_R = "cat $segfaulting_file | head -$HR | tail -$TR | $bi +nary > /dev/null;"; my $cmd_L = "cat $segfaulting_file | head -$HL | tail -$TL | $bi +nary > /dev/null;"; print "\nRunning $cmd_R\n"; `$cmd_R`; #`./a.out $M $R`; print "RETVAL=$?\n"; $go_right = ($? > 30000); # right side caused SEGFAULT `rm core`; print "\nRunning $cmd_L\n"; `$cmd_L`; print "RETVAL=$?\n"; #`./a.out $L $M`; $go_left = ($? > 30000); # left side caused SEGFAULT `rm core`; if( $L == $R ) { last; }elsif ( $go_left ) { print "GO left L=$L R=$R\n"; $R = $M ; }elsif ( $go_right ) { print "GO right L=$L R=$R\n"; $L = $M+1; }; }; # the loop stopped because $L==$R==$M , so we just print out $M print "Segfault caused by line $M\n";

Comment on Binary search the cause of a Segmentation Fault (searching automatically the cause of a segfault)
Select or Download Code
Re: Binary search the cause of a Segmentation Fault
by Athanasius (Monsignor) on Apr 02, 2013 at 04:39 UTC
    How do I robustly and properly check in Perl, for a segfault that occured upon running a child process ?

    From perlvar under “$CHILD_ERROR”:

    Thus, the exit value of the subprocess is really ($? >> 8), and $? & 127 gives which signal, if any, the process died from, and $? & 128 reports whether there was a core dump.

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1026578]
Approved by Athanasius
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others surveying the Monastery: (15)
As of 2014-09-16 14:41 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    How do you remember the number of days in each month?











    Results (31 votes), past polls