perlquestion
spx2
<p>Hello dear monks,</p>
<p>It's been a while, but I'm back :)</p>
<p>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.</p>
<p>So basically I'm trying to iron out the bugs. It segfaults now more and more rarely.</p>
<p>Btw, I'm talking 500mb log gzipped log files, so processing takes some time.</p>
<p>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.</p>
<p>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.</p>
<p>So in order to check if one of the halves of the input segfaulted is that I check <b>$?</b> to see if it's 139. This is the value I should get but for a different binary called <b>filter</b> I get <b>35584</b> upon SEGFAULT. So what should I check for ? Maybe just <b>$?</b> > 0 ?</p>
<p>So my question is: What return value should I expect upon a segfault ? How do I robustly check if a segmentation fault occured.</p>
<p>
<b>tl;dr</b> => How do I robustly and properly check in Perl, for a segfault that occured upon running a child process ?</p>
<p>Let me show you a small C program that I wrote that takes 2 parameters and <b>intentionally</b>
segfaults if <b>30</b> is in the interval of these 2 parameters:</p>
<code>
#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 said so :)
};
};
</code>
<p>So compile this with <code>gcc f.c</code> </p>
<p>Now you get an `a.out` which you can use below in the script.</p>
<p>Now here's the script which is the binary search that I wrote:</p>
<code>
#!/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 | $binary > /dev/null;";
my $cmd_L = "cat $segfaulting_file | head -$HL | tail -$TL | $binary > /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";
</code>