FIX: Direction Flag Is Not Cleared When an Exception Occurs

ID: Q106262


The information in this article applies to:
  • The C Run-Time (CRT), included with:
    • Microsoft Visual C++ 32-bit Edition, version 1.0


SYMPTOMS

Functions called in an exception handler can cause unexpected behavior such as access violations.


CAUSE

The direction flag bit may not be cleared when the exception occurs.


RESOLUTION

Clear the direction flag bit within either the exception handler or the termination handler. The sample code shown below illustrates clearing the flag in an exception handler.


STATUS

Microsoft has confirmed this to be a bug in the products listed at the beginning of this article. This problem was corrected in Visual C++ version 2.0.


MORE INFORMATION

On Intel processors, the direction flag bit in the flags register modifies the behavior of the string instructions. When the direction flag (DF) is 0 (zero), the string instructions operate on incrementally higher addresses. When DF is 1, the string instructions operate on incrementally lower addresses. On Intel chips, DF can be set to 1 with the STD instruction and can be cleared to 0 with the CLD instruction.

If a function sets DF to 1, it should clear DF before terminating. This allows all functions to make the assumption that DF is always 0.

All C run-time functions correctly clear DF upon termination. However, if an exception occurs before a function has a chance to clear DF, the flag will still be set when the exception handler is executed. This will cause code in the handler (which assumes that DF is 0) to fail. The manner in which the code fails depends on what the code is trying to do. In the example shown below, the printf() function called in the exception handler causes a memory access violation.

The problem can be worked around by clearing DF upon entry into an exception or termination handler. In the sample code shown below, the exception handler checks the value of the do_cld variable to determine whether or not it will clear DF. The do_cld variable is set to 0 or 1 depending on whether or not the CLD command-line argument is specified when the sample is run. To illustrate the problem with DF being set to 1, run the sample without any command-line arguments. To allow the sample to run correctly, specify the CLD command-line argument.

Sample Code


/* Compiler options needed: /D_X86_
*/ 

#include <windows.h>
#include <memory.h>
#include <string.h>
#include <stdio.h>

int handling = 0;
int do_cld = 0;

LONG MyFilter(LPEXCEPTION_POINTERS except_pointers)
{
    EXCEPTION_RECORD* er = except_pointers->ExceptionRecord;

    if (do_cld)
    {
        __asm cld
    }

    if (er->ExceptionCode==EXCEPTION_ACCESS_VIOLATION && handling==0)
    {
        handling = 1;
        printf("We're in the filter now and printing out a long"
               "string that's long enough to cause a problem\n");
        handling = 0;
        return EXCEPTION_EXECUTE_HANDLER;
    }
    else return EXCEPTION_CONTINUE_SEARCH;
}

int main(int argc,char** argv)
{
    if ( argc==2 && ((strcmp(argv[1],"cld")==0) ||
                     (strcmp(argv[1],"CLD")==0)))
        do_cld = 1;

    __try
    {
        printf("Starting the test\n");
        memcpy((void*)4,(void*)0,8);
        printf("After exception");
    }
    __except (MyFilter(GetExceptionInformation()))
    {
        printf("In the handler now\n");
    }

    return 0;
} 

Additional query words: 1.00 structured handling protection fault

Keywords : kbCRT kbVC
Version : winnt:
Platform : winnt
Issue type :


Last Reviewed: January 19, 2000
© 2000 Microsoft Corporation. All rights reserved. Terms of Use.