在将我的东方弹幕游戏拖到 win10 虚拟机中运行时发现程序一运行就崩溃了,报了内存访问异常(0xc0000005),而且多运行几次现象也会不同,有时是直接崩溃,有时还能坚持到显示完启动画面,但进入游戏时还是会高概率的崩溃 – -b 。

于是挂上 windbg 看一下,发现断在了这里

0012da40 55              push    ebp
0012da41 8bec            mov     ebp,esp
0012da43 8b4508          mov     eax,dword ptr [ebp+8]
0012da46 0f2800          movaps  xmm0,xmmword ptr [eax]
0012da49 0f2901          movaps  xmmword ptr [ecx],xmm0    ; <--- 0xc0000005
0012da4c 0f284010        movaps  xmm0,xmmword ptr [eax+10h]
0012da50 0f294110        movaps  xmmword ptr [ecx+10h],xmm0

没啥问题啊?看到 ecx 是一个栈上的局部变量,而且内存确实是可写状态。于是搜一搜 movaps 的解释,看到了里面的这个:”When the source or destination operand is a memory operand, the operand must be aligned on a 16-byte boundary or a general-protection exception (#GP) is generated.”,再回头看看 ecx 的值是 0x00404348,好吧确实不能被 16 整除。。。所以为什么只有在虚拟机中才会出现?

继续往前翻代码,发现 ecx 是由 ID3D11DeviceContext::Map 创建而来的一个 D3D11_MAPPED_SUBRESOURCE 映射结构,随后发现了这段话:

  • For D3D_FEATURE_LEVEL_10_0 and higher, the pointer is aligned to 16 bytes.
  • For lower than D3D_FEATURE_LEVEL_10_0, the pointer is aligned to 4 bytes.

本以为找到原因了,但是用 dxdiag 一看我又迷糊了,虚拟机中的 dx 和 ddi 版本都是 10,支持 10.0,而且使用 D3D11CreateDeviceAndSwapChain 创建设备后显示所用的 feature levels 确实也是 D3D_FEATURE_LEVEL_10_0,那么照文档的说法应该是 16 字节对齐才对 ∠( ᐛ 」∠)_。

随后用物理机对比了一下,使用 D3D_FEATURE_LEVEL_10_0 创建的 d3d 设备是可以正常运行的,因此推测是虚拟机显卡驱动的实现有问题。在虚拟机中跟踪了一番,发现确实是在 VMware 的驱动 vm3dum_10.dll 中返回了没有对齐的内存地址。(所以还是老老实实换物理机测了,VMware 搞的这反人类驱动)