# include < iostream > # include < cstring > # include < conio.h > # include < windows.h > using namespace std ; # define If ( EXPR , T , A , B ) \ ( ( [ & ] ( ) - > T { if ( EXPR ) return ( A ) ; return ( B ) ; } ) ( ) ) void Report ( size_t x , size_t a , size_t b ) { cout < < x < < endl ; if ( x = = a & & x > b ) cout < < " OK, result is strlen(argv[0]) " < < endl ; else if ( x = = b & & x > a ) cout < < " OK, result is strlen(argv[1]) " < < endl ; else cout < < " Error - result is garbage " < < endl ; } int main ( int argc , char * * argv ) { if ( argc < 2 ) cout < < " Enter anything as first parameter " < < endl < < " If compiled with cl -EHsc, output will be " " max(strlen(argv[0]), strlen(argv[1])) " < < endl < < " If compiled with cl -EHsc -O2 under VS 2015 Update 3 x64, " " output will be a large garbage number " < < endl < < " If compiled with cl -EHsc -O2 under VS 2015 Update 3 x86, " " output may or may not be a small garbage number " < < endl ; else { cout < < " Opportunity to attach a debugger. " " Press any key to continue " < < endl ; _getch ( ) ; if ( IsDebuggerPresent ( ) ) DebugBreak ( ) ; size_t a = strlen ( argv [ 0 ] ) ; size_t b = strlen ( argv [ 1 ] ) ; Report ( If ( a > b , size_t , a , b ) , a , b ) ; } return 0 ; } /* Problem disassembly on x64: Optimizer appears to recognize that variables "a" and "b" never need to be stored on stack, so it gives them both a dummy stack location [rsp+40h]. This location is never written to. But code generated for the If lambda returns values from the dummy stack location. size_t a = (size_t) strlen(argv[0]); 00007FF60F43A41F mov rax,qword ptr [rbx] 00007FF60F43A422 or r8,0FFFFFFFFFFFFFFFFh 00007FF60F43A426 mov rdx,r8 00007FF60F43A429 nop dword ptr [rax] 00007FF60F43A430 inc rdx 00007FF60F43A433 cmp byte ptr [rax+rdx],0 00007FF60F43A437 jne main+0B0h (07FF60F43A430h) size_t b = (size_t) strlen(argv[1]); 00007FF60F43A439 mov rax,qword ptr [rbx+8] 00007FF60F43A43D nop dword ptr [rax] 00007FF60F43A440 inc r8 00007FF60F43A443 cmp byte ptr [rax+r8],0 00007FF60F43A448 jne main+0C0h (07FF60F43A440h) Report(If(a > b, size_t, a, b), a, b); 00007FF60F43A44A cmp rdx,r8 00007FF60F43A44D lea rax,[rsp+40h] 00007FF60F43A452 lea rcx,[rsp+40h] 00007FF60F43A457 cmovbe rcx,rax 00007FF60F43A45B mov rcx,qword ptr [rcx] 00007FF60F43A45E call Report (07FF60F4292F2h) Example output: C:\Temp>VsUpdate3.exe a Opportunity to attach a debugger. Press any key to continue 140694781775872 Error - result is garbage */

Solution?

-d2SSAOptimizer-

size_t a = strlen(argv[0]); 00007FF7B48C9FAF mov rax,qword ptr [rbx] 00007FF7B48C9FB2 or r8,0FFFFFFFFFFFFFFFFh 00007FF7B48C9FB6 mov rdx,r8 00007FF7B48C9FB9 nop dword ptr [rax] 00007FF7B48C9FC0 inc rdx 00007FF7B48C9FC3 cmp byte ptr [rax+rdx],0 00007FF7B48C9FC7 jne main+0B0h (07FF7B48C9FC0h) size_t b = strlen(argv[1]); 00007FF7B48C9FC9 mov rax,qword ptr [rbx+8] 00007FF7B48C9FCD nop dword ptr [rax] 00007FF7B48C9FD0 inc r8 00007FF7B48C9FD3 cmp byte ptr [rax+r8],0 00007FF7B48C9FD8 jne main+0C0h (07FF7B48C9FD0h) Report(If(a > b, size_t, a, b), a, b); 00007FF7B48C9FDA cmp rdx,r8 00007FF7B48C9FDD mov rcx,r8 00007FF7B48C9FE0 cmova rcx,rdx 00007FF7B48C9FE4 call Report (07FF7B48B92F2h)

Update blues

After uninstalling Update 3, the development environment would no longer start; it would crash after displaying the splash screen.

The Microsoft pages that claim to offer the Update 2 installer perform a bait-and-switch, and link to the Update 3 installer instead.

I downloaded the full Update 2 ISO from MSDN Subscriber Downloads, only to find that it goes online, as well as consults locally cached data, and then also pushes Update 3.

When I saw that Visual Studio 2015 Update 3 includes a brand new optimizer, my first thought was: yikes, I wonder how well this is tested. It can't be very mature code.Well – it isn't. The following reproduces a code generation bug involving the optimizer and a lambda that captures local variables by reference:According to the MSDN blog post that introduces the new optimizer , it can be disabled using the undocumented flag:The above snippet runs properly when compiled with this flag. The disassembly is:Interestingly – the code looks cleaner and more optimizedthe SSA Optimizer. :-)I first tried to work around this issue by downgrading back to Update 2. This is not for the faint-hearted:This isthe Update 3 installer took 3 hours and 50 minutes to run, because it turns out it downloads 1.7 GB during the installation on-demand – and it does so much slower than it would have taken to download the full 6 GB ISO, all while preventing getting any work done due to installation in progress.Fortunately, comments suggest the optimizer issue might be fixed within a week, so that this will no longer be an obstacle.