You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
324 lines
5.9 KiB
324 lines
5.9 KiB
// 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);
|
|
|
|
}
|
|
|
|
|
|
}
|