3

I have a C++ application that is crashing on startup for some Windows 7 users. I can't reproduce the error on my own machine, but used breakpad to generate a .dmp file, which shows that the code is crashing with "Illegal instruction" initializing a static std::vector array. What could this possibly mean?

Exception: Unhandled exception at 0x000000013F121362 (myApp.exe) in myApp.exe.4328.dmp: 0xC000001D:

Illegal Instruction.myApp.exe! dynamic initializer for Keyboard::key_freqs_() Line 11 C++

Dissasembly:

const std::vector<double> Keyboard::key_freqs_ = std::vector<double>({
**Crashed here->** 000000013F121362  vmovaps     ymm0,ymmword ptr [__ymm@404059fbe76c8b44403ede353f7ced91403d228f5c28f5c3403b800000000000 (01408B7DE0h)]  
000000013F12136A  movzx       r9d,byte ptr [rsp+20h]  
000000013F121370  lea         r8,[rbp+1F0h]  
000000013F121377  vmovups     ymmword ptr [rsp+30h],ymm0  
000000013F12137D  vmovaps     ymm0,ymmword ptr [__ymm@404499fbe76c8b44404371eb851eb85240425a9fbe76c8b4404152f1a9fbe76d (01408B7E00h)]  
000000013F121385  vmovups     ymmword ptr [rsp+50h],ymm0  
000000013F12138B  vmovaps     ymm0,ymmword ptr [__ymm@4049f4dd2f1a9fbe40487fdf3b645a1d40471fdf3b645a1d4045d3b645a1cac1 (01408B7E20h)]  
000000013F121393  vmovups     ymmword ptr [rsp+70h],ymm0  
000000013F121399  vmovaps     ymm0,ymmword ptr [__ymm@405059fbe76c8b44404ede147ae147ae404d22b020c49ba6404b800000000000 (01408B7E40h)]  
000000013F1213A1  vmovups     ymmword ptr [rbp-70h],ymm0  
000000013F1213A6  vmovaps     ymm0,ymmword ptr [__ymm@40549a0c49ba5e354053720c49ba5e3540525a9fbe76c8b4405152f1a9fbe76d (01408B7E60h)]  
000000013F1213AE  vmovups     ymmword ptr [rbp-50h],ymm0  
000000013F1213B3  vmovaps     ymm0,ymmword ptr [__ymm@4059f47ae147ae1440587fef9db22d0e40571fef9db22d0e4055d3a5e353f7cf (01408B7E80h)]  
000000013F1213BB  vmovups     ymmword ptr [rbp-30h],ymm0  
000000013F1213C0  vmovaps     ymm0,ymmword ptr [__ymm@406059eb851eb852405ede147ae147ae405d228f5c28f5c3405b800000000000 (01408B7EA0h)]  
000000013F1213C8  vmovups     ymmword ptr [rbp-10h],ymm0  
...

Edit: As the answers allude to, I was using an /arch:AVX compile flag, which doesn't work on all machines.

user1389840
  • 651
  • 9
  • 24
  • 8
    Your binary apparently contains AVX instructions. Did you compile this with AVX enabled (it's off by default)? I guess your users are just trying to run this on CPUs that don't support AVX!? – Michael Kenzel Jan 03 '20 at 19:20
  • Why not use static linking for the C++ libs instead of nonstandard distribution of the DLLs? – Dave S Jan 03 '20 at 19:20
  • 1
    Could this be as simple as your code using some CPU instructions (like SSE3 or AVX) that is not supported by your client machines? – Jesper Juhl Jan 03 '20 at 19:22

2 Answers2

8

vmovups is an AVX instruction. AVX is supported starting from Intel Sandy Bridge (2nd gen i3/i5/i7 series (2xxx and later), introduced around 2011), and AMD from Bulldozer.

On an older CPU (or current Pentium/Celeron or low-power Atom/Silvermont) the instruction will trap with an Illegal Instruction error.

You should either recompile your app without AVX support and/or use __cpuid to check the CPU capabilities, and delegate execution to the "slow" version, if needed.


Virtual machines may not pass through AVX support by default, but this is configurable. If the guest OS doesn't see AVX in the CPUID flags, it won't set the control-register bit that lets AVX instructions execute without faulting. (This must-enable mechanism prevents AVX-using user-space from having its state corrupted by context switches on an AVX-unaware OS.)

So unlike other extensions like BMI2 that you can use if the real HW supports them (regardless of virtualized CPUID), that's not the case for extensions that introduce new architectural state: AVX and AVX-512.

VMs may default to a guest without AVX so the VM can be migrated to hosts without AVX.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
rustyx
  • 80,671
  • 25
  • 200
  • 267
2

The immediate answer, you have: you've compiled for AVX registers and instructions, and the code assumes AVX availability but some users are running your code in circumstances where AVX is not available.

Less immediate is that there can be two circumstances. One is that, as already told to you, the processor may be too old to have AVX support. The other, which is my interest even a year too late for you, is that the operating system may have deliberately not enabled the processor's AVX functionality.

Windows 7 is specially affected on this. AVX instructions fault unless the operating system has enabled the AVX state component for use with XSAVE to save and restore AVX state on context switches. AVX is the first feature that needs XSAVE in contrast to FXSAVE. So, there'd be a mystery of history if Microsoft wrote its XSAVE support without planning for AVX. XSAVE support starts with the original Windows 7.

Where it gets weird is that the original Windows 7 would enable AVX (if the processor has it) but never does in practice. The reason is a policy in the resources of the hwpolicy.sys driver. The original Windows 7 has operating-system support for AVX and XSAVE but using AVX with XSAVE is disabled by policy! (I haven't found that this has ever been published, not that I'm good with Google.)

The policy in Windows 7 SP1 allows AVX, though only for GenuineIntel and AuthenticAMD processors (which is perhaps another story). If you want your AVX to get enabled on the original Windows 7, you can get it by updating the policy!

But be warned: whether the system's AVX support is quite right even for SP1 is unclear. There certainly were issues, even some that Microsoft admitted to at the time. Microsoft's user-mode documentation has SP1 requirements all over it, but the kernel-mode documentation to this day says nothing about SP1.

The summary, then, is that AVX on Windows 7, even SP1, is more than a bit troubled and Microsoft can fairly be said to have been less than open about it. Nobody should be caught out by this a decade later.