#!/usr/bin/perl # # Reads a log file, containing lines of the four types # malloc() returns # strdup() returns # calloc(*) returns # realloc(,) returns # free() # # with optional line on the front saying # null pointer is # # and produces a list of free()s and realloc()s of wrong pointers, # and also of malloc()s, calloc()s and realloc()s that never get free()d. $errors=0; while (<>) { $in=$out=""; ($file, $line, $call, $in, $out)=($1,$2,$3,"",$4) if /^(\S+) (\S+) (malloc|strdup)\(\S+\) returns (\S+)$/; ($file, $line, $call, $in, $out)=($1,$2,"calloc","",$5) if /^(\S+) (\S+) calloc\(\S+\*\S+\) returns (\S+)$/; ($file, $line, $call, $in, $out)=($1,$2,"realloc",$3,$4) if /^(\S+) (\S+) realloc\((\S+),\S+\) returns (\S+)$/; ($file, $line, $call, $in, $out)=($1,$2,"free",$3,"") if /^(\S+) (\S+) free\((\S+)\)$/; $null = $1, next if /^null pointer is (\S+)$/; if ($in ne "") { if (&null($in)) { $bad = "null pointer"; } elsif (defined $lastalloc{$in}) { $bad = "already-freed pointer (last alloc $lastalloc{$in}, last free $lastfree{$in})"; } else { $bad = "bad pointer"; } $errors=1, print "($.) $file:$line: $call() $bad\n" if $record{$in} eq ""; $lastfree{$in}="($.) $file:$line"; $record{$in}=""; } if ($out ne "" && !&null($out)) { $errors=1, print "($.) $file:$line: $call() returned already ". "allocated pointer\n" if $record{$out} ne ""; $record{$out}="($.) $file:$line: $call()"; $lastalloc{$out}="($.) $file:$line"; } } foreach $i (keys %record) { $errors=1, print "$record{$i} never got freed\n" if $record{$i} ne ""; } print "no problems\n" if !$errors; # determine if a string refers to a null pointer sub null { local ($_) = @_; $null ? $_ eq $null : /^((0x)?0+|\(nil\))$/; }