|
|
// options: /Oxs /EHa /GX
#include "stdio.h"
#include "windows.h"
typedef void (*PEXCEPTION_TEST) (void (*p)(void), volatile int *State); typedef struct _EXCEPTION_TEST_INFO { PEXCEPTION_TEST ExceptionTest; int State; } EXCEPTION_TEST_INFO;
void TestUnwindFromRecoveryCodeInFinally (void (*p)(void), volatile int *State); void TestUnwindFromRecoveryCodeTryFinallyBlock (void (*p)(void), volatile int *State); void TestUnwindFromRecoverCodeDuplicatesScopeEntries (void (*p)(void), volatile int *State); void TestUnwindFromInfiniteLoop (void (*p)(void), volatile int *State); void TestExtendedTrySCopeForRecoveryCode (void (*p)(void), volatile int *State); void TestIPStatesCoverRecoveryCode (void (*p)(void), volatile int *State); void TestNestedFinally (void (*p)(void), volatile int *State); EXCEPTION_TEST_INFO ExceptionTests[] = { {TestNestedFinally, 3 }, {TestExtendedTrySCopeForRecoveryCode, 2}, {TestIPStatesCoverRecoveryCode, 2}, {TestUnwindFromInfiniteLoop, 2}, {TestUnwindFromRecoverCodeDuplicatesScopeEntries, 4}, {TestUnwindFromRecoveryCodeTryFinallyBlock, 1}, {TestUnwindFromRecoveryCodeInFinally, 1}, };
const MaxExceptionTests = sizeof(ExceptionTests) / sizeof(EXCEPTION_TEST_INFO);
//
// Test that recovery code is covered by extended try scope.
void TestExtendedTrySCopeForRecoveryCode (void (*p)(void), volatile int *State)
{
__try
{ if ((int)p != 1)
{
(*p)();
}
} __finally
{
++*State++; }
}
// VSWhidbey:14611
// Test that recovery code for finally block is covered by full pdata range.
// Inspect code to be sure LD.S/CHK is generated in funclet for (*p).
// Failure will cause bad unwind and program will fail.
void TestUnwindFromRecoveryCodeInFinally (void (*p)(void), volatile int *State)
{
__try
{ // transfer to finally funclet
(*p)();
}
__finally
{
// cause speculative load of p (ld.s p) and chk to fail. If recovery code isn't covered by pdata range of
// funclet unwind will fail.
if ((int)p != 1)
{
(*p)();
}
}
}
// VSWhidbey:10415
// Test that if the extended scope table entry ends at the beginning address of finally funclet that
// the runtime (CRT, RTL) doesn't use it's address as the NextPC after invoking the finally. This leads
// to the finally being called twice and unwinding failing. This bug fixed in CRT and RTL.
void TestUnwindFromRecoveryCodeTryFinallyBlock (void (*p)(void), volatile int *State)
{
int rg[5];
rg[1] = 0; rg[2] = 0; rg[3] = 0;
rg[3] = 0xC0000005;
__try
{
if ((int)p != 1)
{
(*p)();
}
}
__finally
{ RaiseException( rg[3], 0, 0, 0 );
}
}
// VSWhidbey:10415
// Test that nested scope table entries are duplicated for recover code.
// Failure will cause finally to be called in wrong order
void TestUnwindFromRecoverCodeDuplicatesScopeEntries (void (*p)(void), volatile int *State)
{
int rg[5];
rg[1] = 0; rg[2] = 0; rg[3] = 0;
__try
{
__try { rg[3] = 0xC0000005;
if ((int)p != 1)
{
(*p)();
}
}
__finally
{
++*State;
__try {
RaiseException( rg[3], 0, 0, 0 );
} __finally
{ ++*State;
} } } __finally {
++*State;
} }
// VSWhidbeg:13074
// Test that infinite loop covers the entire try/except body range.
void TestUnwindFromInfiniteLoop (void (*p)(void), volatile int *State) { __try {
if (!State) { ++*State; __leave;
} while (1) {
p();
} }__except(1){
++*State; p(); } }
// VSWhidbey:15700 - Test Extended IP States cover Recovery Code
void TestIPStatesCoverRecoveryCode (void (*p)(void), volatile int *State) {
int rg[5];
rg[1] = 0; rg[2] = 0; rg[3] = 0;
try {
try
{
rg[3] = 0xC0000005;
if ((int)p != 1)
{
(*p)();
}
}
catch (...) { ++*State; throw; }
} catch (...) { ++*State; } }
// VSWhidbey:14606
void TestNestedFinally (void (*p)(void), volatile int *State) { // __try {
__try { *State += *State / *State; } __finally { if (_abnormal_termination()) ++*State; __try {
// This thing is screwed up - IA64 is wrong, the AMD64 compiler chokes, x86's helper routine is just messed up.
if (_abnormal_termination()) ++*State; } __finally { if (_abnormal_termination()) // On x86 only, this is true, if the outer one is true, or if this on is true
++*State; } } // } __except(1){}
}
void main (void)
{ int i = 0; volatile int State = 0;
printf("Number of tests = %d\n",MaxExceptionTests); for (i = 0; i < MaxExceptionTests; i++) { __try
{
State = 0; ExceptionTests[i].ExceptionTest(0, &State);
} __except( 1 ) { ++State; }
if (ExceptionTests[i].State == State) printf("#%d pass\n", i+1); else printf("#%d fail, State == %d\n", i+1, State);
}
}
|