[英]Interpret Valgrind's trace-malloc output
Valgrind is an excellent memory debugger, and it has the option --trace-malloc=yes
, which produces something like this: Valgrind是一个优秀的内存调试器,它有选项--trace-malloc=yes
,它产生如下内容:
--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
Is there a tool that parses this output and tells me for each address whether it's not been correctly allocated and freed in a matching pair? 是否有一个工具可以解析此输出并告诉我每个地址是否未在匹配的对中正确分配和释放?
GCC has something similar with the mtrace()
function and the mtrace
command-line tool, but the format is different. GCC与mtrace()
函数和mtrace
命令行工具类似,但格式不同。
Bonus question: Is it possible to output the actual address next to a "definitely lost" statement? 奖金问题:是否可以输出“绝对丢失”声明旁边的实际地址?
(I'm tagging this "C" and "C++" for the two languages most likely to be used with Valgrind.) (我正在为最有可能与Valgrind一起使用的两种语言标记这个“C”和“C ++”。)
The output seems to be a partial output (or it is from hideously broken code. However, this seems to be a jobby for a simple perl script matching up the address. Actually, with C++2011's regular expressions even C++ should be up to the task but I haven't used these, yet. So, here is a simple (although probably rather clumsy) perl script reading valgrind's output from standard input: 输出似乎是一个部分输出(或者它来自可怕的破解代码。但是,这似乎是一个匹配地址的简单perl脚本的工作。实际上,使用C ++ 2011的正则表达式,即使C ++也应该是但是我还没有使用过这些任务。所以,这里有一个简单的(尽管可能相当笨拙)perl脚本从标准输入读取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";
}
I'm a bit late to the party, but the other answer didn't take memalign into account. 我参加聚会有点晚了,但另一个答案没有考虑到memalign。 There are other functions like valloc, cfree or posix_memalign but at least on linux they are aliased. 还有其他功能,如valloc,cfree或posix_memalign,但至少在linux上它们是别名。 Anyway here is my python version, no guarantees. 无论如何这里是我的python版本,没有保证。
#!/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())
Yesterday's solution used perl to analyze the output. 昨天的解决方案使用perl来分析输出。 Obviously, being a C++ programmer I'm supposed to do it in C++. 显然,作为一名C ++程序员,我应该用C ++来做。 I hadn't used std::regex
before and need to learn a bit about this first. 我以前没有使用过std::regex
,需要先了解一下这个。 So here is a C++ solution: 所以这是一个C ++解决方案:
#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";
}
}
Because it seems that gcc's current version of std::regex
is buggy I used the implementation from Boost. 因为看起来gcc的当前版本的std::regex
是错误的,我使用了Boost的实现。 It should be easy to switch the version: just define re
to be an alias for std
instead of boost
. 切换版本应该很容易:只需将re
定义为std
的别名而不是boost
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.