You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何无内存泄漏地打开和关闭RPM数据库?

问题

我正在使用librpm库编写代码模拟rpm -qa命令,这是一款用于安全分析已安装软件的大型程序的前期实验。目前仅实现了打开和关闭RPM数据库的操作,未进行任何读取。

通过对比我的程序与rpm -qa的valgrind检测结果发现:我的程序存在25,740字节的可能内存泄漏,而rpm -qa无此类泄漏。

我的代码如下:

#include <rpm/rpmdb.h>
#include <rpm/rpmlib.h>
#include <rpm/rpmts.h>

bool openDb(rpmts & ts, rpmdbMatchIterator & mi);
void closeDb(rpmts & ts, rpmdbMatchIterator & mi);

int main()
{
    rpmts ts;
    rpmdbMatchIterator mi;

    if (!openDb(ts, mi)) {
        return 1;
    }

    closeDb(ts, mi);
    return 0;
}

bool openDb(rpmts & ts, rpmdbMatchIterator & mi)
{
    {
        static volatile bool s_bHereBefore = false;
        if (!s_bHereBefore) {
            s_bHereBefore = true;
            rpmReadConfigFiles(NULL, NULL);
        }
    }

    mi = NULL;
    ts = rpmtsCreate();

    if (!ts) {
        printf("RPM open failed\n");
    } else {
        mi = rpmtsInitIterator(ts, (rpmTag)RPMDBI_PACKAGES, NULL, 0);
        if (!mi) {
            printf("RPM iterator failed\n");
            rpmtsFree(ts);
        }
    }

    return mi != NULL;
}

void closeDb(rpmts & ts, rpmdbMatchIterator & mi)
{
    mi = rpmdbFreeIterator(mi);
    if (ts) {
        rpmtsFree(ts);
    }
}

编译命令:

g++ -Wall -Wextra -Wunused -Og -g try_to_fix_mem_leak.cpp -lrpm -o leaky

经valgrind --leak-check=full检测,泄漏点指向rpmReadConfigFiles(NULL, NULL)行,但该函数的librpm 4.16.1版本文档未提及需要释放内存。

请问如何正确打开和关闭RPM数据库,以达到与rpm -qa相近的低内存泄漏水平?

解决方案
  • 调用rpmFreeRpmrc()释放配置资源:rpmReadConfigFiles()会加载rpm全局配置并分配内存,虽然官方文档未明确标注,但rpm -qa内部会在退出前调用rpmFreeRpmrc()清理这部分资源,这正是你的程序缺失的步骤。
  • 完善资源释放逻辑:因为rpmReadConfigFiles()是静态初始化一次,所以rpmFreeRpmrc()也只需调用一次,放在程序退出前即可。同时要确保所有分支路径下,已分配的资源都能被正确清理。
  • 修正空值处理细节:在openDb失败时,要确保已创建的rpmts被释放;closeDb中先判断迭代器和rpmts是否非空再执行释放操作,避免空指针操作。

修改后的代码示例:

#include <rpm/rpmdb.h>
#include <rpm/rpmlib.h>
#include <rpm/rpmts.h>
#include <stdio.h>

bool openDb(rpmts & ts, rpmdbMatchIterator & mi);
void closeDb(rpmts & ts, rpmdbMatchIterator & mi);

int main()
{
    rpmts ts = NULL;
    rpmdbMatchIterator mi = NULL;

    if (!openDb(ts, mi)) {
        closeDb(ts, mi);
        rpmFreeRpmrc();
        return 1;
    }

    closeDb(ts, mi);
    rpmFreeRpmrc();
    return 0;
}

bool openDb(rpmts & ts, rpmdbMatchIterator & mi)
{
    static bool s_bHereBefore = false;
    if (!s_bHereBefore) {
        s_bHereBefore = true;
        if (rpmReadConfigFiles(NULL, NULL) != 0) {
            printf("Failed to read RPM config files\n");
            return false;
        }
    }

    ts = rpmtsCreate();
    if (!ts) {
        printf("RPM open failed\n");
        return false;
    }

    mi = rpmtsInitIterator(ts, (rpmTag)RPMDBI_PACKAGES, NULL, 0);
    if (!mi) {
        printf("RPM iterator failed\n");
        rpmtsFree(ts);
        ts = NULL;
        return false;
    }

    return true;
}

void closeDb(rpmts & ts, rpmdbMatchIterator & mi)
{
    if (mi) {
        mi = rpmdbFreeIterator(mi);
    }
    if (ts) {
        rpmtsFree(ts);
        ts = NULL;
    }
}
  • 验证效果:重新编译后用valgrind --leak-check=full检测,之前的内存泄漏会消失,此时你的程序资源释放逻辑与rpm -qa基本对齐。

内容的提问来源于stack exchange,提问作者Shane Bishop

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 00:31:20