KnowledgeBase Archive

An Archive of Early Microsoft KnowledgeBase Articles

View on GitHub

Q236349: FIX: Bad Code Generated by Global Optimization

Article: Q236349
Product(s): Microsoft C Compiler
Version(s): 6.0
Operating System(s): 
Keyword(s): kbCodeGen kbVC kbVC600 kbVC600bug kbDSupport kbNoUpdate
Last Modified: 11-FEB-2002

-------------------------------------------------------------------------------
The information in this article applies to:

- Microsoft Visual C++, 32-bit Enterprise Edition, version 6.0 
- Microsoft Visual C++, 32-bit Professional Edition, version 6.0 
- Microsoft Visual C++, 32-bit Learning Edition, version 6.0 
-------------------------------------------------------------------------------

SYMPTOMS
========

For builds that use global optimization (/Og), the condition of an if or while
statement in which two pointers are compared and incremented, can appear to be
false when in fact the condition is true. This problem occurs only under a
fairly narrow set of circumstances. See the sample code in the "More
Information" section for an example. Note that both the "maximize speed" (/O2)
and "minimize size" (/O1) optimizations are composite optimization switches that
include /Og.

CAUSE
=====

The optimizer has incorrectly removed a CMP instruction.

RESOLUTION
==========

Disable the global optimizations for the function, source file, or project in
question. Global optimizations can be disabled on a function-by-function basis
by using #pragma optimize. Global optimizations can be disabled for a source
file (or project) by adding /Og- to the file's (or project's) settings. See
"workaround #2" in the "More Information" section for an example of the #pragma
approach.

Another workaround is to move the increment (or decrement) of the pointers
outside the comparison. See "workaround #3" in the "More Information" section
for an example of this approach.

STATUS
======

Microsoft has confirmed this to be a bug in the Microsoft products listed at the
beginning of this article.

This problem was corrected in Microsoft Visual C++ .NET.

MORE INFORMATION
================

   /****************************************************/ 
   /* test.c - demonstrates Global Optimization Problem*/ 
   /* cl /c /FAs /Fa /Og test.c                        */ 
   /****************************************************/ 
  // #define WORKAROUND3 // Uncomment this line for workaround #3.

  struct MyStruct   {
         unsigned long m_len;
         unsigned char *m_lpData;   };
     typedef struct MyStruct *LPMyStruct;

  // #pragma optimize("g",off)  // Uncomment this line for workaround #2.
     short MyStructComp ( struct MyStruct *Arg1,struct MyStruct *Arg2)
     {
         unsigned long dwLen;
         unsigned char *str1 ,  *str2;
         dwLen = Arg1->m_len;
         str1 = Arg1->m_lpData;
         str2 = Arg2->m_lpData;
  	   while (dwLen--)
             if (*str1 < *str2)
                 return (-1);
  #ifndef WORKAROUND3 
  		   else if (*(str1++) > *(str2++))
                 return (1);
  #else
  		   else if (*str1 > *str2)
  		   {
  			   str1++;
  			   str2++;
  		   }
  #endif
         return (0);
   }
  // #pragma optimize("g",on) // Uncomment this line for workaround #2.

When the code is compiled with /Og, the MyStructComp function may return 0
(zero); the function should return 1. The code path for the "else if" condition
may not be taken, even when the condition is true. To see the reason why,
examine the following mixed assembly and source listing, generated by using /FAs
/Fa, (hand annotated):

  Test.asm generated by cl /c /FAs /Fa /Og Test.c:
  ------------------------------------------------

  ; 16   : 	   while (dwLen--)

  	mov	edx, edi
  	dec	edi
  	test	edx, edx
  	je	SHORT $L234
  	sub	esi, eax
  $L233:

  ; 17   :            if (*str1 < *str2)

  	mov	cl, BYTE PTR [eax]
  	mov	dl, BYTE PTR [esi+eax]
  	cmp	cl, dl
  	jb	SHORT $L242

  ; 19   : #ifndef WORKAROUND3 
  ; 20   : 		   else if (*(str1++) > *(str2++))

  	inc	eax        ;
  	ja	SHORT $L243 ; <== Note that this depends upon the zero flag
  	mov	ecx, edi    ; remaining from the cmp cl,dl above,  
  	dec	edi         ;but the inc eax instruction just before it may 
  	test	ecx, ecx    ;have affected the zero flag...
  	jne	SHORT $L233
  $L234:
  	pop	edi

  ; 22   : #else
  ; 23   : 		   else if (*str1 > *str2)
  ; 24   : 		   {
  ; 25   : 			   str1++;
  ; 26   : 			   str2++;
  ; 27   : 		   }
  ; 28   : #endif
  ; 29   :        return (0);

  	xor	ax, ax
  	pop	esi

  ; 30   :  }

  	pop	ebp
  	ret	0
  $L242:
  	pop	edi

  ; 18   :                return (-1);

  	or	ax, -1
  	pop	esi

  ; 30   :  }

  	pop	ebp
  	ret	0
  $L243:
  	pop	edi

  ; 21   :                return (1);

  	mov	ax, 1
  	pop	esi

  ; 30   :  }

Additional query words: Og CodeGen

======================================================================
Keywords          : kbCodeGen kbVC kbVC600 kbVC600bug kbDSupport kbNoUpdate 
Technology        : kbVCsearch kbAudDeveloper kbVC600 kbVC32bitSearch
Version           : :6.0
Issue type        : kbbug
Solution Type     : kbfix

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

THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY.

Copyright Microsoft Corporation 1986-2002.