> This is probably not such a better method.
It actually really, really is. At least from a technical perspective on x64. Having language-level lexical scoping of system-level exceptions is incredibly useful and once you've grokked how NT's trap handler, PE .xdata sections, prologues and epilogues all work in concert, signals just seem barbaric.
Here's an example trapping an access violation:
//
// Prefault the page.
//
TRY_MAPPED_MEMORY_OP {
TraceStore->Rtl->PrefaultPages(PrefaultMemoryMap->NextAddress, 1);
} CATCH_EXCEPTION_ACCESS_VIOLATION {
//
// This will happen if servicing the prefault off-core has taken longer
// for the originating core (the one that submitted the prefault work)
// to consume the entire memory map, then *another* memory map, which
// will retire the memory map backing this prefault address, which
// results in the address being invalidated, which results in an access
// violation when we try and read/prefault it from the thread pool.
//
TraceStore->Stats->AccessViolationsEncounteredDuringAsyncPrefault++;
}
Or an alignment fault:
FORCEINLINE
VOID
StoreXmm(
_In_ XMMWORD *Destination,
_In_ XMMWORD Source
)
{
TRY_SSE42_ALIGNED {
_mm_store_si128(Destination, Source);
} CATCH_EXCEPTION_ACCESS_VIOLATION {
_mm_storeu_si128(Destination, Source);
}
}
Or an illegal instruction:
FORCEINLINE
VOID
StoreYmmFallbackXmm(
_In_ PYMMWORD Destination,
_In_ PXMMWORD Destination128Low,
_In_ PXMMWORD Destination128High,
_In_ YMMWORD Source,
_In_ XMMWORD Source128Low,
_In_ XMMWORD Source128High
)
{
TRY_AVX {
TRY_AVX_ALIGNED {
_mm256_store_si256(Destination, Source);
} CATCH_EXCEPTION_ILLEGAL_INSTRUCTION {
Store2Xmm(
Destination128Low,
Destination128High,
Source128Low,
Source128High
);
}
} CATCH_EXCEPTION_ACCESS_VIOLATION {
_mm256_storeu_si256(Destination, Source);
}
Or a page fault that has occurred against a memory map backed file (because, say, the underlying network drive has been disconnected):
TRY_MAPPED_MEMORY_OP {
//
// Copy the caller's address range structure over.
//
__movsq((PDWORD64)NewAddressRange,
(PDWORD64)AddressRange,
sizeof(*NewAddressRange) >> 3);
//
// If there's an existing address range set, update its ValidTo
// timestamp.
//
if (TraceStore->AddressRange) {
TraceStore->AddressRange->Timestamp.ValidTo.QuadPart = (
Timestamp.QuadPart
);
}
//
// Update the trace store's address range pointer.
//
TraceStore->AddressRange = NewAddressRange;
} CATCH_STATUS_IN_PAGE_ERROR {
//
// We'll leak the address range we just allocated here, but a copy
// failure is indicative of much bigger issues (drive full, network
// map disappearing) than leaking ~32 bytes, so we don't attempt to
// roll back the allocation.
//
return FALSE;
}
Relevant macro definitions:
#define TRY_AVX __try
#define TRY_AVX_ALIGNED __try
#define TRY_AVX_UNALIGNED __try
#define TRY_SSE42 __try
#define TRY_SSE42_ALIGNED __try
#define TRY_SSE42_UNALIGNED __try
#define TRY_MAPPED_MEMORY_OP __try
#define CATCH_EXCEPTION_ILLEGAL_INSTRUCTION __except( \
GetExceptionCode() == EXCEPTION_ILLEGAL_INSTRUCTION ? \
EXCEPTION_EXECUTE_HANDLER : \
EXCEPTION_CONTINUE_SEARCH \
)
#define CATCH_EXCEPTION_ACCESS_VIOLATION __except( \
GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ? \
EXCEPTION_EXECUTE_HANDLER : \
EXCEPTION_CONTINUE_SEARCH \
)
#define CATCH_STATUS_IN_PAGE_ERROR __except( \
GetExceptionCode() == STATUS_IN_PAGE_ERROR ? \
EXCEPTION_EXECUTE_HANDLER : \
EXCEPTION_CONTINUE_SEARCH \
)