Figure 5 Custom Error Handler /*/////////////////////////////////////////////////////////////////////
FUNCTION : HandleRTCFailure
DESCRIPTION :
The Runtime Checking (RTC) handler function when NOT running
under the debugger. When running under a debugger, this function
is ignored. Consequently, you can't debug this puppy at all!
PARAMETERS :
iError - The type of error as reported through _RTC_SetErrorType.
Note that I don't use this parameter.
szFile - The source file name where the error occurred.
iLine - The line where the error occurred.
szModule - The module where the error occurred.
szFormat - The printf-style format string for the variable
parameters.
Note that I don't use this parameter except to get the
values out of the variables parameters.
... - The "variable" length parameter list. There are only
two values passed here. The first is the RTC Error
number.
1 = /RTCc
2 = /RTCs
3 = /RTCu
The second is the string that appears when the debugger
shows the message. This is only important for /RTCs and
/RTCu as those show the variable where the problem
happened.
RETURN VALUES :
TRUE - Cause a _DebugBreak to be called after this function
returns.
FALSE - Continue execution.
/////////////////////////////////////////////////////////////////////*/
// Turn off run time checks for this function so I don't go recursive
// on myself.
#pragma runtime_checks("", off)
// The critical section to protect against reentrancy in the
// HandleRTCFailure function.
CRITICAL_SECTION g_csRTCLock ;
int HandleRTCFailure ( int /*iError*/ ,
const char * szFile ,
int iLine ,
const char * szModule ,
const char * szFormat ,
... )
{
// Just say no to reentrant code!
EnterCriticalSection ( &g_csRTCLock ) ;
// Get the two variable length parameters. I guess they plan on
// adding a ton of these RTC checks in the future.
va_list vl ;
va_start ( vl , szFormat ) ;
// The first one is the number of the error that occured.
_RTC_ErrorNumber RTCErrNum = va_arg ( vl , _RTC_ErrorNumber ) ;
// The second is the additional description of the error.
char * szErrorVariableDesc = va_arg ( vl , char * ) ;
va_end ( vl ) ;
TCHAR szBuff [ 512 ] ;
// Get the error description text based off the error number.
const char *szErr = _RTC_GetErrDesc ( RTCErrNum ) ;
// Make sure szFile and szModule have something in them.
if ( NULL == szFile )
{
szFile = "Unknown File" ;
}
if ( NULL == szModule )
{
szModule = "Unknown Module" ;
}
// If it's any error other than /RTCc, I can show some cool info
// that includes the variable in question!
if ( 1 != RTCErrNum )
{
_stprintf ( szBuff ,
_T ( "%S\n%S\nLine #%d\nFile:%S\nModule:%S" ) ,
szErr ,
szErrorVariableDesc ,
iLine ,
szFile ,
szModule ) ;
}
else
{
// Build the string.
_stprintf ( szBuff ,
_T ( "%S\nLine #%d\nFile:%S\nModule:%S" ) ,
szErr ,
iLine ,
szFile ,
szModule ) ;
}
int iRes = TRUE ;
if ( IDYES == MessageBox ( GetForegroundWindow ( ) ,
szBuff ,
_T ( "Run Time Check Failure" ) ,
MB_YESNO ) )
{
// Returning TRUE means DebugBreak will happen when this
// function returns.
iRes = TRUE ;
}
else
{
iRes = FALSE ;
}
// Pop out of the lock.
LeaveCriticalSection ( &g_csRTCLock ) ;
return ( iRes ) ;
}
#pragma runtime_checks("", restore)
Figure 6 Optimization on Several Files
Optimizations.cpp - The Main File // CL: /GL /O1 /Ob1 /Oy /GF /EHsc /Gy
//////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "AnotherModule.h"
#include "YetAnother.h"
void wmain ( void )
{
int i = 1 ;
int j = 2 ;
InitializeVariables ( &i , &j ) ;
wprintf ( L"i = %d, j = %d\n" , i , j ) ;
i = InitializeTLSValues ( ) ;
wprintf ( L"InitializeLTSValues returned %d\n" , i ) ;
i = ReturnValue ( ) ;
wprintf ( L"ReturnValue returned %d\n" , i ) ;
}
AnotherModule.cpp // CL: /GL /O1 /Ob1 /Oy /GF /EHsc /Gy
//////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "AnotherModule.h"
__declspec ( thread ) int g_TLSInteger = 0 ;
void InitializeVariables ( int * i , int * j )
{
*i = 0xA ;
*j = 0xB ;
}
int InitializeTLSValues ( void )
{
g_TLSInteger = 1 ;
return ( g_TLSInteger ) ;
}
YetAnother.cpp // CL: /GL /O1 /Ob2 /Oy /GF /EHsc /Gy
//////////////////////////////////////////////////////////////
#include "stdafx.h"
int ReturnValue ( void )
{
return ( 0xBB ) ;
}
Figure 7 wmain Disassembly for Version 6.0 wmain:
00401000: push ebp
00401001: mov ebp,esp
00401003: push ecx
00401004: push ecx
00401005: lea eax,dword ptr [ebp-008h]
00401008: push esi
00401009: push eax
0040100A: lea eax,dword ptr [ebp-004h]
0040100D: push eax
0040100E: mov dword ptr [ebp-004h],00000001h
00401015: mov dword ptr [ebp-008h],00000002h
0040101C: call InitializeVariables
00401021: pop ecx
00401022: mov esi,dword ptr [_imp__wprintf]
00401028: pop ecx
00401029: push dword ptr [ebp-008h]
0040102C: push dword ptr [ebp-004h]
0040102F: push 'string'
00401034: call esi
00401036: add esp,00Ch
00401039: call InitializeTLSValues
0040103E: push eax
0040103F: push 'string'
00401044: mov dword ptr [ebp-004h],eax
00401047: call esi
00401049: pop ecx
0040104A: pop ecx
0040104B: call ReturnValue
00401050: push eax
00401051: push 'string'
00401056: mov dword ptr [ebp-004h],eax
00401059: call esi
0040105B: pop ecx
0040105C: pop ecx
0040105D: pop esi
0040105E: leave
0040105F: ret
Figure 8 wmain Disassembly for Version 7.0 wmain:
00401000: push ebp
00401001: mov ebp,esp
00401003: push ecx
00401004: push ecx
00401005: lea eax,dword ptr [ebp-004h]
00401008: push esi
00401009: push eax
0040100A: lea eax,dword ptr [ebp-008h]
0040100D: mov dword ptr [ebp-008h],00000001h
00401014: mov dword ptr [ebp-004h],00000002h
0040101B: call InitializeVariables
00401020: push dword ptr [ebp-004h]
00401023: mov esi,dword ptr [_imp__wprintf]
00401029: push dword ptr [ebp-008h]
0040102C: push 'string'
00401031: call esi
00401033: call InitializeTLSValues
00401038: push eax
00401039: push 'string'
0040103E: call esi
00401040: push 000000BBh
00401045: push 'string'
0040104A: call esi
0040104C: add esp,020h
0040104F: xor eax,eax
00401051: pop esi
00401052: leave
00401053: ret
|