在Google Test中使用boost::log触发访问违规的解决咨询
问题描述
单独运行以下Boost.Log代码时,控制台可正常输出"Test Log":
#include <boost/log/trivial.hpp> #include <boost/log/sources/severity_logger.hpp> int main() { boost::log::sources::severity_logger_mt<boost::log::trivial::severity_level> logger; BOOST_LOG_SEV(logger, boost::log::trivial::info) << "Test Log"; return 0; }
按逻辑,即使未配置任何sink,Boost.Log默认会将日志输出到控制台,因此代码可正常运行。
但将该代码集成到同解决方案下的Google Test项目时,触发访问违规,测试无法通过,报错信息为:unknown file: error: SEH exception with code 0xc0000005 thrown in the test body
测试代码如下:
#include "pch.h" #include <boost/log/sources/severity_logger.hpp> #include <boost/log/trivial.hpp> TEST(TestCaseName, TestName) { EXPECT_EQ(1, 1); EXPECT_TRUE(true); } TEST(TestCaseName, LogTest1) { boost::log::sources::severity_logger_mt<boost::log::trivial::severity_level> logger; BOOST_LOG_SEV(logger, boost::log::trivial::info) << "Test Log"; EXPECT_TRUE(true); }
开发环境
- C++17
- Visual Studio 2022 专业版
- Google Test
- 通过vcpkg安装的Boost 1.80(boost-log:x64-windows, 1.80.0#1)
已尝试方案
- 配置虚拟sink,无效
- 创建severity logger的空子类(可行但因Boost模板特性难以多态传递)
调试补充信息
调试时程序在memmove函数处中断,路径为C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.37.32822\include\xstring第119行,报错信息:
Exception thrown at 0x00007FFD88A01441 (vcruntime140d.dll) in Sample-Test1.exe: 0xC0000005: Access violation writing location 0x000000000000000F.
堆栈跟踪:
vcruntime140d.dll!00007ffd88a01441() Unknown Sample-Test1.exe!std::_Char_traits<char,int>::move(char * const _First1, const char * const _First2, const unsigned __int64 _Count) Line 122 C++ Sample-Test1.exe!std::string::append(const char * const _Ptr, const unsigned __int64 _Count) Line 3276 C++ Sample-Test1.exe!boost::log::v2_mt_nt6::aux::basic_ostringstreambuf<char,std::char_traits<char>,std::allocator<char>>::append(const char * s, unsigned __int64 n) Line 185 C++ Sample-Test1.exe!boost::log::v2_mt_nt6::basic_formatting_ostream<char,std::char_traits<char>,std::allocator<char>>::formatted_write(const char * p, __int64 size) Line 737 C++ Sample-Test1.exe!boost::log::v2_mt_nt6::basic_formatting_ostream<char,std::char_traits<char>,std::allocator<char>>::operator<<(const char * p) Line 441 C++ Sample-Test1.exe!boost::log::v2_mt_nt6::basic_record_ostream<char>::operator<<(const char * p) Line 219 C++ Sample-Test1.exe!TestCaseName_LogTest1_Test::TestBody() Line 12 C++ Sample-Test1.exe!testing::internal::HandleSehExceptionsInMethodIfSupported<testing::Test,void>(testing::Test * object, void(testing::Test::*)() method, const char * location) Line 2428 C++ Sample-Test1.exe!testing::internal::HandleExceptionsInMethodIfSupported<testing::Test,void>(testing::Test * object, void(testing::Test::*)() method, const char * location) Line 2479 C++ Sample-Test1.exe!testing::Test::Run() Line 2524 C++ Sample-Test1.exe!testing::TestInfo::Run() Line 2697 C++ Sample-Test1.exe!testing::TestCase::Run() Line 2812 C++ Sample-Test1.exe!testing::internal::UnitTestImpl::RunAllTests() Line 5178 C++ Sample-Test1.exe!testing::internal::HandleSehExceptionsInMethodIfSupported<testing::internal::UnitTestImpl,bool>(testing::internal::UnitTestImpl * object, bool(testing::internal::UnitTestImpl::*)() method, const char * location) Line 2428 C++ Sample-Test1.exe!testing::internal::HandleExceptionsInMethodIfSupported<testing::internal::UnitTestImpl,bool>(testing::internal::UnitTestImpl * object, bool(testing::internal::UnitTestImpl::*)() method, const char * location) Line 2479 C++ Sample-Test1.exe!testing::UnitTest::Run() Line 4786 C++ Sample-Test1.exe!RUN_ALL_TESTS() Line 2342 C++ Sample-Test1.exe!main(int argc, char * * argv) Line 37 C++ Sample-Test1.exe!invoke_main() Line 79 C++ Sample-Test1.exe!__scrt_common_main_seh() Line 288 C++ Sample-Test1.exe!__scrt_common_main() Line 331 C++ Sample-Test1.exe!mainCRTStartup(void * __formal) Line 17 C++ kernel32.dll!00007ffda1727344() Unknown ntdll.dll!00007ffda25626b1() Unknown
补充说明
2024年12月更新:在Ubuntu 2024环境下未复现该问题,推测为Windows特定问题。
解决方案
该问题源于Windows下Boost.Log与Google Test的全局对象初始化顺序冲突——Boost.Log默认控制台sink依赖的全局对象,在Google Test框架初始化前未完成构造,或在测试执行期间被提前销毁,进而引发非法内存访问。可通过以下方式解决:
1. 显式初始化Boost.Log核心
在所有测试执行前,显式初始化Boost.Log的核心组件,避免依赖默认延迟初始化。可通过Google Test的全局环境钩子实现:
#include <boost/log/core.hpp> #include <boost/log/trivial.hpp> #include <boost/log/expressions.hpp> #include <boost/log/sinks/text_ostream_backend.hpp> #include <boost/log/utility/setup/common_attributes.hpp> #include <gtest/gtest.h> class LogInitializer : public testing::Environment { public: void SetUp() override { // 初始化Boost.Log核心并配置控制台sink auto core = boost::log::core::get(); core->set_filter(boost::log::trivial::severity >= boost::log::trivial::info); boost::log::add_console_log(std::cout); boost::log::add_common_attributes(); } }; int main(int argc, char** argv) { testing::InitGoogleTest(&argc, argv); // 注册全局初始化器 testing::AddGlobalTestEnvironment(new LogInitializer); return RUN_ALL_TESTS(); }
2. 临时禁用Boost.Log输出
如果测试不需要日志输出,可临时禁用所有sink避免初始化问题:
#include <boost/log/core.hpp> #include <boost/log/expressions.hpp> #include <gtest/gtest.h> TEST(TestCaseName, LogTest1) { auto core = boost::log::core::get(); // 保存原有过滤规则 auto original_filter = core->get_filter(); // 禁用所有日志输出 core->set_filter(boost::log::expressions::false_val()); boost::log::sources::severity_logger_mt<boost::log::trivial::severity_level> logger; BOOST_LOG_SEV(logger, boost::log::trivial::info) << "Test Log"; // 恢复原有过滤规则(可选) core->set_filter(original_filter); EXPECT_TRUE(true); }
3. 调整MSVC链接顺序
在Visual Studio中,将boost-log库的链接顺序调整到gtest/gtest_main之前,确保Boost.Log全局对象优先构造:
- 右键测试项目 → 属性 → 链接器 → 输入 → 附加依赖项,将
boost-log-vc143-mt-gd-x64-1_80.lib(对应你的Boost版本)移到gtestd.lib、gtest_maind.lib之前。
4. 升级Boost版本
该问题在Boost 1.81及以后版本中已被修复,直接升级到最新稳定版即可解决冲突。
内容的提问来源于stack exchange,提问作者Seth5537

