none
VC++ 2013 tan() causes illegal instruction exception in x64

    Question

  • I've encountered what I believe to be a compiler bug, but am unsure at the moment.

    Background:

    I've got a program which builds and runs fine in VS2010 for both debug/release on Win32/64.

    I recently upgraded to VS 2013, update 3 and am now getting illegal instruction exceptions that crash my program.

    This only happens when building for x64, and not for Win32. The bug can be reproduced very easily with this code:

    float f = 8388608.0;
    float f2 = tan(f);//Crashes

    This doesn't happen when using double, only with float, and only on x64.

    I'm stumped as to what could be the problem and am suspecting the compiler.

    My CPU: AMD Phenom II


    Any help is greatly appreciated. Thanks.

    Monday, September 01, 2014 12:58 AM

Answers

All replies

  • Can you see in the debugger which assembly instruction has triggered the exception? Probably it's an SSE/AVX instruction which is not available on your CPU.

    To report compiler bugs you can use the Connect site: https://connect.microsoft.com/VisualStudio

    Monday, September 01, 2014 5:05 AM
    Moderator
  • I suspect your suggestion is correct, but the assembly looks pretty innocent. It's just calling into the standard tan() function:

      00082 e8 00 00 00 00 call ?tan@@YAMM@Z ; tan
      00087 c6 44 24 44 01 mov BYTE PTR $T10[rsp], 1
      0008c f3 0f 11 44 24
    20 movss DWORD PTR f2$5[rsp], xmm0

    And here is the implementation of tan():

    ; Function compile flags: /Odsp /RTCsu
    ; File c:\program files (x86)\microsoft visual studio 12.0\vc\include\math.h
    ; COMDAT ?tan@@YAMM@Z
    _TEXT SEGMENT
    _X$ = 64
    ?tan@@YAMM@Z PROC ; tan, COMDAT

    ; 1138 :         {return (tanf(_X)); }

    $LN3:
      00000 f3 0f 11 44 24
    08 movss DWORD PTR [rsp+8], xmm0
      00006 57 push rdi
      00007 48 83 ec 30 sub rsp, 48 ; 00000030H
      0000b 48 8b fc mov rdi, rsp
      0000e b9 0c 00 00 00 mov ecx, 12
      00013 b8 cc cc cc cc mov eax, -858993460 ; ccccccccH
      00018 f3 ab rep stosd
      0001a f3 0f 10 44 24
    40 movss xmm0, DWORD PTR _X$[rsp]
      00020 ff 15 00 00 00
    00 call QWORD PTR __imp_tanf
      00026 48 83 c4 30 add rsp, 48 ; 00000030H
      0002a 5f pop rdi
      0002b c3 ret 0
    ?tan@@YAMM@Z ENDP ; tan
    _TEXT ENDS

    I submitted a bug on connect like you suggested.

    Monday, September 01, 2014 6:11 AM
  • So, where does it stop? Did it reach ‘call __imp_tanf’?

    Monday, September 01, 2014 7:23 AM
  • I stepped into the assembly code and it indeed calls __imp_tanf(), and immediately throws the exception.


    • Edited by Feem Monday, September 01, 2014 9:23 AM
    Monday, September 01, 2014 9:19 AM
  • Try going to the disassembly view when the debugger stops and use the show next statement command from the disassembly view context menu.
    Monday, September 01, 2014 9:24 AM
    Moderator
  • I've encountered what I believe to be a compiler bug, but am unsure at the moment.

    float f = 8388608.0;
    float f2 = tan(f);//Crashes

    Any help is greatly appreciated. Thanks.

    Does this happen for smaller arguments? It is not easy to accurately calculate the trigonometric functions for large radian arguments.

    David Wilkinson | Visual C++ MVP

    Monday, September 01, 2014 9:44 AM
  • Does this happen for smaller arguments? It is not easy to accurately calculate the trigonometric functions for large radian arguments.

    It happens for 8388608 and above. The tan() documentation mentions something about losing precision. But this throws an exception that can only be caught with (...). The strange thing is that it's not present on Win32 builds, and not with VS2010 either. Only with float on x64 in VS2013.

    If I can't find a fix for this, I'll just write a custom tan function that is sin(x)/cos(x). Not ideal, but it can be a workaround for now.

    Thanks.

    Monday, September 01, 2014 10:04 AM
  • Does this happen for smaller arguments? It is not easy to accurately calculate the trigonometric functions for large radian arguments.

    It happens for 8388608 and above. The tan() documentation mentions something about losing precision.

    This loss of accuracy is not a minor matter. If you run the program

    #include <math.h>
    
    int main()
    {
    	float f = 8388608.1f;	
    	float f2 = tan(f);
    	
    	double d = 8388608.1;
    	double d2 = tan(d);
    
    	return 0;
    }

    you will find that f2 and d2 are completely different (no figures in common).



    David Wilkinson | Visual C++ MVP

    Monday, September 01, 2014 10:18 AM
  • I understand there's a loss of accuracy, and my program will be ok with that. However, I just need it not to crash. VS2010 seemed to handle this fine, so I need to find out why VS2013 is producing code that crashes.
    Monday, September 01, 2014 7:39 PM