在将我的东方弹幕游戏拖到 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 搞的这反人类驱动)
逆天,,我查了半天到你这终于看明白了