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

C++20共享内存日志写入触发Core Dump问题求助

共享内存日志模块Core Dump问题分析

参考Youtube教程实现C++20共享内存日志模块,向内存块写入数据时持续触发Core Dump,尝试strncpy等字符串操作方法未解决问题。以下是相关代码片段及调试信息:

main.cpp

变量log_type为int类型,通过argv赋值

switch (log_type)
{
    case 1:
        char do_test[6];
        std::memset(do_test, 0, sizeof(do_test));
        std::snprintf(do_test, sizeof(do_test), "%s", "Hello");
        logs::BLogger::append_log(do_test, std::strlen(do_test));
        logs::BLogger::test_console_log_data();
    break;
    case 2:
        logs::BLogger::test_console_log_data();
    break;
    case 3:
    break;
    default:
    break;
}

logs::BLogger::destroy();
std::cout << "Program is now ending..." << std::endl;

logger.cpp

错误发生在std::memmove调用时

bool
logs::BLogger::append_log(char* _data_p, std::size_t _size)
{
    if (!m_logfile_data_p) return false;
    if (_size + m_log_size >= m_log_size_limit) create_log_file();

    std::memmove(tail(), _data_p, _size + 1);
    m_log_size = m_log_size + _size;
    return true;
}

bool
logs::BLogger::start(uint32_t _log_size = LOG_SIZE_LIMIT)
{
    // std::lock_guard<std::mutex> start_guard(m_log_mutex);
    m_directory.append(LOG_DIRECTORY).append("/").append(shared::s_app_name).append("/");
    name_log_file();
    m_log_size_limit = _log_size;
    if (m_log_size_limit > LOG_SIZE_LIMIT) m_log_size_limit = LOG_SIZE_LIMIT;

    /**
     * @brief
     *      Checks if directory exists, and proceeds to create one if it does not exists.
     */
    if (!shared::is_directory(m_directory))
    {
        if (!shared::create_directory(m_directory)) return false;
    }

    std::string filepath;
    filepath.append(m_directory).append(m_file_name);

    /**
     * @brief
     *      Checks if file exists, and proceeds to create one if it does not exists.
     */
    if (!shared::is_file(filepath))
    {
        if (!shared::create_file(filepath)) return false;
    }

    if (!logs::BLogSharedMemory::attach_memory_block(filepath, m_logfile_data_p)) return false;

    m_log_size = std::strlen(m_logfile_data_p);
    std::cout << "[logger] Is NULL: " << (m_logfile_data_p ? "No" : "Yes") << std::endl;
    std::cout << "[logger] Log size: " << m_log_size << std::endl;
    return true;
}

logger.hpp(关键片段)

class BLogger final
{
    // ==================================================
    // * CONSTRUCTOR(S)
    // ==================================================
    public:
        /**
         * @brief
         *      Default constructor
         */
        BLogger() = delete;
        
        /**
         * @brief
         *      Default destructor.
         */
        ~BLogger();

    // ==================================================
    // * INLINE METHOD(S)
    // ==================================================
    private:
        /**
         * @brief
         *      Get the tail of logfile.
         */
        static char*
        tail(void) { return m_logfile_data_p + m_log_size; }
        
    // ==================================================
    // * METHOD(S)
    // ==================================================
    public:
        /**
         * @brief
         *      Attempts to check if directory exists and if folder can be created.
         * @param _log_size
         *      The file created will have a size limit.
         */
        static bool
        start(uint32_t _log_size);
        /**
         * @brief
         *      Attempts to append data into log.
         * @param _data_p
         *      The data to append into
         * @param _size
         *      Size of the data.
         */
        static bool
        append_log(char* _data_p, std::size_t _size);
        
    // ==================================================
    // * MEMBER(S)
    // ==================================================
    private:
        /**
         * @brief
         *      The data used when opening the file in shared memory.
         */
        static char*
        m_logfile_data_p;
        
        /**
         * @brief
         *      Size of the log
         */
        static std::size_t
        m_log_size;
};

shared_memory.hpp

/**
 * @brief
 *      Shared memory for I/O purposes.
 */
class BLogSharedMemory final
{
    // ==================================================
    // * CONSTRUCTOR(S)
    // ==================================================
    public:
        /**
         * @brief
         *      Prevent creation of shared memory class.
         */
        BLogSharedMemory() = delete;
    
    private:
        /**
         * @brief
         *      Default destructor.
         */
        ~BLogSharedMemory();
        
