如何无内存泄漏地打开和关闭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
相关产品推荐
相关产品推荐

