Valgrind是一个优秀的内存调试器,它的选项是–trace-malloc = yes,它产生如下所示的内容:
有没有一个工具来解析这个输出,并告诉我每个地址是否没有正确分配和释放匹配的一对?
GCC与mtrace()函数和mtrace命令行工具类似,但格式不同.
奖金问题:是否可以在“绝对丢失”语句旁边输出实际地址?
(我将这个“C”和“C”标记为最有可能与Valgrind一起使用的两种语言.)
解决方法
昨天的解决方案使用perl来分析输出.显然,作为C程序员,我应该在C中做.我以前没有使用std :: regex,需要先了解一下.所以这里是一个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(),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& 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\\((.*),(.*)\\)) = (.*)"),results[4],::to_long(results[2]) * ::to_long(results[3]));
- });
- exps.emplace_back(re::regex(".*(realloc\\((.*),results[1]);
- ::insert(m,::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";
- }
- }
因为gcc的当前版本的std :: regex似乎是错误的,所以我使用了Boost的实现.应该很容易切换版本:只需将re定义为std的别名,而不是boost.