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 :