调用rollingfile_udata_set_logdir时log4c报segmentation fault
段错误根本原因
触发崩溃的核心原因是log4c调用顺序完全错误,在库未完成初始化时就操作内部结构体,具体细节:
- log4c所有自定义类型(rollingfile appender、sizewin滚动策略等)的注册、内存分配逻辑、操作函数表绑定,都要在
log4c_init()执行完成后才会生效。 - 你的代码跳过了
log4c_init()步骤,直接调用log4c_appender_get()拿appender、调用rollingfile_make_udata()创建用户数据,这两个接口在库未初始化时返回的都是无效指针(要么是空,要么是未完成内存映射的野指针)。 - 后续调用
rollingfile_udata_set_logdir()向无效指针指向的内存地址写入数据,直接触发段错误。 - 额外存在逻辑冲突:你在代码中手动创建udata设置日志目录,和xml配置文件中rfileappender的logdir、rollingpolicy绑定逻辑完全脱节,就算不崩溃,配置的滚动规则、日志前缀等参数也不会生效。
修复方法
严格按照log4c的生命周期调整代码逻辑,禁止在库初始化前操作内部结构体:
- 程序启动后第一时间调用
log4c_init(),完成库初始化、xml配置文件加载、所有appender/layout/rollingpolicy实例的初始化工作。 - 如果不需要动态修改配置,完全不需要手动调用
rollingfile_make_udata()、rollingfile_udata_set_logdir()这类appender内部操作接口,xml里配置的/var/log/日志目录、1KB大小滚动、保留10个日志文件的规则会自动生效。 - 如果确实需要动态修改日志目录(比如运行用户没有
/var/log/写入权限),要在log4c_init()执行完成后,从已经初始化好的appender实例中取出合法的udata指针,再修改参数,禁止手动创建udata。
修正后的参考代码
#include <log4c.h> // 其他头文件省略 int main() { // 第一步:必须先初始化log4c if (log4c_init() != 0) { return -1; } const char *logdir = "."; // 初始化完成后再获取appender,此时拿到的是合法实例 log4c_appender_t* app = log4c_appender_get("rfileappender"); // 从已初始化的appender中取出自动分配的udata,不要自己手动make rollingfile_udata_t *rfup = (rollingfile_udata_t*)log4c_appender_get_udata(app); if (rfup != NULL) { // 此时rfup是合法指针,调用set方法不会触发段错误 rollingfile_udata_set_logdir(rfup, logdir); } // 正常日志打印逻辑 log4c_category_t *collector_cat = log4c_category_get("log4c.collector"); log4c_category_debug(collector_cat, "log system init success"); // 程序退出前执行资源清理 log4c_fini(); return 0; }
补充说明:如果不需要动态覆盖配置,上述代码里手动取rfup改logdir的逻辑可以全部删掉,直接用xml里的配置即可,代码会更简洁。
内容的提问来源于stack exchange,提问作者Rony Tesler
相关产品推荐
相关产品推荐

