64-bit compiler generates bad jump - by Johan Torp

Status : 

  Fixed<br /><br />
		This item has been fixed in the current or upcoming version of this product.<br /><br />
		A more detailed explanation for the resolution of this particular item may have been provided in the comments section.


2
0
Sign in
to vote
ID 823570 Comments
Status Closed Workarounds
Type Bug Repros 0
Opened 2/25/2014 6:17:27 AM
Access Restriction Public

Description

The loop branches with JE without doing a prior compare/test first. The clearing XOR sets ZF, MOV and BTR doesn't affect it, then JE jumps past the for loop ignoring the loop condition.

The bug manifests itself in the 64-bit compiler when /O2 optimizations and exceptions are enabled. It's present in MSVC 2010/12/13 but not in the 32-bit compilers. 

======== main.cpp ========
#include <stdio.h>

// Defined in foo.cpp
void nothing();
extern int x;

struct dtor
{
	~dtor() { nothing(); }
};

void main()
{
	x = 10;
	nothing();
	
	int i=0;
	int e = x & 0x7fffffff;
	for (; i != e; ++i)
	{
		dtor d;

		if (!e && i)
			break;
	}
	
	printf("i:%d e:%d \n", i, e);
}
======== foo.cpp ========
void nothing() {}
int x;
======== build ========
cl /O2 /EHsc foo.cpp main.cpp
======== main.cod snippet========
; 16   : 	
; 17   : 	int i=0;

  00028	33 db		 xor	 ebx, ebx

; 18   : 	int e = x & 0x7fffffff;

  0002a	8b 3d 00 00 00
	00		 mov	 edi, DWORD PTR ?x@@3HA	; x
  00030	0f ba f7 1f	 btr	 edi, 31
$LN18@main:

; 19   : 	for (; i != e; ++i)

  00034	74 18		 je	 SHORT $LN17@main

; 20   : 	{
; 21   : 		dtor d;
; 22   : 
; 23   : 		if (!e && i)

  00036	85 ff		 test	 edi, edi
  00038	75 04		 jne	 SHORT $LN1@main
  0003a	85 db		 test	 ebx, ebx
  0003c	75 0b		 jne	 SHORT $LN13@main
$LN1@main:

; 25   : 	}

  0003e	e8 00 00 00 00	 call	 ?nothing@@YAXXZ		; nothing

; 19   : 	for (; i != e; ++i)

  00043	ff c3		 inc	 ebx
  00045	3b df		 cmp	 ebx, edi
  00047	eb eb		 jmp	 SHORT $LN18@main
$LN13@main:

; 24   : 			break;

  00049	e8 00 00 00 00	 call	 ?nothing@@YAXXZ		; nothing
$LN17@main:

; 26   : 	
; 27   : 	printf("i:%d e:%d \n", i, e);

====================

...and some credits :)
- Tobias Bexelius and Andreas Jones for finding this 
- Christopher Bergqvist for the first part of the tedious boiling down process of this very volatile bug

An ugly and somewhat shaky workaround until this is fixed is using "x - (x & ~0x7fffffff)" instead of "x & 0x7fffffff". It makes the compiler emit a SUB instruction that sets the ZF flag in place of the test/compare it fails to emit.
Sign in to post a comment.
Posted by Microsoft on 5/27/2014 at 11:54 AM
Hi, this bug has been identified and will be fixed in next VS release.
Thank you for your feedback.
Posted by Microsoft on 2/25/2014 at 6:40 PM
Thank you for submitting feedback on Visual Studio and .NET Framework. Your issue has been reproduced and has been routed to the appropriate VS development team for review. We will contact you if we require any additional information. If you require immediate assistance with this issue, please contact product support at http://support.microsoft.com/ph/1117.
Posted by Microsoft on 2/25/2014 at 6:50 AM
Thank you for your feedback, we are currently reviewing the issue you have submitted. If this issue is urgent, please contact support directly(http://support.microsoft.com)