gcc segfault由file_event_handlers回调中的spdlog::get(“logger”)->info()调用引起

uplii1fm  于 2023-05-18  发布在  其他
关注(0)|答案(1)|浏览(116)

下面的程序由于seg故障而崩溃。我找不到理由。目前我所知道的是,对info()成员spdlog::get( "basic_logger" )->info( "\nLogging started..." );spdlog::get( "basic_logger" )->info( "Logging finished." );的两个调用导致了问题(第一个导致了segfault,第二个导致了double free)。
一个最小的例子:

#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 )
                            {   // Comment this line out to see the error caused by the before_close callback
                                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

print的调用不会导致任何问题。但是,我想用上面看到的对info()的调用来替换它们,因为这样会记录更多的细节。

fiei3ece

fiei3ece1#

很不幸,你想做的是不可能的。您对spdlog::basic_logger_st的调用以here结束:

static std::shared_ptr<spdlog::logger> create(std::string logger_name, SinkArgs &&... args)
    {
/*[1]*/ auto sink = std::make_shared<Sink>(std::forward<SinkArgs>(args)...);
        auto new_logger = std::make_shared<spdlog::logger>(std::move(logger_name), std::move(sink));
/*[2]*/ details::registry::instance().initialize_logger(new_logger);
        return new_logger;
    }

标记为[1]的行是创建接收器并调用after_open回调的行,但[2]实际上是使记录器作为basic_logger可用的行。
您必须将after_open中的log语句提升到调用basic_logger_st之后的行中。before_close中的log语句应该可以正常工作。

相关问题