读取指令写入访问冲突

时间:2014-01-21 11:26:31

标签: visual-c++ optimization compiler-construction processor amd-processor

我们在产品中使用SQLite库,并在使用不同的编译器版本(Visual C ++)重新编译后突然在客户计算机上崩溃。

崩溃是

ExceptionAddress: 0710eadd (sqlite3!sqlite3_transfer_bindings+0x0004e5bd)
   ExceptionCode: c0000005 (Access violation)
  ExceptionFlags: 00000000
NumberParameters: 2
   Parameter[0]: 00000001
   Parameter[1]: 07148688
Attempt to write to address 07148688

导致崩溃的代码如下(sqlite3MutexInit的一部分):

0710ead0 b804811407      mov     eax, 0x07148104
0710ead5 b97c861407      mov     ecx, 0x0714867c
0710eada 0f44c8          cmove   ecx, eax
0710eadd f30f7e410c      movq    xmm0, mmword ptr [ecx+0Ch]

相应的C代码:

if( sqlite3GlobalConfig.bCoreMutex ){
  pFrom = sqlite3DefaultMutex();
}else{
  pFrom = sqlite3NoopMutex();
}
memcpy(pTo, pFrom, offsetof(sqlite3_mutex_methods, xMutexAlloc));

这不是特别重要,但在我们的例子中,sqlite3GlobalConfig.bCoreMutex设置为1。

问题在于,在这种特殊情况下,地址为07148688的内存是可读的,指令应该读取,而不是写入。

我们有来自两台机器的内存转储,在两种情况下都发生在Athlon XP处理器上(系列/型号/步进:6/10 / 0,6 / 8/1)。

使用多个Visual C ++版本(2012,2013和2013 Update 1)进行重新编译时,代码略有不同(在错误地址处为movq vs movdqu指令),但崩溃始终如一。

可能是由我们遇到的处理器或编译器错误造成的吗?

1 个答案:

答案 0 :(得分:3)

较旧的AMD Athlon(和Pentium III)处理器显然不支持这种随SSE2指令引入的movq形式。我引用了GCC discussion中的Anders Carlsson:

  

查看ftp://download.intel.com/design/Pentium4/manuals/25366614.pdf MOVQ提供的英特尔参考文档,其中包含以下操作码:

0F 6F /r MOVQ mm, mm/m64      Move quadword from mm/m64 to mm. 
0F 7F /r MOVQ mm/m64, mm      Move quadword from mm to mm/m64. 
F3 0F 7E MOVQ xmm1, xmm2/m64  Move quadword from xmm2/mem64 to xmm1.
66 0F D6 MOVQ xmm2/m64, xmm1  Move quadword from xmm1 to xmm2/mem64.
     

由于后两条指令在AMD和Pentium III上不受支持,因此您需要一些其他方法在xmm寄存器和内存之间移动数据。

英特尔参考文档不再可用; movq指令的另一个引用是http://x86.renejeschke.de/html/file_module_x86_id_201.html。不过,我没有AMD Athlon XP来测试它。

关闭SSE2优化应该可以解决问题。 SSE2指令集是VS2012及更高版本中的缺省值,/ arch编译器标志控制使用哪个指令集;见http://msdn.microsoft.com/en-us/library/7t5yh4fd%28v=vs.110%29.aspx