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

spdlog文件事件回调调用info()致段错误与双释放问题求助

解决spdlog回调中调用logger引发的段错误与双释放问题

问题背景

在使用spdlog的after_open和before_close文件事件回调时,调用spdlog::get("basic_logger")->info()会触发段错误或双释放崩溃,但直接用fmt::print写入文件流则正常。需要替换为spdlog的info()方法来获取规范的日志格式。

最小复现代码

#include <chrono>
#include <exception>
#include <cstdio>
#include <fmt/core.h>
#include <fmt/chrono.h>
#include <spdlog/spdlog.h>
#include <spdlog/sinks/basic_file_sink.h>


int main( )
{
    spdlog::file_event_handlers handlers;

    handlers.after_open   = [ ]( const spdlog::filename_t filename, std::FILE* const stream )
                            {   // 注释此行可查看before_close回调引发的错误
                                spdlog::get( "basic_logger" )->info( "\nLogging started..." );
                                fmt::print( stream, "\n[{}] [{}] Logging started...\n",
                                            std::chrono::system_clock::now( ), filename );
                            };

    handlers.before_close = [ ]( const spdlog::filename_t filename, std::FILE* const stream )
                            {
                                spdlog::get( "basic_logger" )->info( "Logging finished." );
                                fmt::print( stream, "[{}] [{}] Logging finished.\n",
                                            std::chrono::system_clock::now( ), filename );
                            };

    try
    {
        auto logger { spdlog::basic_logger_st( "basic_logger", "logs/basic-log.txt", true, handlers ) };
    }
    catch ( const std::exception& sx )
    {
        fmt::print( stderr, "\nSomething went wrong during program startup: log file init failed: {}\n\n",
                            sx.what( ) );
    }
}

错误信息

段错误时输出:

Segmentation fault (core dumped)

双释放时输出:

free(): double free detected in tcache 2
Aborted (core dumped)

编译命令

g++ -std=c++23 -O3 -march=westmere -Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -Wshadow -fwhole-program -DNDEBUG `pkg-config --cflags spdlog` `pkg-config --libs spdlog` Temp.cpp -o runTemp

问题原因与修复方案

原因分析

  1. after_open回调段错误:创建basic_logger_st时,after_open回调执行时机早于logger注册到spdlog全局注册表的节点,此时spdlog::get("basic_logger")返回空指针,调用info()触发段错误。
  2. before_close回调双释放:logger对象离开作用域销毁时,会先触发before_close回调,此时通过spdlog::get获取的logger正处于销毁流程中,内部资源已开始释放,重复操作导致双释放错误。

修复代码

绕过全局注册表,直接通过共享指针捕获logger传递给回调:

#include <chrono>
#include <exception>
#include <cstdio>
#include <fmt/core.h>
#include <fmt/chrono.h>
#include <spdlog/spdlog.h>
#include <spdlog/sinks/basic_file_sink.h>
#include <memory>

int main( )
{
    try
    {
        // 先创建不带回调的logger,确保初始化完成
        auto logger = spdlog::basic_logger_st( "basic_logger", "logs/basic-log.txt", true );
        
        // 获取文件sink指针,设置事件回调
        auto file_sink = std::dynamic_pointer_cast<spdlog::sinks::basic_file_sink_mt>(logger->sinks()[0]);
        if (file_sink)
        {
            spdlog::file_event_handlers handlers;
            
            // 捕获logger的shared_ptr,确保回调执行时对象有效
            handlers.after_open = [logger](const spdlog::filename_t filename, std::FILE* const stream)
            {
                logger->info("\nLogging started...");
                fmt::print(stream, "\n[{}] [{}] Logging started...\n",
                           std::chrono::system_clock::now(), filename);
            };
            
            handlers.before_close = [logger](const spdlog::filename_t filename, std::FILE* const stream)
            {
                logger->info("Logging finished.");
                fmt::print(stream, "[{}] [{}] Logging finished.\n",
                           std::chrono::system_clock::now(), filename);
            };
            
            file_sink->set_event_handlers(std::move(handlers));
        }
        
        // 正常使用logger
        logger->info("Program running...");
    }
    catch (const std::exception& sx)
    {
        fmt::print(stderr, "\n程序启动出错:日志文件初始化失败:{}\n\n", sx.what());
    }
}

关键说明

  • 先完成logger初始化,再获取对应的文件sink设置回调,避免时序问题。
  • 通过lambda捕获logger的shared_ptr,保证回调执行时logger对象始终有效,不会出现悬空指针或重复释放。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 13:05:00