2012-01-05 1 views
10

Valgrind의 우수한 메모리 디버거 해석하고,이 같은 생산 옵션 --trace-malloc=yes있다 :Valgrind의의 추적 - malloc에 ​​출력

--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 

이 출력을 구문 분석하고 각 주소를 알려줍니다 도구가됩니다 일치하는 쌍으로 올바르게 할당되고 해제되지 않았습니까?

GCC는 mtrace() 함수와 mtrace 명령 줄 도구와 비슷하지만 형식이 다릅니다.

보너스 질문 : "확실하게 잃어버린"진술 옆에 실제 주소를 출력 할 수 있습니까?

출력은 부분적인 출력 될 것으로 보인다

답변

1

어제의 솔루션을 사용 펄은 C++ 홍보되는 :. (비록 아마 오히려 서투른) 펄 스크립트 표준 입력에서 Valgrind의의 출력을 읽는 간단한 ogrammer 나는 C++로 그것을하기로되어있다. 나는 전에 std::regex을 사용하지 않았으며 이것에 대해 조금 배우는 것이 필요하다. 이 std::regex의 GCC의 현재 버전의 버그가 내가 부스트에서 구현을 사용하는 것 같다 때문에

#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"; 
    } 
} 

: 그래서 여기에 C++ 솔루션입니다. 버전을 쉽게 전환 할 수 있습니다. reboost 대신 std의 별칭으로 정의하십시오.

3

(내가 가장 가능성이 두 언어이 "C"와 "C++를"태그거야가. Valgrind의와 함께 사용되는) (또는 그것을 무시 무시하게 깨진 코드에서이다 C++ 2011의 정규 표현식을 사용해도 C++이 작업을 수행해야하지만 아직 사용하지는 않았습니다. , 분명히 출력을 분석하는

#!/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

예, 가능한 출력을 보여주는 예입니다. 스크립트를 시험해 봅시다 - 고마워요! 오, 패턴에 맞지 않는 모든 선을 무시하도록 만들 수 있습니까? –

+0

아주 좋습니다. 하나의 질문 : 이것은 'realloc'의 다양한 가능성을 설명합니까? 똑바로 새로운'malloc '일 수도 있고, 기존 주소를 이동할 수도 있습니다. (또한'free (0)'은 허위가 아닙니다 :-). –

+0

해충이 될 수있어서 유감입니다. 최종 유출 액을 더할 수 있습니까? Valgrind의 보고서와 비교하고 싶습니다. –

1

나는 파티에 약간 늦었지만 다른 대답은 memalign을 고려하지 않았습니다. valloc, cfree 또는 posix_memalign과 같은 다른 기능이 있지만 최소한 Linux에서는 별칭이 지정됩니다. 어쨌든 여기 내 파이썬 버전입니다.

#!/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())