2012-01-05 20 views
10

Valgrind mükemmel bir hafıza ayıklama aracıdır yorumlayın ve böyle bir şey üretir seçeneği --trace-malloc=yes sahiptir:Valgrind en iz-malloc çıkış

--16301-- malloc(8) = 0x4EAD748 
--16301-- free(0x4EAD748) 
--16301-- free(0x4EAD498) 
--16301-- malloc(21) = 0x4EAD780 
--16301-- malloc(8) = 0x4EAD838 
--16301-- free(0x4EAD6F8) 
--16301-- calloc(1,88) = 0x4EAD870 
--16301-- realloc(0x0,160)malloc(160) = 0x4EB1CF8 
--16301-- realloc(0x4EB9F28,4) = 0x4EBA060 

bu çıktıyı ayrıştırır ve her adres için bana söyler bir araç var mı Eşleşen bir çiftte doğru şekilde tahsis edilip serbest bırakılmadı mı?

GCC, mtrace() işlevi ve mtrace komut satırı aracıyla benzer bir etkiye sahiptir, ancak biçim farklıdır.

Bonus soru: "Kesinlikle kayıp" ifadesinin yanındaki gerçek adresi çıktılamak mümkün mü?

çıkışı kısmi çıkış gibi görünüyor

cevap

1

Dünün çözümü kullanılan perl, C++ pr olmak:. (her ne kadar muhtemelen oldukça hantal) perl komut standart girdiden Valgrind çıkışını okurken basit ogrammer C++ 'da yapmam gerekiyor. Daha önce std::regex kullanmamıştım ve önce bunun hakkında biraz bilgi edinmem gerekiyordu. o std::regex ait gcc en güncel sürümü aracı işte ben Boost gelen uygulanmasını kullanılan görünüyor Çünkü

#include "boost/regex.hpp" 
#include <functional> 
#include <iostream> 
#include <iterator> 
#include <map> 
#include <stdexcept> 
#include <string> 
#include <vector> 

namespace re = boost; 

long to_long(std::string const& s) 
{ 
    return strtol(s.c_str(), 0, 10); 
} 

template <typename T> 
static void insert(T& map, std::string const& address, std::string const& call, size_t size) 
{ 
    if (!map.insert(std::make_pair(address, std::make_pair(call, size))).second) 
     std::cout << "WARNING: duplicate address for " << call << ": " << address << "\n"; 
} 

template <typename T> 
static void erase(T& map, std::string const& address, std::string const& call) 
{ 
    auto it(map.find(address)); 
    if (it == map.end() && address != "0x0") 
     std::cout << "WARNING: spurious address in " << call << "\n"; 
    else 
     map.erase(it); 
} 

static void process(std::istream& in) 
{ 
    std::map<std::string, std::pair<std::string, size_t>> m; 

    std::vector<std::pair<re::regex, std::function<void(re::smatch&)>>> exps; 
    exps.emplace_back(re::regex(".*(malloc\\((.*)\\)) = (.*)"), [&](re::smatch& results){ 
      ::insert(m, results[3], results[1], ::to_long(results[2])); 
     }); 
    exps.emplace_back(re::regex(".*(free\\((.*)\\))"), [&](re::smatch& results){ 
      ::erase(m, results[2], results[1]); 
     }); 
    exps.emplace_back(re::regex(".*(calloc\\((.*),(.*)\\)) = (.*)"), [&](re::smatch& results){ 
      ::insert(m, results[4], results[1], ::to_long(results[2]) * ::to_long(results[3])); 
     }); 
    exps.emplace_back(re::regex(".*(realloc\\((.*),(.*)\\)) = (.*)"), [&](re::smatch& results){ 
      ::erase(m, results[2], results[1]); 
      ::insert(m, results[4], results[1], ::to_long(results[3])); 
     }); 

    for (std::string line; std::getline(in, line);) 
    { 
     re::smatch results; 
     for (auto it(exps.begin()), end(exps.end()); it != end; ++it) 
     { 
      if (re::regex_match(line, results, it->first)) 
      { 
       (it->second)(results); 
       break; 
      } 
     } 
    } 

    size_t total{0}; 
    for (auto it(m.begin()), end(m.end()); it != end; ++it) 
    { 
     std::cout << "leaked memory at " << it->first << " " << "from " << it->second.first << "\n"; 
     total += it->second.second; 
    } 
    std::cout << "total leak: " << total << "\n"; 
} 

