C++11 错误的\u alloc,带有无序的\u映射初始值设定项\u列表和MMX指令,可能存在堆损坏?

C++11 错误的\u alloc,带有无序的\u映射初始值设定项\u列表和MMX指令,可能存在堆损坏?,c++11,gcc,initializer-list,bad-alloc,mmx,C++11,Gcc,Initializer List,Bad Alloc,Mmx,下面用gcc编译的代码抛出了一个bad_alloc(尝试了4.9.3、5.40和6.2)。gdb告诉我它发生在无序映射的initializer_列表的最后一行。如果我注释掉mmx指令\u m_maskmovq,则没有错误。同样,如果我注释掉无序_映射的初始化,这也不是错误。只有在调用mmx指令并使用初始值设定项列表初始化无序映射时,我才能获得bad\u alloc。如果我默认构建无序的映射并调用map.emplace(1,1),那么也不会有错误。我在一台拥有48核(英特尔至强)和376GB内存的

下面用gcc编译的代码抛出了一个
bad_alloc
(尝试了4.9.3、5.40和6.2)。gdb告诉我它发生在无序映射的initializer_列表的最后一行。如果我注释掉mmx指令
\u m_maskmovq
,则没有错误。同样,如果我注释掉无序_映射的初始化,这也不是错误。只有在调用mmx指令并使用初始值设定项列表初始化无序映射时,我才能获得
bad\u alloc
。如果我默认构建无序的映射并调用
map.emplace(1,1)
,那么也不会有错误。我在一台拥有48核(英特尔至强)和376GB内存的centos7机器上运行过这个程序,在Ubuntu WSL下的戴尔笔记本电脑(英特尔酷睿i7)上也运行过这个程序,得到了相同的结果。这是怎么回事?MMX指令是否损坏堆?Valgrind似乎没有发现任何有用的东西

编译器命令和输出:

$g++ -g -std=c++11 main.cpp
$./a.out
   terminate called after throwing an instance of 'std::bad_alloc'
   what():  std::bad_alloc
   Aborted
源代码(main.cpp):

#包括
#包括
int main()
{
__m64 a_64=_mm_set_pi8(0,0,0,0,0,0,0);
__m64 b_64=_mm_set_pi8(0,0,0,0,0,0,0);
char dest[8]={0};
_m_maskmovq(a_64,b_64,dest);
无序的_映射{{1,1};
}
更新:
_mm_empty()变通方法确实修复了此示例。在使用多线程代码时,一个线程执行向量指令,另一个线程使用无序的_映射,这似乎不是一个可行的解决方案。另一个有趣的问题是,如果我打开优化功能,坏的东西就会消失。但愿我们在生产过程中不会遇到这个错误(畏缩)。

没有堆损坏。这是因为
std::unordered\u map
在内部使用
long double
从初始值设定项中的元素数计算存储桶计数(请参阅
\u Prime\u rehash\u策略::\u M\u bkt\u获取libstdc++源代码中的元素数)

在从MMX代码切换到FPU代码之前,需要调用
\u mm\u empty
。这与为MMX寄存器文件重用FPU寄存器的历史决定有关(与现代CPU中的寄存器重命名相反)

如果添加了
\u mm\u empty
调用,则异常将消失:

…
  _m_maskmovq(a_64, b_64, dest);
  _mm_empty();
  std::unordered_map<int, int> map{{ 1, 1}};
…
…
_m_maskmovq(a_64,b_64,dest);
_mm_empty();
无序的_映射{{1,1};
…
参见,如所示


有,这将使此问题消失,因为SSE指令不会影响FPU状态,反之亦然。

我想这与谢谢有关。我已经验证了解决方法。以下几点:-
\u m_maskmovq
被列为一个,而不是MMX。这令人困惑错误的分配只在初始化器列表中发生。知道为什么吗如果我有多线程代码,那么我看不出_mm_empty将如何帮助我?构造函数中的计算使用长双精度
,请参阅我引用的GCC PR。您引用的网页上显示CPUID Flags:SSE,它告诉您如何检查指令的支持情况。这并不意味着函数在SSE指令集中(也不是因为它在MMX寄存器上运行)。引用的GCC PR使用无序_映射的默认构造函数。该PR中的代码是否正在优化以使用初始值设定项\u list构造函数?当我将代码更改为使用默认构造函数并随后调用insert时,坏的\u alloc会消失。
\u M\u bkt\u for \u元素
使用
长双精度
,因此FPU。显然,它只用于初始值设定项列表。
…
  _m_maskmovq(a_64, b_64, dest);
  _mm_empty();
  std::unordered_map<int, int> map{{ 1, 1}};
…