Annotation of embedaddon/curl/tests/memanalyze.pl, revision 1.1

1.1     ! misho       1: #!/usr/bin/env perl
        !             2: #***************************************************************************
        !             3: #                                  _   _ ____  _
        !             4: #  Project                     ___| | | |  _ \| |
        !             5: #                             / __| | | | |_) | |
        !             6: #                            | (__| |_| |  _ <| |___
        !             7: #                             \___|\___/|_| \_\_____|
        !             8: #
        !             9: # Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
        !            10: #
        !            11: # This software is licensed as described in the file COPYING, which
        !            12: # you should have received as part of this distribution. The terms
        !            13: # are also available at https://curl.haxx.se/docs/copyright.html.
        !            14: #
        !            15: # You may opt to use, copy, modify, merge, publish, distribute and/or sell
        !            16: # copies of the Software, and permit persons to whom the Software is
        !            17: # furnished to do so, under the terms of the COPYING file.
        !            18: #
        !            19: # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
        !            20: # KIND, either express or implied.
        !            21: #
        !            22: ###########################################################################
        !            23: #
        !            24: # Example input:
        !            25: #
        !            26: # MEM mprintf.c:1094 malloc(32) = e5718
        !            27: # MEM mprintf.c:1103 realloc(e5718, 64) = e6118
        !            28: # MEM sendf.c:232 free(f6520)
        !            29: 
        !            30: my $mallocs=0;
        !            31: my $callocs=0;
        !            32: my $reallocs=0;
        !            33: my $strdups=0;
        !            34: my $wcsdups=0;
        !            35: my $showlimit;
        !            36: my $sends=0;
        !            37: my $recvs=0;
        !            38: my $sockets=0;
        !            39: 
        !            40: while(1) {
        !            41:     if($ARGV[0] eq "-v") {
        !            42:         $verbose=1;
        !            43:         shift @ARGV;
        !            44:     }
        !            45:     elsif($ARGV[0] eq "-t") {
        !            46:         $trace=1;
        !            47:         shift @ARGV;
        !            48:     }
        !            49:     elsif($ARGV[0] eq "-l") {
        !            50:         # only show what alloc that caused a memlimit failure
        !            51:         $showlimit=1;
        !            52:         shift @ARGV;
        !            53:     }
        !            54:     else {
        !            55:         last;
        !            56:     }
        !            57: }
        !            58: 
        !            59: my $maxmem;
        !            60: 
        !            61: sub newtotal {
        !            62:     my ($newtot)=@_;
        !            63:     # count a max here
        !            64: 
        !            65:     if($newtot > $maxmem) {
        !            66:         $maxmem= $newtot;
        !            67:     }
        !            68: }
        !            69: 
        !            70: my $file = $ARGV[0];
        !            71: 
        !            72: if(! -f $file) {
        !            73:     print "Usage: memanalyze.pl [options] <dump file>\n",
        !            74:     "Options:\n",
        !            75:     " -l  memlimit failure displayed\n",
        !            76:     " -v  Verbose\n",
        !            77:     " -t  Trace\n";
        !            78:     exit;
        !            79: }
        !            80: 
        !            81: open(FILE, "<$file");
        !            82: 
        !            83: if($showlimit) {
        !            84:     while(<FILE>) {
        !            85:         if(/^LIMIT.*memlimit$/) {
        !            86:             print $_;
        !            87:             last;
        !            88:         }
        !            89:     }
        !            90:     close(FILE);
        !            91:     exit;
        !            92: }
        !            93: 
        !            94: 
        !            95: my $lnum=0;
        !            96: while(<FILE>) {
        !            97:     chomp $_;
        !            98:     $line = $_;
        !            99:     $lnum++;
        !           100:     if($line =~ /^LIMIT ([^ ]*):(\d*) (.*)/) {
        !           101:         # new memory limit test prefix
        !           102:         my $i = $3;
        !           103:         my ($source, $linenum) = ($1, $2);
        !           104:         if($trace && ($i =~ /([^ ]*) reached memlimit/)) {
        !           105:             print "LIMIT: $1 returned error at $source:$linenum\n";
        !           106:         }
        !           107:     }
        !           108:     elsif($line =~ /^MEM ([^ ]*):(\d*) (.*)/) {
        !           109:         # generic match for the filename+linenumber
        !           110:         $source = $1;
        !           111:         $linenum = $2;
        !           112:         $function = $3;
        !           113: 
        !           114:         if($function =~ /free\((\(nil\)|0x([0-9a-f]*))/) {
        !           115:             $addr = $2;
        !           116:             if($1 eq "(nil)") {
        !           117:                 ; # do nothing when free(NULL)
        !           118:             }
        !           119:             elsif(!exists $sizeataddr{$addr}) {
        !           120:                 print "FREE ERROR: No memory allocated: $line\n";
        !           121:             }
        !           122:             elsif(-1 == $sizeataddr{$addr}) {
        !           123:                 print "FREE ERROR: Memory freed twice: $line\n";
        !           124:                 print "FREE ERROR: Previously freed at: ".$getmem{$addr}."\n";
        !           125:             }
        !           126:             else {
        !           127:                 $totalmem -= $sizeataddr{$addr};
        !           128:                 if($trace) {
        !           129:                     print "FREE: malloc at ".$getmem{$addr}." is freed again at $source:$linenum\n";
        !           130:                     printf("FREE: %d bytes freed, left allocated: $totalmem bytes\n", $sizeataddr{$addr});
        !           131:                 }
        !           132: 
        !           133:                 newtotal($totalmem);
        !           134:                 $frees++;
        !           135: 
        !           136:                 $sizeataddr{$addr}=-1; # set -1 to mark as freed
        !           137:                 $getmem{$addr}="$source:$linenum";
        !           138: 
        !           139:             }
        !           140:         }
        !           141:         elsif($function =~ /malloc\((\d*)\) = 0x([0-9a-f]*)/) {
        !           142:             $size = $1;
        !           143:             $addr = $2;
        !           144: 
        !           145:             if($sizeataddr{$addr}>0) {
        !           146:                 # this means weeeeeirdo
        !           147:                 print "Mixed debug compile ($source:$linenum at line $lnum), rebuild curl now\n";
        !           148:                 print "We think $sizeataddr{$addr} bytes are already allocated at that memory address: $addr!\n";
        !           149:             }
        !           150: 
        !           151:             $sizeataddr{$addr}=$size;
        !           152:             $totalmem += $size;
        !           153: 
        !           154:             if($trace) {
        !           155:                 print "MALLOC: malloc($size) at $source:$linenum",
        !           156:                 " makes totally $totalmem bytes\n";
        !           157:             }
        !           158: 
        !           159:             newtotal($totalmem);
        !           160:             $mallocs++;
        !           161: 
        !           162:             $getmem{$addr}="$source:$linenum";
        !           163:         }
        !           164:         elsif($function =~ /calloc\((\d*),(\d*)\) = 0x([0-9a-f]*)/) {
        !           165:             $size = $1*$2;
        !           166:             $addr = $3;
        !           167: 
        !           168:             $arg1 = $1;
        !           169:             $arg2 = $2;
        !           170: 
        !           171:             if($sizeataddr{$addr}>0) {
        !           172:                 # this means weeeeeirdo
        !           173:                 print "Mixed debug compile, rebuild curl now\n";
        !           174:             }
        !           175: 
        !           176:             $sizeataddr{$addr}=$size;
        !           177:             $totalmem += $size;
        !           178: 
        !           179:             if($trace) {
        !           180:                 print "CALLOC: calloc($arg1,$arg2) at $source:$linenum",
        !           181:                 " makes totally $totalmem bytes\n";
        !           182:             }
        !           183: 
        !           184:             newtotal($totalmem);
        !           185:             $callocs++;
        !           186: 
        !           187:             $getmem{$addr}="$source:$linenum";
        !           188:         }
        !           189:         elsif($function =~ /realloc\((\(nil\)|0x([0-9a-f]*)), (\d*)\) = 0x([0-9a-f]*)/) {
        !           190:             my ($oldaddr, $newsize, $newaddr) = ($2, $3, $4);
        !           191: 
        !           192:             $totalmem -= $sizeataddr{$oldaddr};
        !           193:             if($trace) {
        !           194:                 printf("REALLOC: %d less bytes and ", $sizeataddr{$oldaddr});
        !           195:             }
        !           196:             $sizeataddr{$oldaddr}=0;
        !           197: 
        !           198:             $totalmem += $newsize;
        !           199:             $sizeataddr{$newaddr}=$newsize;
        !           200: 
        !           201:             if($trace) {
        !           202:                 printf("%d more bytes ($source:$linenum)\n", $newsize);
        !           203:             }
        !           204: 
        !           205:             newtotal($totalmem);
        !           206:             $reallocs++;
        !           207: 
        !           208:             $getmem{$oldaddr}="";
        !           209:             $getmem{$newaddr}="$source:$linenum";
        !           210:         }
        !           211:         elsif($function =~ /strdup\(0x([0-9a-f]*)\) \((\d*)\) = 0x([0-9a-f]*)/) {
        !           212:             # strdup(a5b50) (8) = df7c0
        !           213: 
        !           214:             $dup = $1;
        !           215:             $size = $2;
        !           216:             $addr = $3;
        !           217:             $getmem{$addr}="$source:$linenum";
        !           218:             $sizeataddr{$addr}=$size;
        !           219: 
        !           220:             $totalmem += $size;
        !           221: 
        !           222:             if($trace) {
        !           223:                 printf("STRDUP: $size bytes at %s, makes totally: %d bytes\n",
        !           224:                        $getmem{$addr}, $totalmem);
        !           225:             }
        !           226: 
        !           227:             newtotal($totalmem);
        !           228:             $strdups++;
        !           229:         }
        !           230:         elsif($function =~ /wcsdup\(0x([0-9a-f]*)\) \((\d*)\) = 0x([0-9a-f]*)/) {
        !           231:             # wcsdup(a5b50) (8) = df7c0
        !           232: 
        !           233:             $dup = $1;
        !           234:             $size = $2;
        !           235:             $addr = $3;
        !           236:             $getmem{$addr}="$source:$linenum";
        !           237:             $sizeataddr{$addr}=$size;
        !           238: 
        !           239:             $totalmem += $size;
        !           240: 
        !           241:             if($trace) {
        !           242:                 printf("WCSDUP: $size bytes at %s, makes totally: %d bytes\n",
        !           243:                        $getmem{$addr}, $totalmem);
        !           244:             }
        !           245: 
        !           246:             newtotal($totalmem);
        !           247:             $wcsdups++;
        !           248:         }
        !           249:         else {
        !           250:             print "Not recognized input line: $function\n";
        !           251:         }
        !           252:     }
        !           253:     # FD url.c:1282 socket() = 5
        !           254:     elsif($_ =~ /^FD ([^ ]*):(\d*) (.*)/) {
        !           255:         # generic match for the filename+linenumber
        !           256:         $source = $1;
        !           257:         $linenum = $2;
        !           258:         $function = $3;
        !           259: 
        !           260:         if($function =~ /socket\(\) = (\d*)/) {
        !           261:             $filedes{$1}=1;
        !           262:             $getfile{$1}="$source:$linenum";
        !           263:             $openfile++;
        !           264:             $sockets++; # number of socket() calls
        !           265:         }
        !           266:         elsif($function =~ /socketpair\(\) = (\d*) (\d*)/) {
        !           267:             $filedes{$1}=1;
        !           268:             $getfile{$1}="$source:$linenum";
        !           269:             $openfile++;
        !           270:             $filedes{$2}=1;
        !           271:             $getfile{$2}="$source:$linenum";
        !           272:             $openfile++;
        !           273:         }
        !           274:         elsif($function =~ /accept\(\) = (\d*)/) {
        !           275:             $filedes{$1}=1;
        !           276:             $getfile{$1}="$source:$linenum";
        !           277:             $openfile++;
        !           278:         }
        !           279:         elsif($function =~ /sclose\((\d*)\)/) {
        !           280:             if($filedes{$1} != 1) {
        !           281:                 print "Close without open: $line\n";
        !           282:             }
        !           283:             else {
        !           284:                 $filedes{$1}=0; # closed now
        !           285:                 $openfile--;
        !           286:             }
        !           287:         }
        !           288:     }
        !           289:     # FILE url.c:1282 fopen("blabla") = 0x5ddd
        !           290:     elsif($_ =~ /^FILE ([^ ]*):(\d*) (.*)/) {
        !           291:         # generic match for the filename+linenumber
        !           292:         $source = $1;
        !           293:         $linenum = $2;
        !           294:         $function = $3;
        !           295: 
        !           296:         if($function =~ /f[d]*open\(\"(.*)\",\"([^\"]*)\"\) = (\(nil\)|0x([0-9a-f]*))/) {
        !           297:             if($3 eq "(nil)") {
        !           298:                 ;
        !           299:             }
        !           300:             else {
        !           301:                 $fopen{$4}=1;
        !           302:                 $fopenfile{$4}="$source:$linenum";
        !           303:                 $fopens++;
        !           304:             }
        !           305:         }
        !           306:         # fclose(0x1026c8)
        !           307:         elsif($function =~ /fclose\(0x([0-9a-f]*)\)/) {
        !           308:             if(!$fopen{$1}) {
        !           309:                 print "fclose() without fopen(): $line\n";
        !           310:             }
        !           311:             else {
        !           312:                 $fopen{$1}=0;
        !           313:                 $fopens--;
        !           314:             }
        !           315:         }
        !           316:     }
        !           317:     # GETNAME url.c:1901 getnameinfo()
        !           318:     elsif($_ =~ /^GETNAME ([^ ]*):(\d*) (.*)/) {
        !           319:         # not much to do
        !           320:     }
        !           321:     # SEND url.c:1901 send(83) = 83
        !           322:     elsif($_ =~ /^SEND ([^ ]*):(\d*) (.*)/) {
        !           323:         $sends++;
        !           324:     }
        !           325:     # RECV url.c:1901 recv(102400) = 256
        !           326:     elsif($_ =~ /^RECV ([^ ]*):(\d*) (.*)/) {
        !           327:         $recvs++;
        !           328:     }
        !           329: 
        !           330:     # ADDR url.c:1282 getaddrinfo() = 0x5ddd
        !           331:     elsif($_ =~ /^ADDR ([^ ]*):(\d*) (.*)/) {
        !           332:         # generic match for the filename+linenumber
        !           333:         $source = $1;
        !           334:         $linenum = $2;
        !           335:         $function = $3;
        !           336: 
        !           337:         if($function =~ /getaddrinfo\(\) = (\(nil\)|0x([0-9a-f]*))/) {
        !           338:             my $add = $2;
        !           339:             if($add eq "(nil)") {
        !           340:                 ;
        !           341:             }
        !           342:             else {
        !           343:                 $addrinfo{$add}=1;
        !           344:                 $addrinfofile{$add}="$source:$linenum";
        !           345:                 $addrinfos++;
        !           346:             }
        !           347:             if($trace) {
        !           348:                 printf("GETADDRINFO ($source:$linenum)\n");
        !           349:             }
        !           350:         }
        !           351:         # fclose(0x1026c8)
        !           352:         elsif($function =~ /freeaddrinfo\(0x([0-9a-f]*)\)/) {
        !           353:             if(!$addrinfo{$1}) {
        !           354:                 print "freeaddrinfo() without getaddrinfo(): $line\n";
        !           355:             }
        !           356:             else {
        !           357:                 $addrinfo{$1}=0;
        !           358:                 $addrinfos--;
        !           359:             }
        !           360:             if($trace) {
        !           361:                 printf("FREEADDRINFO ($source:$linenum)\n");
        !           362:             }
        !           363:         }
        !           364: 
        !           365:     }
        !           366:     else {
        !           367:         print "Not recognized prefix line: $line\n";
        !           368:     }
        !           369: }
        !           370: close(FILE);
        !           371: 
        !           372: if($totalmem) {
        !           373:     print "Leak detected: memory still allocated: $totalmem bytes\n";
        !           374: 
        !           375:     for(keys %sizeataddr) {
        !           376:         $addr = $_;
        !           377:         $size = $sizeataddr{$addr};
        !           378:         if($size > 0) {
        !           379:             print "At $addr, there's $size bytes.\n";
        !           380:             print " allocated by ".$getmem{$addr}."\n";
        !           381:         }
        !           382:     }
        !           383: }
        !           384: 
        !           385: if($openfile) {
        !           386:     for(keys %filedes) {
        !           387:         if($filedes{$_} == 1) {
        !           388:             print "Open file descriptor created at ".$getfile{$_}."\n";
        !           389:         }
        !           390:     }
        !           391: }
        !           392: 
        !           393: if($fopens) {
        !           394:     print "Open FILE handles left at:\n";
        !           395:     for(keys %fopen) {
        !           396:         if($fopen{$_} == 1) {
        !           397:             print "fopen() called at ".$fopenfile{$_}."\n";
        !           398:         }
        !           399:     }
        !           400: }
        !           401: 
        !           402: if($addrinfos) {
        !           403:     print "IPv6-style name resolve data left at:\n";
        !           404:     for(keys %addrinfofile) {
        !           405:         if($addrinfo{$_} == 1) {
        !           406:             print "getaddrinfo() called at ".$addrinfofile{$_}."\n";
        !           407:         }
        !           408:     }
        !           409: }
        !           410: 
        !           411: if($verbose) {
        !           412:     print "Mallocs: $mallocs\n",
        !           413:         "Reallocs: $reallocs\n",
        !           414:         "Callocs: $callocs\n",
        !           415:         "Strdups:  $strdups\n",
        !           416:         "Wcsdups:  $wcsdups\n",
        !           417:         "Frees: $frees\n",
        !           418:         "Sends: $sends\n",
        !           419:         "Recvs: $recvs\n",
        !           420:         "Sockets: $sockets\n",
        !           421:         "Allocations: ".($mallocs + $callocs + $reallocs + $strdups + $wcsdups)."\n",
        !           422:         "Operations: ".($mallocs + $callocs + $reallocs + $strdups + $wcsdups + $sends + $recvs + $sockets)."\n";
        !           423: 
        !           424:     print "Maximum allocated: $maxmem\n";
        !           425: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>