2012-01-05 9 views
10

वेलग्रिंड एक उत्कृष्ट स्मृति डिबगर है, और यह विकल्प --trace-malloc=yes, जो कुछ इस तरह का उत्पादन किया है:व्याख्या वेलग्रिंड के निशान-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 

वहाँ एक उपकरण है कि इस उत्पादन को पार्स करता है और प्रत्येक पते के लिए मुझसे कहता है क्या यह एक मिलान करने वाली जोड़ी में सही ढंग से आवंटित और मुक्त नहीं किया गया है?

जीसीसी के पास mtrace() फ़ंक्शन और mtrace कमांड-लाइन टूल के साथ कुछ समान है, लेकिन प्रारूप अलग है।

बोनस प्रश्न: क्या "निश्चित रूप से खोए गए" कथन के बगल में वास्तविक पता आउटपुट करना संभव है?

(मैं सबसे अधिक संभावना दो भाषाओं के लिए इस 'सी' और 'सी ++ "टैगिंग कर रहा हूँ वेलग्रिंड के साथ प्रयोग किया जा करने के लिए।)

उत्तर

1

कल की समाधान के लिए इस्तेमाल किया उत्पादन विश्लेषण करने के लिए पर्ल जाहिर है, एक सी ++ जनसंपर्क किया जा रहा है ogrammer मुझे इसे C++ में करना है। मैंने पहले std::regex का उपयोग नहीं किया था और इस बारे में कुछ सीखने की आवश्यकता है। तो यहाँ एक सी ++ समाधान है:

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

क्योंकि ऐसा लगता है कि जीसीसी के std::regex के वर्तमान संस्करण गाड़ी है मैं बूस्ट से कार्यान्वयन का इस्तेमाल किया। संस्करण को स्विच करना आसान होना चाहिए: boost के बजाय std के लिए उपनाम होने के लिए बस re को उपनाम दें।

3

उत्पादन एक आंशिक उत्पादन हो रहा है (या इसे घोर रूप से टूटी हुई कोड से है हालांकि, यह पते से मेल खाने वाली एक सरल पर्ल स्क्रिप्ट के लिए एक नौकरी प्रतीत होता है। दरअसल, सी ++ 2011 के नियमित अभिव्यक्तियों के साथ भी सी ++ कार्य तक होना चाहिए लेकिन मैंने इनका उपयोग नहीं किया है, फिर भी, यहां, यहां है एक सरल (हालांकि शायद नहीं बल्कि अनाड़ी) पर्ल स्क्रिप्ट मानक इनपुट से valgrind के उत्पादन पढ़ने:।

#!/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' की विभिन्न संभावनाओं के लिए खाता है? यह या तो एक सीधा नया 'मॉलोक' हो सकता है, या यह एक मौजूदा पते को चारों ओर स्थानांतरित कर सकता है। (इसके अलावा, 'मुक्त (0) 'नकली नहीं है :-)।) –

+0

एक कीट होने के लिए खेद है: क्या आप इसे अंतिम लीक राशि जोड़ सकते हैं? मैं इसे Valgrind की अपनी रिपोर्ट से तुलना करना चाहता हूं। वास्तव में –

1

मैं पार्टी के लिए थोड़ा देर हो चुकी हूं, लेकिन दूसरे जवाब ने याद में खाता नहीं लिया। Valloc, cfree या posix_memalign जैसे अन्य फ़ंक्शन हैं लेकिन कम से कम लिनक्स पर वे अलियाज़ हैं। वैसे भी यहां मेरा अजगर संस्करण है, कोई गारंटी नहीं है।

#!/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()) 
संबंधित मुद्दे