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

未内联Boost System自定义error_code时触发段错误的问题

Boost System自定义error_code栈溢出问题分析

问题描述

严格按照Boost System规范实现自定义error_code,将代码拆分到头文件与实现文件后,调用make_error_code触发GCC ASAN栈缓冲区溢出错误;但将make_error_code内联到头文件后,问题消失。需确认该用法是否存在遗漏。

现有代码实现

头文件(mylib_error_codes.hpp)

#pragma once

#include <boost/system/error_code.hpp>

namespace libmyimg {

enum class error {
    success = 0,

    invalid_signature,
    invalid_width,
    invalid_height,
    unsupported_bit_depth,
    unsupported_channel_count
};

class myimg_category_impl : public boost::system::error_category {
  public:
    const char* name() const noexcept;

    std::string message(int ev) const;
    char const* message(int ev, char* buffer, std::size_t len) const noexcept;
};

boost::system::error_category const& myimg_category();

boost::system::error_code make_error_code(error e);
} // namespace libmyimg

namespace boost::system {

template <> struct is_error_code_enum<::libmyimg::error> : std::true_type {};

} // namespace boost::system

实现文件(mylib_error_codes.cpp)

#include "mylib_error_codes.hpp"

namespace libmyimg {

const char* myimg_category_impl::name() const noexcept { return "libmyimg"; }

std::string myimg_category_impl::message(int ev) const
{
    char buffer[64];
    return this->message(ev, buffer, sizeof(buffer));
}

char const*
myimg_category_impl::message(int ev, char* buffer, std::size_t len) const noexcept
{
    switch (static_cast<error>(ev)) {
    case error::success: return "No error";
    case error::invalid_signature: return "Invalid image signature";
    case error::invalid_width: return "Invalid image width";
    case error::invalid_height: return "Invalid image height";
    case error::unsupported_bit_depth: return "Unsupported bit depth";
    case error::unsupported_channel_count:
        return "Unsupported number of channels";
    }

    std::snprintf(buffer, len, "Unknown libmyimg error %d", ev);
    return buffer;
}

boost::system::error_category const& myimg_category()
{
    static const myimg_category_impl instance;
    return instance;
}

boost::system::error_code make_error_code(error e)
{
    return boost::system::error_code(static_cast<int>(e), myimg_category());
}

} // namespace libmyimg

测试代码与错误信息

测试代码

auto const input{libmyimg::error::invalid_width};
auto const ec{make_error_code(input)};

ASAN错误日志

==35495==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffd65bf30c0 at pc 0x55ca6996b608 bp 0x7ffd65bf3040 sp 0x7ffd65bf3030
WRITE of size 8 at 0x7ffd65bf30c0 thread T0
    #0 0x55ca6996b607 in boost::system::error_code::error_code(int, boost::system::error_category const&) /home/my_project/build/default/vcpkg_installed/x64-linux/include/boost/system/detail/error_code.hpp:129
    #1 0x55ca69f548d3 in libmyimg::make_error_code(libmyimg::error) /home/my_project/src/error_codes/driver_error_codes.cpp:76
    #2 0x55ca699a68fd in DOCTEST_ANON_FUNC_2 /home/my_project/src/tests/error_codes.test.cpp:20
    #3 0x55ca69a12bac in doctest::Context::run() /home/my_project/build/default/vcpkg_installed/x64-linux/include/doctest/doctest.h:7007
    #4 0x55ca69a149c0 in main /home/my_project/src/tests/main.test.cpp:16
    #5 0x7f3516e33d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
    #6 0x7f3516e33e3f in __libc_start_main_impl ../csu/libc-start.c:392
    #7 0x55ca699605c4 in _start (/home/my_project/build/default/src/tests/driver_unit_tests+0x13d5c4)

问题原因分析

  1. 模板特化可见性问题:boost::system::is_error_code_enum<libmyimg::error>的特化必须在所有使用该枚举转换为error_code的代码前可见。当make_error_code放在实现文件中时,测试代码的翻译单元可能因头文件包含顺序或符号解析问题,导致Boost内部无法识别该枚举为error_code兼容类型,触发错误逻辑。
  2. ODR(单定义规则)冲突:make_error_code在实现文件中定义时,若多个翻译单元包含头文件并调用该函数,可能因符号重复定义或链接时的符号不一致,导致未定义行为。

解决方案

将make_error_code标记为inline并移至头文件中,确保所有翻译单元能看到一致的函数实现,同时保证模板特化的可见性:

修改后的头文件

#pragma once

#include <boost/system/error_code.hpp>

namespace libmyimg {

enum class error {
    success = 0,

    invalid_signature,
    invalid_width,
    invalid_height,
    unsupported_bit_depth,
    unsupported_channel_count
};

class myimg_category_impl : public boost::system::error_category {
  public:
    const char* name() const noexcept override;

    std::string message(int ev) const override;
    char const* message(int ev, char* buffer, std::size_t len) const noexcept override;
};

boost::system::error_category const& myimg_category();

// 标记为inline,放入头文件
inline boost::system::error_code make_error_code(error e)
{
    return boost::system::error_code(static_cast<int>(e), myimg_category());
}
} // namespace libmyimg

namespace boost::system {

template <> struct is_error_code_enum<::libmyimg::error> : std::true_type {};

} // namespace boost::system

实现文件无需修改

保持原实现文件内容不变,仅移除make_error_code的定义(因已移至头文件)。

额外检查点

  • 确保所有调用make_error_code或使用枚举隐式转换为error_code的翻译单元,都正确包含头文件mylib_error_codes.hpp。
  • 验证头文件路径是否正确,避免因路径错误导致的重复包含或符号缺失。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 21:39:52