C++ Modules执行触发std::bad_alloc核心转储,请求排查原因
问题描述
源代码
hello.cpp
module; import <filesystem>; import <iostream>; export module hello; export void fun() { std::cout << "Hello, GCC " << __GNUC__ << '.' << __GNUC_MINOR__ << '.' << __GNUC_PATCHLEVEL__ << '!' << std::endl; std::cout << "Hello, CXX " << __cplusplus << '!' << std::endl; std::cout << "PWD: " << std::filesystem::current_path() << std::endl; }
main.cpp
import hello; int main() { fun(); return 0; }
运行平台
- 操作系统:Linux
- 发行版:Ubuntu 22.04.2 LTS
- 架构:x86_64 & aarch64(均已测试)
- GCC版本:11.3.0 & 14.0.0(均已测试)
编译命令
g++-14 -std=c++23 -fmodules-ts -Wall -Wextra -pedantic -c -x c++-system-header filesystem iostream g++-14 -std=c++23 -fmodules-ts -Wall -Wextra -pedantic hello.cpp main.cpp -o module-test-g++-14 g++-11 -std=c++23 -fmodules-ts -Wall -Wextra -pedantic -c -x c++-system-header filesystem iostream g++-11 -std=c++23 -fmodules-ts -Wall -Wextra -pedantic hello.cpp main.cpp -o module-test-g++-11
执行结果
不同架构和GCC版本下结果类似,均出现核心转储问题。
user@host:~/tmp$ ./module-test-g++-14 Hello, GCC 14.0.0! Hello, CXX 202302! terminate called after throwing an instance of 'std::bad_alloc' what(): std::bad_alloc Aborted (core dumped) user@host:~/tmp$ ./module-test-g++-11 Hello, GCC 11.3.0! Hello, CXX 202100! terminate called after throwing an instance of 'std::bad_alloc' what(): std::bad_alloc Aborted (core dumped)
调试信息
问题源于内部内存分配失败:
(gdb) 298 _M_get_allocator() const (gdb) std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::max_size (this=0x7fffffffdf40) at /usr/include/c++/11/bits/basic_string.h:932 932 { return (_Alloc_traits::max_size(_M_get_allocator()) - 1) / 2; } (gdb) std::allocator_traits<std::allocator<char> >::max_size (__a=...) at /usr/include/c++/11/bits/alloc_traits.h:552 552 return size_t(-1) / sizeof(value_type); (gdb) 547 max_size(const allocator_type& __a __attribute__((__unused__))) noexcept (gdb) std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::max_size (this=0x7fffffffdf40) at /usr/include/c++/11/bits/basic_string.h:932 932 { return (_Alloc_traits::max_size(_M_get_allocator()) - 1) / 2; } (gdb) 931 max_size() const _GLIBCXX_NOEXCEPT (gdb) std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_create (this=0x7fffffffdf40, __capacity=@0x7fffffffddd0: 93824992338720, __old_capacity=0) at /usr/include/c++/11/bits/basic_string.tcc:137 137 if (__capacity > max_size()) (gdb) 143 if (__capacity > __old_capacity && __capacity < 2 * __old_capacity) (gdb) 153 return _Alloc_traits::allocate(_M_get_allocator(), __capacity + 1); (gdb) std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_get_allocator (this=0x7fffffffdf40) at /usr/include/c++/11/bits/basic_string.h:295 295 { return _M_dataplus; } (gdb) 294 _M_get_allocator() (gdb) std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_create (this=0x7fffffffdf40, __capacity=@0x7fffffffddd0: 93824992338720, __old_capacity=0) at /usr/include/c++/11/bits/basic_string.tcc:153 153 return _Alloc_traits::allocate(_M_get_allocator(), __capacity + 1); (gdb) std::allocator_traits<std::allocator<char> >::allocate (__a=..., __n=93824992338721) at /usr/include/c++/11/bits/alloc_traits.h:464 464 { return __a.allocate(__n); } (gdb) std::allocator<char>::allocate (__n=93824992338721, this=0x7fffffffdf40) at /usr/include/c++/11/bits/allocator.h:182 182 if (std::is_constant_evaluated()) (gdb) std::is_constant_evaluated () at /usr/include/c++/11/type_traits:3419 3419 { return __builtin_is_constant_evaluated(); } (gdb) 3418 is_constant_evaluated() noexcept (gdb) std::allocator<char>::allocate (__n=93824992338721, this=0x7fffffffdf40) at /usr/include/c++/11/bits/allocator.h:182 182 if (std::is_constant_evaluated()) (gdb) 185 return __allocator_base<_Tp>::allocate(__n, 0); (gdb) __gnu_cxx::new_allocator<char>::allocate (this=0x7fffffffdf40, __n=93824992338721) at /usr/include/c++/11/ext/new_allocator.h:111 111 if (__builtin_expect(__n > this->_M_max_size(), false)) (gdb) __gnu_cxx::new_allocator<char>::_M_max_size (this=0x7fffffffdf40) at /usr/include/c++/11/ext/new_allocator.h:200 200 return std::size_t(__PTRDIFF_MAX__) / sizeof(_Tp); (gdb) 197 _M_max_size() const _GLIBCXX_USE_NOEXCEPT (gdb) __gnu_cxx::new_allocator<char>::allocate (this=0x7fffffffdf40, __n=93824992338721) at /usr/include/c++/11/ext/new_allocator.h:111 111 if (__builtin_expect(__n > this->_M_max_size(), false)) (gdb) 127 return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp))); (gdb) terminate called after throwing an instance of 'std::bad_alloc' what(): std::bad_alloc Program received signal SIGABRT, Aborted. __pthread_kill_implementation (no_tid=0, signo=6, threadid=140737348187968) at ./nptl/pthread_kill.c:44 44 ./nptl/pthread_kill.c: No such file or directory.
问询
编译命令是否存在错误?或者这是GCC的bug?
- 若为个人问题,请告知正确编译方式。
- 若为GCC的bug,将向官方提交报告。
解答
这是GCC在C++模块TS支持中的已知bug,根源在于std::filesystem的全局状态在模块模式下未正确初始化,导致current_path()返回的std::string内部出现非法的超大容量值,触发std::bad_alloc异常。
临时修复方案
- 切换为传统头文件包含方式:将模块中的
import <filesystem>;替换为#include <filesystem>,移除模块前缀module;,转为普通C++代码编译(不再使用-fmodules-ts参数)。 - 手动触发初始化:在调用
current_path()前,显式调用std::filesystem::path::codecvt()强制初始化相关全局状态。修改后的fun()函数如下:export void fun() { std::cout << "Hello, GCC " << __GNUC__ << '.' << __GNUC_MINOR__ << '.' << __GNUC_PATCHLEVEL__ << '!' << std::endl; std::cout << "Hello, CXX " << __cplusplus << '!' << std::endl; // 手动触发filesystem全局状态初始化 (void)std::filesystem::path::codecvt(); std::cout << "PWD: " << std::filesystem::current_path() << std::endl; }
bug提交建议
该问题在GCC 11到14版本中均存在,属于模块TS与标准库组件的兼容性问题。提交bug时附上测试代码、编译命令、运行环境及调试信息,可帮助开发者快速定位问题。
内容的提问来源于stack exchange,提问作者Shuangcheng Ni
相关产品推荐
相关产品推荐