int main(int, char*[]) 
{ 
    try 
    { 
     ::process(std::cin); 
    } 
    catch (std::exception const &ex) 
    { 
     std::cerr << "ERROR: " << ex.what() << "\n"; 
    } 
} 

: Yani burada bir C++ çözümdür. Versiyonu değiştirmek kolay olmalı: 'u boost yerine std için bir takma ad olarak tanımlayın.

3

(Ben büyük olasılıkla iki dil için bu "C" ve "C++" etiketleme ediyorum. Valgrind ile kullanılmak üzere) (ya da iğrenç kırık koddan olduğunu Ancak, bu, adresi eşleştiren basit bir perl betiği için bir iş gibi gözüküyor, aslında, C++ 2011'in normal ifadeleriyle, C++ bile görevde kalmalı, ama bunları kullanmamıştım. Açıkçası çıkışını analiz etmek

#!/usr/bin/perl -w 
use strict; 

my %allocated; 

while (<>) 
    { 
    chomp; 
    if (/(realloc\(([^,]*),([^)]*)\)).* = (.*)/) 
     { 
     if ($2 ne "0x0") 
      { 
      if (!exists $allocated{$2}) 
       { 
       print "spurious realloc($2, $3) = $4\n"; 
       } 
      else 
       { 
       delete $allocated{$2}; 
       } 
      } 
     $allocated{$4} = "$1$;$3"; 
     } 
    elsif (/(malloc\((.*)\)) = (.*)/) 
     { 
     $allocated{$3} = "$1$;$2"; 
     } 
    elsif (/ free\((.*)\)/) 
     { 
     if ($1 ne "0x0") 
      { 
      if (!exists $allocated{$1}) 
       { 
       print "spurious free($1)\n"; 
       } 
      else 
       { 
       delete $allocated{$1}; 
       } 
      } 
     } 
    elsif (/(calloc\((.*),(.*)\)) = (.*)/) 
     { 
     $allocated{$4} = "$1$;" . ($2 * $3); 
     } 
    } 

my $total = 0; 
foreach my $leak (keys %allocated) 
    { 
    my($call, $size) = split(/$;/, $allocated{$leak}); 
    print "leak: address=$leak source=$call size=$size\n"; 
    $total += $size; 
    } 

if (0 < $total) 
    { 
    print "total leak=$total\n"; 
    } 
+0

Evet, çıktı olası satırları göstermek için bir örnektir! Senaryoyu deneyeyim - teşekkürler! Oh, kalıba uymayan tüm satırları görmezden gelebilir misin? –

+0

Çok hoş. Bir soru: Bu, 'realloc'un çeşitli olasılıkları için mi hesap yapıyor? Düz bir yeni 'malloc' olabilir veya mevcut bir adresi etrafa taşıyabilir. (Ayrıca, özgür (0) 'sahte değil :-).) –

+0

Zararlı olduğum için üzgünüm: Sızdıran son miktarı ekleyebilir misin? Valgrind'in kendi raporuyla karşılaştırmak istiyorum. –

1

Partiye biraz geç kaldım, ama diğer cevaplar not almayı hesaba katmadı. Valloc, cfree veya posix_memalign gibi başka işlevler de vardır, ancak en azından linux'lar takma addır. Her neyse, benim python versiyonum, garanti yok.

#!/usr/bin/python 
import sys, re 

memmap = {} 

for line in sys.stdin: 
    tok = [x for x in re.split(' |\(|\)|,|=|\n', line) if x][1:] 
    if tok and tok[0] in ['malloc', 'calloc', 'memalign', 'realloc', 'free']: 
     addr = int(tok[-1], 16) 
     if tok[0] == 'malloc': 
      memmap[addr] = int(tok[1]) 
     elif tok[0] == 'calloc': 
      memmap[addr] = int(tok[1]) * int(tok[2]) 
     elif tok[0] == 'memalign': 
      memmap[addr] = int(tok[-2]) 
     elif tok[0] == 'realloc': 
      oldaddr = int(tok[1], 16) 
      if oldaddr != 0: 
       del memmap[oldaddr] 
      memmap[addr] = int(tok[2]) 
     elif tok[0] == 'free' and addr != 0: 
      del memmap[addr] 

for k, v in memmap.iteritems(): 
    print 'leak at 0x%x, %d bytes' % (k, v) 
print 'total %d bytes' % sum(memmap.itervalues())