    // ==================================================
    // * METHOD(S)
    // ==================================================
    public:
        /**
         * @brief
         *      Attempts to get memory information.
         * @param _path
         *      The path of the log file to exist.
         * @param _file_name
         *      Name of the file to create. The path must start from the path of bin if relative.
         * @param _block_p
         *      The block used for appending.
         * @param _block_size
         *      Size of the block.
         */
        static bool
        attach_memory_block(const std::string& _file_name, char*& _block_p, int _block_size = 4096);

        /**
         * @brief
         *      Detaches memory block information.
         * @param _block_p
         *      The block used for appending.
         * @return
         *      FALSE if memory block detachment fails.
         */
        static bool
        detach_memory_block(char*& _block_p);
        
    // ==================================================
    // * MEMBER(S)
    // ==================================================
    private:
        /**
         * @brief
         *      Key of the file for access.
         */
        static int
        m_shm_id;
};

shared_memory.cpp

bool
logs::BLogSharedMemory::attach_memory_block(const std::string& _file_name, char*& _block_p, int _block_size)
{
    // key_t key = SHARED_MEMORY_KEY;

    key_t key;
    if ((key = ftok(_file_name.c_str(), 0)) == -1) return false;

    m_shm_id = shmget(key, _block_size, IPC_EXCL | IPC_CREAT | 0666);
    if (m_shm_id == -1 && errno == EEXIST)
    {
        m_shm_id = shmget(key, _block_size, IPC_CREAT | 0666);
        if (m_shm_id == -1) return false;
    }
    
    /**
     * @note
     *      shmat returns shmid_ds structure associated with the memory, or error.
     */
    _block_p = (char*)shmat(m_shm_id, NULL, 0);
    std::cout << "Is NULL (shm): " << (_block_p ? "No" : "Yes") << std::endl;
    if (_block_p == (char*) -1 || !_block_p)
    {
        std::cout << "Shared memory: shmat error!" << std::endl;
        return false;
    }

    return true;
}

错误前输出

Is NULL (shm): No
[logger] Is NULL: No
[logger] Log size: 0
Log type: 1
Segmentation fault

GDB错误栈

#0  std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_data (this=0x5) at /usr/include/c++/11/bits/basic_string.h:194
194           _M_data() const
(gdb) bt full
#0  std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_data (this=0x5) at /usr/include/c++/11/bits/basic_string.h:194
No locals.
#1  std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_is_local (this=0x5) at /usr/include/c++/11/bits/basic_string.h:230
No locals.
#2  std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_dispose (this=0x5) at /usr/include/c++/11/bits/basic_string.h:239
No locals.
#3  std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string (this=0x5, __in_chrg=<optimized out>) at /usr/include/c++/11/bits/basic_string.h:672
No locals.
#4  0x0000aaaad7a83ffc in memmove (__len=6, __src=<optimized out>, __dest=<optimized out>) at /usr/include/aarch64-linux-gnu/bits/string_fortified.h:36
No locals.
#5  logs::BLogger::append_log (_data_p=_data_p@entry=0xffffdbc872c8 "Hello", _size=5) at src/logs/logs_logger.cpp:225
No locals.
#6  0x0000aaaad7a828bc in main (_argc=3, _argv=0xffffdbc87468) at experiment/logging/main.cpp:121
        do_test = "Hello"
        opt = <optimized out>
        log_type = 1
        char_log_type = "1", '\000' <repeats 18 times>

问题原因分析

  1. 静态成员未显式初始化
    BLogger类的m_logfile_data_p和m_log_size是静态成员变量,若未在类外显式初始化(如char* logs::BLogger::m_logfile_data_p = nullptr;),其初始值为随机内存值。虽然当前输出显示m_log_size=0,但这是巧合,实际运行中可能因随机值导致内存计算错误,触发越界访问。

  2. 共享内存未初始化导致的未定义行为
    shmget创建的共享内存块内容为随机值,start函数中用std::strlen(m_logfile_data_p)计算初始日志长度时,若内存中不存在'\0'终止符,strlen会持续读取直到越界,触发未定义行为。即使当前返回0,后续写入操作仍可能受随机内存影响。

  3. create_log_file函数潜在错误
    虽然当前_size + m_log_size >= m_log_size_limit条件不满足(不会调用create_log_file),但GDB栈中显示std::string析构错误(this=0x5为无效地址),说明该函数可能存在std::string的非法操作(如访问空指针或无效内存),间接触发Core Dump。

  4. 共享内存大小与日志限制不匹配
    共享内存默认大小为4096字节,若LOG_SIZE_LIMIT大于该值,m_log_size_limit会被设为更大的数值,后续写入时可能忽略实际内存边界,导致越界访问共享内存。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 14:30:53