CatCoding

valgrind

2011-05-06

纪念一下跑测试跑了几天才找出的一个内存泄漏,这个函数源于 UNP,还以为 UNP 有 bug 呢,找到原书当 getaddreinfo 失败或者 res==NULL 的时候直接退出了。但是写这个代码的同学当然不想连接不上直接退出,于是忘记了 freeaddrinfo 调用直接返回,那个 struct addrinfo 就没释放。很多错误都是这种,涉及到库函数的时候更加难查。

int tcp_connect(const char host, const char serv){
    int    sockfd, n;
    struct addrinfo hints, res, ressave;

    bzero(&hints, sizeof(struct addrinfo));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;

    if ( (n = getaddrinfo(host, serv, &hints, &res)) != 0)
    {
        log_sprintf(“tcp_connect error for %s, %s: %s”, host, serv, gai_strerror(n));
        freeaddrinfo(res); //oops: memory leak

        return -1;
    }
    ressave = res;

    do {
        sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
        if (sockfd < 0)
                continue;       / ignore this one /
        if (connect(sockfd, res->ai_addr, res->ai_addrlen) == 0)
                break;          / success /
        close(sockfd);  / ignore this one /

    } while ( (res = res->ai_next) != NULL);

    if (res == NULL)        / errno set from final connect() /
    {
        log_sprintf(“tcp_connect error for %s, %s”, host, serv);
        freeaddrinfo(ressave); //oops: memory leak
        return -1;
    }
    freeaddrinfo(ressave);
    return(sockfd);
}

上一篇博文中说到自己包装的内存检测方法,这还有个问题当时没发现,就是那个包装 malloc 之类的方法对于库函数中的内存申请调用没法记录,所以是不会发现上面这个 bug 的。这个 Memwatch 倒是把原生的 malloc 都重定义了,但是最好的 Linux 下检测内存泄漏的工具还是 valgrind,这真是个神器,在代码上不用做一点修改,这东西甚至能测试程序的 cache 命中率。看了一下 valgrind 的相关论文,对于检测方法都是一种称之为 shadow value 的方法,也就是用信息来记录每一个 byte 内存的使用情况。这种方式的一个缺点都是会拖慢速度,前面提到的那种稍微包装了一下的方式可能还好 (因为使用的是静态数组), Memwatch 里面使用了不少链表也会拖慢速度。再看看 valgrind 的实现,以后工作可能会碰上类似的。

更多 valgrind

更多 Memwatch

公号同步更新,欢迎关注👻
Tags: Tools