From 15049b2cf01a4dc5e3d24875a428df60a9c9f18a Mon Sep 17 00:00:00 2001 From: MiroKaku <50670906+MiroKaku@users.noreply.github.com> Date: Wed, 9 Nov 2022 16:23:11 +0800 Subject: [PATCH] fix: #15, update crt. --- src/crt/i386/trnsctrl.cpp | 10 +- src/crt/stl/excptptr.cpp | 10 +- src/crt/stl/vector_algorithms.cpp | 1141 ++++++++++++++++++++++-- src/crt/stl/xdtest.cpp | 4 - src/crt/stl/xfdtest.cpp | 4 - src/crt/stl/xldtest.cpp | 4 - src/crt/stl/xmath.hpp | 51 +- src/crt/stl/xrngdev.cpp | 15 +- src/crt/stl/xxxprec.hpp | 86 +- src/crt/vcruntime/ehhelpers.h | 2 +- src/crt/vcruntime/ehvccctr.cpp | 26 +- src/crt/vcruntime/ehvcccvb.cpp | 22 +- src/crt/vcruntime/ehvecctr.cpp | 22 +- src/crt/vcruntime/ehveccvb.cpp | 22 +- src/crt/vcruntime/ehvecdtr.cpp | 27 +- src/crt/vcruntime/frame.cpp | 62 +- src/crt/vcruntime/gs_report.cpp | 8 +- src/crt/vcruntime/guard_support.cpp | 36 +- src/crt/vcruntime/initialization.cpp | 2 +- src/crt/vcruntime/internal_shared.h | 130 ++- src/crt/vcruntime/riscchandler.cpp | 316 ++++++- src/crt/vcruntime/risctrnsctrl.cpp | 13 +- src/crt/vcruntime/undname.cxx | 541 ++++++----- src/crt/vcruntime/vcruntime_internal.h | 2 +- src/crt/vcruntime/vcstartup_internal.h | 1 - src/version.txt | 4 +- 26 files changed, 2012 insertions(+), 549 deletions(-) diff --git a/src/crt/i386/trnsctrl.cpp b/src/crt/i386/trnsctrl.cpp index 768c8b5..cd4bd5a 100644 --- a/src/crt/i386/trnsctrl.cpp +++ b/src/crt/i386/trnsctrl.cpp @@ -209,7 +209,7 @@ extern "C" _VCRTIMP __declspec(naked) DECLSPEC_GUARD_SUPPRESS EXCEPTION_DISPOSIT EHTRACE_FMT1("pRN = 0x%p", pRN); - result = __InternalCxxFrameHandler( pExcept, pRN, (PCONTEXT)pContext, pDC, pFuncInfo, 0, nullptr, FALSE ); + result = __InternalCxxFrameHandlerWrapper( pExcept, pRN, (PCONTEXT)pContext, pDC, pFuncInfo, 0, nullptr, FALSE ); EHTRACE_HANDLER_EXIT(result); @@ -263,7 +263,7 @@ extern "C" _VCRTIMP __declspec(naked) DECLSPEC_GUARD_SUPPRESS EXCEPTION_DISPOSIT EHTRACE_FMT1("pRN = 0x%p", pRN); - result = __InternalCxxFrameHandler( pExcept, pRN, (PCONTEXT)pContext, pDC, pFuncInfo, 0, nullptr, FALSE ); + result = __InternalCxxFrameHandlerWrapper( pExcept, pRN, (PCONTEXT)pContext, pDC, pFuncInfo, 0, nullptr, FALSE ); EHTRACE_HANDLER_EXIT(result); @@ -313,7 +313,7 @@ extern "C" _VCRTIMP __declspec(naked) DECLSPEC_GUARD_SUPPRESS EXCEPTION_DISPOSIT EHTRACE_FMT1("pRN = 0x%p", pRN); - result = __InternalCxxFrameHandler( pExcept, pRN, (PCONTEXT)pContext, pDC, pFuncInfo, 0, nullptr, FALSE ); + result = __InternalCxxFrameHandlerWrapper( pExcept, pRN, (PCONTEXT)pContext, pDC, pFuncInfo, 0, nullptr, FALSE ); EHTRACE_HANDLER_EXIT(result); @@ -442,7 +442,7 @@ extern "C" EXCEPTION_DISPOSITION __cdecl _CatchGuardHandler( __security_check_cookie(pRN->RandomCookie ^ (UINT_PTR)pRN); EXCEPTION_DISPOSITION result = - __InternalCxxFrameHandler( pExcept, + __InternalCxxFrameHandlerWrapper( pExcept, pRN->pRN, (PCONTEXT)pContext, nullptr, @@ -667,7 +667,7 @@ extern "C" EXCEPTION_DISPOSITION __cdecl _TranslatorGuardHandler( // // Check for a handler: // - __InternalCxxFrameHandler( pExcept, pRN->pRN, (PCONTEXT)pContext, nullptr, pRN->pFuncInfo, pRN->CatchDepth, pRN->pMarkerRN, TRUE ); + __InternalCxxFrameHandlerWrapper( pExcept, pRN->pRN, (PCONTEXT)pContext, nullptr, pRN->pFuncInfo, pRN->CatchDepth, pRN->pMarkerRN, TRUE ); if (!pRN->DidUnwind) { // diff --git a/src/crt/stl/excptptr.cpp b/src/crt/stl/excptptr.cpp index 67f762a..b3afa3a 100644 --- a/src/crt/stl/excptptr.cpp +++ b/src/crt/stl/excptptr.cpp @@ -37,6 +37,10 @@ extern "C" _CRTIMP2 void* __cdecl __AdjustPointer(void*, const PMD&); // defined using namespace std; +#ifndef _MSVC_NOOP_DTOR +#define _MSVC_NOOP_DTOR [[msvc::noop_dtor]] +#endif + namespace { #if defined(_M_CEE_PURE) template @@ -53,10 +57,10 @@ namespace { constexpr _Constexpr_excptptr_immortalize_impl() noexcept : _Storage{} {} - _Constexpr_excptptr_immortalize_impl(const _Constexpr_excptptr_immortalize_impl&) = delete; + _Constexpr_excptptr_immortalize_impl(const _Constexpr_excptptr_immortalize_impl&) = delete; _Constexpr_excptptr_immortalize_impl& operator=(const _Constexpr_excptptr_immortalize_impl&) = delete; - [[msvc::noop_dtor]] ~_Constexpr_excptptr_immortalize_impl() { + _MSVC_NOOP_DTOR ~_Constexpr_excptptr_immortalize_impl() { // do nothing, allowing _Ty to be used during shutdown } }; @@ -80,7 +84,7 @@ namespace { _Ty& _Immortalize() { // return a reference to an object that will live forever static once_flag _Flag; alignas(_Ty) static unsigned char _Storage[sizeof(_Ty)]; - if (_Execute_once(_Flag, _Immortalize_impl<_Ty>, &_Storage) == 0) { + if (!_Execute_once(_Flag, _Immortalize_impl<_Ty>, &_Storage)) { // _Execute_once should never fail if the callback never fails _STD terminate(); } diff --git a/src/crt/stl/vector_algorithms.cpp b/src/crt/stl/vector_algorithms.cpp index 7e69cce..2a52b09 100644 --- a/src/crt/stl/vector_algorithms.cpp +++ b/src/crt/stl/vector_algorithms.cpp @@ -10,53 +10,77 @@ #error _M_CEE_PURE should not be defined when compiling vector_algorithms.cpp. #endif -#if defined(_M_IX86) || defined(_M_X64) +#if (defined(_M_IX86) || defined(_M_X64)) && !defined(_M_ARM64EC) -#if defined(_M_ARM64EC) -#include -#else // defined(_M_ARM64EC) +#include #include #include #include -#endif // defined(_M_ARM64EC) #include extern "C" long __isa_enabled; -template -static void _Reverse_tail(_BidIt _First, _BidIt _Last) noexcept { - for (; _First != _Last && _First != --_Last; ++_First) { - const auto _Temp = *_First; - *_First = *_Last; - *_Last = _Temp; +#ifndef _DEBUG +#pragma optimize("t", on) // Override /Os with /Ot for this TU +#endif // !_DEBUG + +namespace { + bool _Use_avx2() noexcept { + return __isa_enabled & (1 << __ISA_AVAILABLE_AVX2); } -} -template -static void _Reverse_copy_tail(_BidIt _First, _BidIt _Last, _OutIt _Dest) noexcept { - while (_First != _Last) { - *_Dest++ = *--_Last; + bool _Use_sse42() noexcept { + return __isa_enabled & (1 << __ISA_AVAILABLE_SSE42); } -} -static size_t _Byte_length(const void* _First, const void* _Last) noexcept { - return static_cast(_Last) - static_cast(_First); -} + bool _Use_sse2() noexcept { +#ifdef _M_IX86 + return __isa_enabled & (1 << __ISA_AVAILABLE_SSE2); +#else + return true; +#endif // _M_IX86 + } -static void _Advance_bytes(void*& _Target, ptrdiff_t _Offset) noexcept { - _Target = static_cast(_Target) + _Offset; -} + template + void _Reverse_tail(_BidIt _First, _BidIt _Last) noexcept { + for (; _First != _Last && _First != --_Last; ++_First) { + const auto _Temp = *_First; + *_First = *_Last; + *_Last = _Temp; + } + } -static void _Advance_bytes(const void*& _Target, ptrdiff_t _Offset) noexcept { - _Target = static_cast(_Target) + _Offset; -} + template + void _Reverse_copy_tail(_BidIt _First, _BidIt _Last, _OutIt _Dest) noexcept { + while (_First != _Last) { + *_Dest++ = *--_Last; + } + } + + size_t _Byte_length(const void* _First, const void* _Last) noexcept { + return static_cast(_Last) - static_cast(_First); + } + + void _Advance_bytes(void*& _Target, ptrdiff_t _Offset) noexcept { + _Target = static_cast(_Target) + _Offset; + } + + void _Advance_bytes(const void*& _Target, ptrdiff_t _Offset) noexcept { + _Target = static_cast(_Target) + _Offset; + } +} // unnamed namespace extern "C" { +// Must be in sync with _Min_max_element_t in +struct _Min_max_element_t { + const void* _Min; + const void* _Max; +}; + __declspec(noalias) void __cdecl __std_swap_ranges_trivially_swappable_noalias( void* _First1, void* _Last1, void* _First2) noexcept { -#if !defined(_M_ARM64EC) constexpr size_t _Mask_32 = ~((static_cast(1) << 5) - 1); - if (_Byte_length(_First1, _Last1) >= 32 && _bittest(&__isa_enabled, __ISA_AVAILABLE_AVX2)) { + if (_Byte_length(_First1, _Last1) >= 32 && _Use_avx2()) { const void* _Stop_at = _First1; _Advance_bytes(_Stop_at, _Byte_length(_First1, _Last1) & _Mask_32); do { @@ -68,14 +92,9 @@ __declspec(noalias) void __cdecl __std_swap_ranges_trivially_swappable_noalias( _Advance_bytes(_First2, 32); } while (_First1 != _Stop_at); } -#endif // !defined(_M_ARM64EC) constexpr size_t _Mask_16 = ~((static_cast(1) << 4) - 1); - if (_Byte_length(_First1, _Last1) >= 16 -#ifdef _M_IX86 - && _bittest(&__isa_enabled, __ISA_AVAILABLE_SSE2) -#endif // _M_IX86 - ) { + if (_Byte_length(_First1, _Last1) >= 16 && _Use_sse2()) { const void* _Stop_at = _First1; _Advance_bytes(_Stop_at, _Byte_length(_First1, _Last1) & _Mask_16); do { @@ -108,8 +127,8 @@ __declspec(noalias) void __cdecl __std_swap_ranges_trivially_swappable_noalias( const void* _Stop_at = _First1; _Advance_bytes(_Stop_at, _Byte_length(_First1, _Last1) & _Mask_4); do { - const unsigned long _Left = *static_cast(_First1); - const unsigned long _Right = *static_cast(_First2); + const unsigned long _Left = *static_cast(_First1); + const unsigned long _Right = *static_cast(_First2); *static_cast(_First1) = _Right; *static_cast(_First2) = _Left; _Advance_bytes(_First1, 4); @@ -137,8 +156,7 @@ void* __cdecl __std_swap_ranges_trivially_swappable(void* _First1, void* _Last1, } __declspec(noalias) void __cdecl __std_reverse_trivially_swappable_1(void* _First, void* _Last) noexcept { -#if !defined(_M_ARM64EC) - if (_Byte_length(_First, _Last) >= 64 && _bittest(&__isa_enabled, __ISA_AVAILABLE_AVX2)) { + if (_Byte_length(_First, _Last) >= 64 && _Use_avx2()) { const __m256i _Reverse_char_lanes_avx = _mm256_set_epi8( // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); @@ -159,9 +177,8 @@ __declspec(noalias) void __cdecl __std_reverse_trivially_swappable_1(void* _Firs _Advance_bytes(_First, 32); } while (_First != _Stop_at); } -#endif // !defined(_M_ARM64EC) - if (_Byte_length(_First, _Last) >= 32 && _bittest(&__isa_enabled, __ISA_AVAILABLE_SSE42)) { + if (_Byte_length(_First, _Last) >= 32 && _Use_sse42()) { const __m128i _Reverse_char_sse = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); const void* _Stop_at = _First; _Advance_bytes(_Stop_at, _Byte_length(_First, _Last) >> 5 << 4); @@ -181,8 +198,7 @@ __declspec(noalias) void __cdecl __std_reverse_trivially_swappable_1(void* _Firs } __declspec(noalias) void __cdecl __std_reverse_trivially_swappable_2(void* _First, void* _Last) noexcept { -#if !defined(_M_ARM64EC) - if (_Byte_length(_First, _Last) >= 64 && _bittest(&__isa_enabled, __ISA_AVAILABLE_AVX2)) { + if (_Byte_length(_First, _Last) >= 64 && _Use_avx2()) { const __m256i _Reverse_short_lanes_avx = _mm256_set_epi8( // 1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14, // 1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14); @@ -201,9 +217,8 @@ __declspec(noalias) void __cdecl __std_reverse_trivially_swappable_2(void* _Firs _Advance_bytes(_First, 32); } while (_First != _Stop_at); } -#endif // !defined(_M_ARM64EC) - if (_Byte_length(_First, _Last) >= 32 && _bittest(&__isa_enabled, __ISA_AVAILABLE_SSE42)) { + if (_Byte_length(_First, _Last) >= 32 && _Use_sse42()) { const __m128i _Reverse_short_sse = _mm_set_epi8(1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14); const void* _Stop_at = _First; _Advance_bytes(_Stop_at, _Byte_length(_First, _Last) >> 5 << 4); @@ -223,30 +238,23 @@ __declspec(noalias) void __cdecl __std_reverse_trivially_swappable_2(void* _Firs } __declspec(noalias) void __cdecl __std_reverse_trivially_swappable_4(void* _First, void* _Last) noexcept { -#if !defined(_M_ARM64EC) - if (_Byte_length(_First, _Last) >= 64 && _bittest(&__isa_enabled, __ISA_AVAILABLE_AVX2)) { + if (_Byte_length(_First, _Last) >= 64 && _Use_avx2()) { const void* _Stop_at = _First; _Advance_bytes(_Stop_at, _Byte_length(_First, _Last) >> 6 << 5); + const __m256i _Shuf = _mm256_set_epi32(0, 1, 2, 3, 4, 5, 6, 7); do { _Advance_bytes(_Last, -32); const __m256i _Left = _mm256_loadu_si256(static_cast<__m256i*>(_First)); const __m256i _Right = _mm256_loadu_si256(static_cast<__m256i*>(_Last)); - const __m256i _Left_perm = _mm256_permute4x64_epi64(_Left, _MM_SHUFFLE(1, 0, 3, 2)); - const __m256i _Right_perm = _mm256_permute4x64_epi64(_Right, _MM_SHUFFLE(1, 0, 3, 2)); - const __m256i _Left_reversed = _mm256_shuffle_epi32(_Left_perm, _MM_SHUFFLE(0, 1, 2, 3)); - const __m256i _Right_reversed = _mm256_shuffle_epi32(_Right_perm, _MM_SHUFFLE(0, 1, 2, 3)); + const __m256i _Left_reversed = _mm256_permutevar8x32_epi32(_Left, _Shuf); + const __m256i _Right_reversed = _mm256_permutevar8x32_epi32(_Right, _Shuf); _mm256_storeu_si256(static_cast<__m256i*>(_First), _Right_reversed); _mm256_storeu_si256(static_cast<__m256i*>(_Last), _Left_reversed); _Advance_bytes(_First, 32); } while (_First != _Stop_at); } -#endif // !defined(_M_ARM64EC) - if (_Byte_length(_First, _Last) >= 32 -#ifdef _M_IX86 - && _bittest(&__isa_enabled, __ISA_AVAILABLE_SSE2) -#endif // _M_IX86 - ) { + if (_Byte_length(_First, _Last) >= 32 && _Use_sse2()) { const void* _Stop_at = _First; _Advance_bytes(_Stop_at, _Byte_length(_First, _Last) >> 5 << 4); do { @@ -265,8 +273,7 @@ __declspec(noalias) void __cdecl __std_reverse_trivially_swappable_4(void* _Firs } __declspec(noalias) void __cdecl __std_reverse_trivially_swappable_8(void* _First, void* _Last) noexcept { -#if !defined(_M_ARM64EC) - if (_Byte_length(_First, _Last) >= 64 && _bittest(&__isa_enabled, __ISA_AVAILABLE_AVX2)) { + if (_Byte_length(_First, _Last) >= 64 && _Use_avx2()) { const void* _Stop_at = _First; _Advance_bytes(_Stop_at, _Byte_length(_First, _Last) >> 6 << 5); do { @@ -280,13 +287,8 @@ __declspec(noalias) void __cdecl __std_reverse_trivially_swappable_8(void* _Firs _Advance_bytes(_First, 32); } while (_First != _Stop_at); } -#endif // !defined(_M_ARM64EC) - if (_Byte_length(_First, _Last) >= 32 -#ifdef _M_IX86 - && _bittest(&__isa_enabled, __ISA_AVAILABLE_SSE2) -#endif // _M_IX86 - ) { + if (_Byte_length(_First, _Last) >= 32 && _Use_sse2()) { const void* _Stop_at = _First; _Advance_bytes(_Stop_at, _Byte_length(_First, _Last) >> 5 << 4); do { @@ -306,8 +308,7 @@ __declspec(noalias) void __cdecl __std_reverse_trivially_swappable_8(void* _Firs __declspec(noalias) void __cdecl __std_reverse_copy_trivially_copyable_1( const void* _First, const void* _Last, void* _Dest) noexcept { -#if !defined(_M_ARM64EC) - if (_Byte_length(_First, _Last) >= 32 && _bittest(&__isa_enabled, __ISA_AVAILABLE_AVX2)) { + if (_Byte_length(_First, _Last) >= 32 && _Use_avx2()) { const __m256i _Reverse_char_lanes_avx = _mm256_set_epi8( // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); @@ -322,9 +323,8 @@ __declspec(noalias) void __cdecl __std_reverse_copy_trivially_copyable_1( _Advance_bytes(_Dest, 32); } while (_Dest != _Stop_at); } -#endif // !defined(_M_ARM64EC) - if (_Byte_length(_First, _Last) >= 16 && _bittest(&__isa_enabled, __ISA_AVAILABLE_SSE42)) { + if (_Byte_length(_First, _Last) >= 16 && _Use_sse42()) { const __m128i _Reverse_char_sse = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); const void* _Stop_at = _Dest; _Advance_bytes(_Stop_at, _Byte_length(_First, _Last) >> 4 << 4); @@ -343,8 +343,7 @@ __declspec(noalias) void __cdecl __std_reverse_copy_trivially_copyable_1( __declspec(noalias) void __cdecl __std_reverse_copy_trivially_copyable_2( const void* _First, const void* _Last, void* _Dest) noexcept { -#if !defined(_M_ARM64EC) - if (_Byte_length(_First, _Last) >= 32 && _bittest(&__isa_enabled, __ISA_AVAILABLE_AVX2)) { + if (_Byte_length(_First, _Last) >= 32 && _Use_avx2()) { const __m256i _Reverse_short_lanes_avx = _mm256_set_epi8( // 1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14, // 1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14); @@ -359,9 +358,8 @@ __declspec(noalias) void __cdecl __std_reverse_copy_trivially_copyable_2( _Advance_bytes(_Dest, 32); } while (_Dest != _Stop_at); } -#endif // !defined(_M_ARM64EC) - if (_Byte_length(_First, _Last) >= 16 && _bittest(&__isa_enabled, __ISA_AVAILABLE_SSE42)) { + if (_Byte_length(_First, _Last) >= 16 && _Use_sse42()) { const __m128i _Reverse_short_sse = _mm_set_epi8(1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14); const void* _Stop_at = _Dest; _Advance_bytes(_Stop_at, _Byte_length(_First, _Last) >> 4 << 4); @@ -380,26 +378,20 @@ __declspec(noalias) void __cdecl __std_reverse_copy_trivially_copyable_2( __declspec(noalias) void __cdecl __std_reverse_copy_trivially_copyable_4( const void* _First, const void* _Last, void* _Dest) noexcept { -#if !defined(_M_ARM64EC) - if (_Byte_length(_First, _Last) >= 32 && _bittest(&__isa_enabled, __ISA_AVAILABLE_AVX2)) { + if (_Byte_length(_First, _Last) >= 32 && _Use_avx2()) { const void* _Stop_at = _Dest; _Advance_bytes(_Stop_at, _Byte_length(_First, _Last) >> 5 << 5); + const __m256i _Shuf = _mm256_set_epi32(0, 1, 2, 3, 4, 5, 6, 7); do { _Advance_bytes(_Last, -32); const __m256i _Block = _mm256_loadu_si256(static_cast(_Last)); - const __m256i _Block_permuted = _mm256_permute4x64_epi64(_Block, _MM_SHUFFLE(1, 0, 3, 2)); - const __m256i _Block_reversed = _mm256_shuffle_epi32(_Block_permuted, _MM_SHUFFLE(0, 1, 2, 3)); + const __m256i _Block_reversed = _mm256_permutevar8x32_epi32(_Block, _Shuf); _mm256_storeu_si256(static_cast<__m256i*>(_Dest), _Block_reversed); _Advance_bytes(_Dest, 32); } while (_Dest != _Stop_at); } -#endif // !defined(_M_ARM64EC) - if (_Byte_length(_First, _Last) >= 16 -#ifdef _M_IX86 - && _bittest(&__isa_enabled, __ISA_AVAILABLE_SSE2) -#endif // _M_IX86 - ) { + if (_Byte_length(_First, _Last) >= 16 && _Use_sse2()) { const void* _Stop_at = _Dest; _Advance_bytes(_Stop_at, _Byte_length(_First, _Last) >> 4 << 4); do { @@ -417,8 +409,7 @@ __declspec(noalias) void __cdecl __std_reverse_copy_trivially_copyable_4( __declspec(noalias) void __cdecl __std_reverse_copy_trivially_copyable_8( const void* _First, const void* _Last, void* _Dest) noexcept { -#if !defined(_M_ARM64EC) - if (_Byte_length(_First, _Last) >= 32 && _bittest(&__isa_enabled, __ISA_AVAILABLE_AVX2)) { + if (_Byte_length(_First, _Last) >= 32 && _Use_avx2()) { const void* _Stop_at = _Dest; _Advance_bytes(_Stop_at, _Byte_length(_First, _Last) >> 5 << 5); do { @@ -429,13 +420,8 @@ __declspec(noalias) void __cdecl __std_reverse_copy_trivially_copyable_8( _Advance_bytes(_Dest, 32); } while (_Dest != _Stop_at); } -#endif // !defined(_M_ARM64EC) - if (_Byte_length(_First, _Last) >= 16 -#ifdef _M_IX86 - && _bittest(&__isa_enabled, __ISA_AVAILABLE_SSE2) -#endif // _M_IX86 - ) { + if (_Byte_length(_First, _Last) >= 16 && _Use_sse2()) { const void* _Stop_at = _Dest; _Advance_bytes(_Stop_at, _Byte_length(_First, _Last) >> 4 << 4); do { @@ -451,7 +437,980 @@ __declspec(noalias) void __cdecl __std_reverse_copy_trivially_copyable_8( static_cast(_Dest)); } +} // extern "C" + +namespace { + + template + const void* _Min_tail(const void* const _First, const void* const _Last, const void* _Res, _Ty _Cur) noexcept { + for (auto _Ptr = static_cast(_First); _Ptr != _Last; ++_Ptr) { + if (*_Ptr < _Cur) { + _Res = _Ptr; + _Cur = *_Ptr; + } + } + + return _Res; + } + + template + const void* _Max_tail(const void* const _First, const void* const _Last, const void* _Res, _Ty _Cur) noexcept { + for (auto _Ptr = static_cast(_First); _Ptr != _Last; ++_Ptr) { + if (_Cur < *_Ptr) { + _Res = _Ptr; + _Cur = *_Ptr; + } + } + + return _Res; + } + + template + _Min_max_element_t _Both_tail(const void* const _First, const void* const _Last, _Min_max_element_t& _Res, + _Ty _Cur_min, _Ty _Cur_max) noexcept { + for (auto _Ptr = static_cast(_First); _Ptr != _Last; ++_Ptr) { + if (*_Ptr < _Cur_min) { + _Res._Min = _Ptr; + _Cur_min = *_Ptr; + } + // Not else! + // * Needed for correctness if start with maximum, as we don't handle specially the first element. + // * Promote branchless code generation. + if (_Cur_max <= *_Ptr) { + _Res._Max = _Ptr; + _Cur_max = *_Ptr; + } + } + + return _Res; + } + + enum _Min_max_mode { + _Mode_min = 1 << 0, + _Mode_max = 1 << 1, + _Mode_both = _Mode_min | _Mode_max, + }; + + template <_Min_max_mode _Mode, class _STy, class _UTy> + auto _Minmax_tail(const void* _First, const void* _Last, _Min_max_element_t& _Res, bool _Sign, _UTy _Cur_min, + _UTy _Cur_max) noexcept { + constexpr _UTy _Correction = _UTy{1} << (sizeof(_UTy) * 8 - 1); + + if constexpr (_Mode == _Mode_min) { + if (_Sign) { + return _Min_tail(_First, _Last, _Res._Min, static_cast<_STy>(_Cur_min)); + } else { + return _Min_tail(_First, _Last, _Res._Min, static_cast<_UTy>(_Cur_min + _Correction)); + } + } else if constexpr (_Mode == _Mode_max) { + if (_Sign) { + return _Max_tail(_First, _Last, _Res._Max, static_cast<_STy>(_Cur_max)); + } else { + return _Max_tail(_First, _Last, _Res._Max, static_cast<_UTy>(_Cur_max + _Correction)); + } + } else { + if (_Sign) { + return _Both_tail(_First, _Last, _Res, static_cast<_STy>(_Cur_min), static_cast<_STy>(_Cur_max)); + } else { + return _Both_tail(_First, _Last, _Res, static_cast<_UTy>(_Cur_min + _Correction), + static_cast<_UTy>(_Cur_max + _Correction)); + } + } + } + + struct _Minmax_traits_1 { + using _Signed_t = int8_t; + using _Unsigned_t = uint8_t; + + static constexpr bool _Has_portion_max = true; + static constexpr size_t _Portion_max = 256; + + static constexpr _Signed_t _Init_min_val = static_cast<_Signed_t>(0x7F); + static constexpr _Signed_t _Init_max_val = static_cast<_Signed_t>(0x80); + + static __m128i _Sign_correction(const __m128i _Val, const bool _Sign) noexcept { + alignas(16) static constexpr _Unsigned_t _Sign_corrections[2][16] = { + {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}, {}}; + return _mm_sub_epi8(_Val, _mm_load_si128(reinterpret_cast(_Sign_corrections[_Sign]))); + } + + static __m128i _Inc(__m128i _Idx) noexcept { + return _mm_add_epi8(_Idx, _mm_set1_epi8(1)); + } + + template + static __m128i _H_func(const __m128i _Cur, _Fn _Funct) noexcept { + const __m128i _Shuf_bytes = _mm_set_epi8(14, 15, 12, 13, 10, 11, 8, 9, 6, 7, 4, 5, 2, 3, 0, 1); + const __m128i _Shuf_words = _mm_set_epi8(13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2); + + __m128i _H_min_val = _Cur; + _H_min_val = _Funct(_H_min_val, _mm_shuffle_epi32(_H_min_val, _MM_SHUFFLE(1, 0, 3, 2))); + _H_min_val = _Funct(_H_min_val, _mm_shuffle_epi32(_H_min_val, _MM_SHUFFLE(2, 3, 0, 1))); + _H_min_val = _Funct(_H_min_val, _mm_shuffle_epi8(_H_min_val, _Shuf_words)); + _H_min_val = _Funct(_H_min_val, _mm_shuffle_epi8(_H_min_val, _Shuf_bytes)); + return _H_min_val; + } + + static __m128i _H_min(const __m128i _Cur) noexcept { + return _H_func(_Cur, [](__m128i _First, __m128i _Second) { return _mm_min_epi8(_First, _Second); }); + } + + static __m128i _H_max(const __m128i _Cur) noexcept { + return _H_func(_Cur, [](__m128i _First, __m128i _Second) { return _mm_max_epi8(_First, _Second); }); + } + + static __m128i _H_min_u(const __m128i _Cur) noexcept { + return _H_func(_Cur, [](__m128i _First, __m128i _Second) { return _mm_min_epu8(_First, _Second); }); + } + + static __m128i _H_max_u(const __m128i _Cur) noexcept { + return _H_func(_Cur, [](__m128i _First, __m128i _Second) { return _mm_max_epu8(_First, _Second); }); + } + + static _Signed_t _Get_any(const __m128i _Cur) noexcept { + return static_cast<_Signed_t>(_mm_cvtsi128_si32(_Cur)); + } + + static _Unsigned_t _Get_v_pos(const __m128i _Idx, const unsigned long _H_pos) noexcept { + return static_cast<_Unsigned_t>(_mm_cvtsi128_si32(_mm_shuffle_epi8(_Idx, _mm_cvtsi32_si128(_H_pos)))); + } + + static __m128i _Cmp_eq(const __m128i _First, const __m128i _Second) noexcept { + return _mm_cmpeq_epi8(_First, _Second); + } + + static __m128i _Cmp_gt(const __m128i _First, const __m128i _Second) noexcept { + return _mm_cmpgt_epi8(_First, _Second); + } + + static __m128i _Min(const __m128i _First, const __m128i _Second, __m128i) noexcept { + return _mm_min_epi8(_First, _Second); + } + + static __m128i _Max(const __m128i _First, const __m128i _Second, __m128i) noexcept { + return _mm_max_epi8(_First, _Second); + } + }; + + struct _Minmax_traits_2 { + using _Signed_t = int16_t; + using _Unsigned_t = uint16_t; + + static constexpr bool _Has_portion_max = true; + static constexpr size_t _Portion_max = 65536; + + static constexpr _Signed_t _Init_min_val = static_cast<_Signed_t>(0x7FFF); + static constexpr _Signed_t _Init_max_val = static_cast<_Signed_t>(0x8000); + + static __m128i _Sign_correction(const __m128i _Val, const bool _Sign) noexcept { + alignas(16) static constexpr _Unsigned_t _Sign_corrections[2][8] = { + 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, {}}; + return _mm_sub_epi16(_Val, _mm_load_si128(reinterpret_cast(_Sign_corrections[_Sign]))); + } + + static __m128i _Inc(__m128i _Idx) noexcept { + return _mm_add_epi16(_Idx, _mm_set1_epi16(1)); + } + + template + static __m128i _H_func(const __m128i _Cur, _Fn _Funct) noexcept { + const __m128i _Shuf_words = _mm_set_epi8(13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2); + + __m128i _H_min_val = _Cur; + _H_min_val = _Funct(_H_min_val, _mm_shuffle_epi32(_H_min_val, _MM_SHUFFLE(1, 0, 3, 2))); + _H_min_val = _Funct(_H_min_val, _mm_shuffle_epi32(_H_min_val, _MM_SHUFFLE(2, 3, 0, 1))); + _H_min_val = _Funct(_H_min_val, _mm_shuffle_epi8(_H_min_val, _Shuf_words)); + return _H_min_val; + } + + static __m128i _H_min(const __m128i _Cur) noexcept { + return _H_func(_Cur, [](__m128i _First, __m128i _Second) { return _mm_min_epi16(_First, _Second); }); + } + + static __m128i _H_max(const __m128i _Cur) noexcept { + return _H_func(_Cur, [](__m128i _First, __m128i _Second) { return _mm_max_epi16(_First, _Second); }); + } + + static __m128i _H_min_u(const __m128i _Cur) noexcept { + return _H_func(_Cur, [](__m128i _First, __m128i _Second) { return _mm_min_epu16(_First, _Second); }); + } + + static __m128i _H_max_u(const __m128i _Cur) noexcept { + return _H_func(_Cur, [](__m128i _First, __m128i _Second) { return _mm_max_epu16(_First, _Second); }); + } + + static _Signed_t _Get_any(const __m128i _Cur) noexcept { + return static_cast<_Signed_t>(_mm_cvtsi128_si32(_Cur)); + } + + static _Unsigned_t _Get_v_pos(const __m128i _Idx, const unsigned long _H_pos) noexcept { + static constexpr _Unsigned_t _Shuf[] = {0x0100, 0x0302, 0x0504, 0x0706, 0x0908, 0x0B0A, 0x0D0C, 0x0F0E}; + + return static_cast<_Unsigned_t>( + _mm_cvtsi128_si32(_mm_shuffle_epi8(_Idx, _mm_cvtsi32_si128(_Shuf[_H_pos >> 1])))); + } + + static __m128i _Cmp_eq(const __m128i _First, const __m128i _Second) noexcept { + return _mm_cmpeq_epi16(_First, _Second); + } + + static __m128i _Cmp_gt(const __m128i _First, const __m128i _Second) noexcept { + return _mm_cmpgt_epi16(_First, _Second); + } + + static __m128i _Min(const __m128i _First, const __m128i _Second, __m128i) noexcept { + return _mm_min_epi16(_First, _Second); + } + + static __m128i _Max(const __m128i _First, const __m128i _Second, __m128i) noexcept { + return _mm_max_epi16(_First, _Second); + } + }; + + struct _Minmax_traits_4 { + using _Signed_t = int32_t; + using _Unsigned_t = uint32_t; + +#ifdef _M_IX86 + static constexpr bool _Has_portion_max = false; +#else // ^^^ 32-bit ^^^ / vvv 64-bit vvv + static constexpr bool _Has_portion_max = true; + static constexpr size_t _Portion_max = 0x1'0000'0000ULL; +#endif // ^^^ 64-bit ^^^ + + static constexpr _Signed_t _Init_min_val = static_cast<_Signed_t>(0x7FFF'FFFFUL); + static constexpr _Signed_t _Init_max_val = static_cast<_Signed_t>(0x8000'0000UL); + + static __m128i _Sign_correction(const __m128i _Val, const bool _Sign) noexcept { + alignas(16) static constexpr _Unsigned_t _Sign_corrections[2][4] = { + 0x8000'0000UL, 0x8000'0000UL, 0x8000'0000UL, 0x8000'0000UL, {}}; + return _mm_sub_epi32(_Val, _mm_load_si128(reinterpret_cast(_Sign_corrections[_Sign]))); + } + + static __m128i _Inc(__m128i _Idx) noexcept { + return _mm_add_epi32(_Idx, _mm_set1_epi32(1)); + } + + template + static __m128i _H_func(const __m128i _Cur, _Fn _Funct) noexcept { + __m128i _H_min_val = _Cur; + _H_min_val = _Funct(_H_min_val, _mm_shuffle_epi32(_H_min_val, _MM_SHUFFLE(1, 0, 3, 2))); + _H_min_val = _Funct(_H_min_val, _mm_shuffle_epi32(_H_min_val, _MM_SHUFFLE(2, 3, 0, 1))); + return _H_min_val; + } + + static __m128i _H_min(const __m128i _Cur) noexcept { + return _H_func(_Cur, [](__m128i _First, __m128i _Second) { return _mm_min_epi32(_First, _Second); }); + } + + static __m128i _H_max(const __m128i _Cur) noexcept { + return _H_func(_Cur, [](__m128i _First, __m128i _Second) { return _mm_max_epi32(_First, _Second); }); + } + + static __m128i _H_min_u(const __m128i _Cur) noexcept { + return _H_func(_Cur, [](__m128i _First, __m128i _Second) { return _mm_min_epu32(_First, _Second); }); + } + + static __m128i _H_max_u(const __m128i _Cur) noexcept { + return _H_func(_Cur, [](__m128i _First, __m128i _Second) { return _mm_max_epu32(_First, _Second); }); + } + + static _Signed_t _Get_any(const __m128i _Cur) noexcept { + return static_cast<_Signed_t>(_mm_cvtsi128_si32(_Cur)); + } + + static _Unsigned_t _Get_v_pos(const __m128i _Idx, const unsigned long _H_pos) noexcept { + _Unsigned_t _Array[4]; + _mm_storeu_si128(reinterpret_cast<__m128i*>(&_Array), _Idx); + return _Array[_H_pos >> 2]; + } + + static __m128i _Cmp_eq(const __m128i _First, const __m128i _Second) noexcept { + return _mm_cmpeq_epi32(_First, _Second); + } + + static __m128i _Cmp_gt(const __m128i _First, const __m128i _Second) noexcept { + return _mm_cmpgt_epi32(_First, _Second); + } + + static __m128i _Min(const __m128i _First, const __m128i _Second, __m128i) noexcept { + return _mm_min_epi32(_First, _Second); + } + + static __m128i _Max(const __m128i _First, const __m128i _Second, __m128i) noexcept { + return _mm_max_epi32(_First, _Second); + } + }; + + struct _Minmax_traits_8 { + using _Signed_t = int64_t; + using _Unsigned_t = uint64_t; + + static constexpr bool _Has_portion_max = false; + + static constexpr _Signed_t _Init_min_val = static_cast<_Signed_t>(0x7FFF'FFFF'FFFF'FFFFULL); + static constexpr _Signed_t _Init_max_val = static_cast<_Signed_t>(0x8000'0000'0000'0000ULL); + + static __m128i _Sign_correction(const __m128i _Val, const bool _Sign) { + alignas(16) static constexpr _Unsigned_t _Sign_corrections[2][2] = { + 0x8000'0000'0000'0000ULL, 0x8000'0000'0000'0000ULL, {}}; + return _mm_sub_epi64(_Val, _mm_load_si128(reinterpret_cast(_Sign_corrections[_Sign]))); + } + + static __m128i _Inc(__m128i _Idx) noexcept { + return _mm_add_epi64(_Idx, _mm_set1_epi64x(1)); + } + + template + static __m128i _H_func(const __m128i _Cur, _Fn _Funct) noexcept { + _Signed_t _H_min_a = _Get_any(_Cur); + _Signed_t _H_min_b = _Get_any(_mm_bsrli_si128(_Cur, 8)); + if (_Funct(_H_min_b, _H_min_a)) { + _H_min_a = _H_min_b; + } + return _mm_set1_epi64x(_H_min_a); + } + + static __m128i _H_min(const __m128i _Cur) noexcept { + return _H_func(_Cur, [](_Signed_t _Lhs, _Signed_t _Rhs) { return _Lhs < _Rhs; }); + } + + static __m128i _H_max(const __m128i _Cur) noexcept { + return _H_func(_Cur, [](_Signed_t _Lhs, _Signed_t _Rhs) { return _Lhs > _Rhs; }); + } + + static __m128i _H_min_u(const __m128i _Cur) noexcept { + return _H_func(_Cur, [](_Unsigned_t _Lhs, _Unsigned_t _Rhs) { return _Lhs < _Rhs; }); + } + + static __m128i _H_max_u(const __m128i _Cur) noexcept { + return _H_func(_Cur, [](_Unsigned_t _Lhs, _Unsigned_t _Rhs) { return _Lhs > _Rhs; }); + } + + static _Signed_t _Get_any(const __m128i _Cur) noexcept { +#ifdef _M_IX86 + return static_cast<_Signed_t>( + (static_cast<_Unsigned_t>(static_cast(_mm_extract_epi32(_Cur, 1))) << 32) + | static_cast<_Unsigned_t>(static_cast(_mm_cvtsi128_si32(_Cur)))); +#else // ^^^ x86 ^^^ / vvv x64 vvv + return static_cast<_Signed_t>(_mm_cvtsi128_si64(_Cur)); +#endif // ^^^ x64 ^^^ + } + + static _Unsigned_t _Get_v_pos(const __m128i _Idx, const unsigned long _H_pos) noexcept { + _Unsigned_t _Array[2]; + _mm_storeu_si128(reinterpret_cast<__m128i*>(&_Array), _Idx); + return _Array[_H_pos >> 3]; + } + + static __m128i _Cmp_eq(const __m128i _First, const __m128i _Second) noexcept { + return _mm_cmpeq_epi64(_First, _Second); + } + + static __m128i _Cmp_gt(const __m128i _First, const __m128i _Second) noexcept { + return _mm_cmpgt_epi64(_First, _Second); + } + + static __m128i _Min(const __m128i _First, const __m128i _Second, const __m128i _Mask) noexcept { + return _mm_blendv_epi8(_First, _Second, _Mask); + } + + static __m128i _Max(const __m128i _First, const __m128i _Second, const __m128i _Mask) noexcept { + return _mm_blendv_epi8(_First, _Second, _Mask); + } + }; + + // _Minmax_element has exactly the same signature as the extern "C" functions + // (__std_min_element_N, __std_max_element_N, __std_minmax_element_N), up to calling convention. + // This makes sure the template specialization is fused with the extern "C" function. + // In optimized builds it avoids an extra call, as this function is too large to inline. + template <_Min_max_mode _Mode, class _Traits> + auto __stdcall _Minmax_element(const void* _First, const void* const _Last, const bool _Sign) noexcept { + _Min_max_element_t _Res = {_First, _First}; + auto _Base = static_cast(_First); + auto _Cur_min_val = _Traits::_Init_min_val; + auto _Cur_max_val = _Traits::_Init_max_val; + + if (_Byte_length(_First, _Last) >= 16 && _Use_sse42()) { + size_t _Portion_byte_size = _Byte_length(_First, _Last) & ~size_t{0xF}; + + if constexpr (_Traits::_Has_portion_max) { + // vector of indices will wrap around at exactly this size + constexpr size_t _Max_portion_byte_size = _Traits::_Portion_max * 16; + if (_Portion_byte_size > _Max_portion_byte_size) { + _Portion_byte_size = _Max_portion_byte_size; + } + } + + const void* _Stop_at = _First; + _Advance_bytes(_Stop_at, _Portion_byte_size); + + // Load values and if unsigned adjust them to be signed (for signed vector comparisons) + __m128i _Cur_vals = + _Traits::_Sign_correction(_mm_loadu_si128(reinterpret_cast(_First)), _Sign); + __m128i _Cur_vals_min = _Cur_vals; // vector of vertical minimum values + __m128i _Cur_idx_min = _mm_setzero_si128(); // vector of vertical minimum indices + __m128i _Cur_vals_max = _Cur_vals; // vector of vertical maximum values + __m128i _Cur_idx_max = _mm_setzero_si128(); // vector of vertical maximum indices + __m128i _Cur_idx = _mm_setzero_si128(); // current vector of indices + + for (;;) { + _Advance_bytes(_First, 16); + + // Increment vertical indices. Will stop at exactly wrap around, if not reach the end before + _Cur_idx = _Traits::_Inc(_Cur_idx); + + if (_First == _Stop_at) { + // Reached end or indices wrap around point. + // Compute horizontal min and/or max. Determine horizontal and vertical position of it. + + if constexpr ((_Mode & _Mode_min) != 0) { + const __m128i _H_min = + _Traits::_H_min(_Cur_vals_min); // Vector populated by the smallest element + const auto _H_min_val = _Traits::_Get_any(_H_min); // Get any element of it + + if (_H_min_val < _Cur_min_val) { // Current horizontal min is less than the old + _Cur_min_val = _H_min_val; // update min + const __m128i _Eq_mask = + _Traits::_Cmp_eq(_H_min, _Cur_vals_min); // Mask of all elems eq to min + int _Mask = _mm_movemask_epi8(_Eq_mask); + // Indices of minimum elements or the greatest index if none + const __m128i _All_max = _mm_set1_epi8(static_cast(0xFF)); + const __m128i _Idx_min_val = _mm_blendv_epi8(_All_max, _Cur_idx_min, _Eq_mask); + __m128i _Idx_min = _Traits::_H_min_u(_Idx_min_val); // The smallest indices + // Select the smallest vertical indices from the smallest element mask + _Mask &= _mm_movemask_epi8(_Traits::_Cmp_eq(_Idx_min, _Idx_min_val)); + unsigned long _H_pos; + _BitScanForward(&_H_pos, _Mask); // Find the smallest horizontal index + const auto _V_pos = _Traits::_Get_v_pos(_Cur_idx_min, _H_pos); // Extract its vertical index + _Res._Min = _Base + _V_pos * 16 + _H_pos; // Finally, compute the pointer + } + } + + if constexpr ((_Mode & _Mode_max) != 0) { + const __m128i _H_max = + _Traits::_H_max(_Cur_vals_max); // Vector populated by the largest element + const auto _H_max_val = _Traits::_Get_any(_H_max); // Get any element of it + + if (_Mode == _Mode_both && _Cur_max_val <= _H_max_val + || _Mode == _Mode_max && _Cur_max_val < _H_max_val) { + // max_element: current horizontal max is greater than the old, update max + // minmax_element: current horizontal max is not less than the old, update max + _Cur_max_val = _H_max_val; + const __m128i _Eq_mask = + _Traits::_Cmp_eq(_H_max, _Cur_vals_max); // Mask of all elems eq to max + int _Mask = _mm_movemask_epi8(_Eq_mask); + + unsigned long _H_pos; + if constexpr (_Mode == _Mode_both) { + // Looking for the last occurrence of maximum + // Indices of maximum elements or zero if none + const __m128i _Idx_max_val = + _mm_blendv_epi8(_mm_setzero_si128(), _Cur_idx_max, _Eq_mask); + const __m128i _Idx_max = _Traits::_H_max_u(_Idx_max_val); // The greatest indices + // Select the greatest vertical indices from the largest element mask + _Mask &= _mm_movemask_epi8(_Traits::_Cmp_eq(_Idx_max, _Idx_max_val)); + _BitScanReverse(&_H_pos, _Mask); // Find the largest horizontal index + _H_pos -= sizeof(_Cur_max_val) - 1; // Correct from highest val bit to lowest + } else { + // Looking for the first occurrence of maximum + // Indices of maximum elements or the greatest index if none + const __m128i _All_max = _mm_set1_epi8(static_cast(0xFF)); + const __m128i _Idx_max_val = _mm_blendv_epi8(_All_max, _Cur_idx_max, _Eq_mask); + const __m128i _Idx_max = _Traits::_H_min_u(_Idx_max_val); // The smallest indices + // Select the smallest vertical indices from the largest element mask + _Mask &= _mm_movemask_epi8(_Traits::_Cmp_eq(_Idx_max, _Idx_max_val)); + _BitScanForward(&_H_pos, _Mask); // Find the smallest horizontal index + } + + const auto _V_pos = _Traits::_Get_v_pos(_Cur_idx_max, _H_pos); // Extract its vertical index + _Res._Max = _Base + _V_pos * 16 + _H_pos; // Finally, compute the pointer + } + } + // Horizontal part done, results are saved, now need to see if there is another portion to process + + if constexpr (_Traits::_Has_portion_max) { + // Either the last portion or wrapping point reached, need to determine + _Portion_byte_size = _Byte_length(_First, _Last) & ~size_t{0xF}; + if (_Portion_byte_size == 0) { + break; // That was the last portion + } + // Start next portion to handle the wrapping indices. Assume _Cur_idx is zero + constexpr size_t _Max_portion_byte_size = _Traits::_Portion_max * 16; + if (_Portion_byte_size > _Max_portion_byte_size) { + _Portion_byte_size = _Max_portion_byte_size; + } + + _Advance_bytes(_Stop_at, _Portion_byte_size); + // Indices will be relative to the new base + _Base = static_cast(_First); + // Load values and if unsigned adjust them to be signed (for signed vector comparisons) + _Cur_vals = + _Traits::_Sign_correction(_mm_loadu_si128(reinterpret_cast(_First)), _Sign); + + if constexpr ((_Mode & _Mode_min) != 0) { + _Cur_vals_min = _Cur_vals; + _Cur_idx_min = _mm_setzero_si128(); + } + + if constexpr ((_Mode & _Mode_max) != 0) { + _Cur_vals_max = _Cur_vals; + _Cur_idx_max = _mm_setzero_si128(); + } + + continue; + } else { + break; // No wrapping, so it was the only portion + } + } + // This is the main part, finding vertical minimum/maximum + + // Load values and if unsigned adjust them to be signed (for signed vector comparisons) + _Cur_vals = _Traits::_Sign_correction(_mm_loadu_si128(reinterpret_cast(_First)), _Sign); + + if constexpr ((_Mode & _Mode_min) != 0) { + // Looking for the first occurrence of minimum, don't overwrite with newly found occurrences + const __m128i _Is_less = _Traits::_Cmp_gt(_Cur_vals_min, _Cur_vals); // _Cur_vals < _Cur_vals_min + _Cur_idx_min = _mm_blendv_epi8(_Cur_idx_min, _Cur_idx, _Is_less); // Remember their vertical indices + _Cur_vals_min = _Traits::_Min(_Cur_vals_min, _Cur_vals, _Is_less); // Update the current minimum + } + + if constexpr (_Mode == _Mode_max) { + // Looking for the first occurrence of maximum, don't overwrite with newly found occurrences + const __m128i _Is_greater = _Traits::_Cmp_gt(_Cur_vals, _Cur_vals_max); // _Cur_vals > _Cur_vals_max + _Cur_idx_max = + _mm_blendv_epi8(_Cur_idx_max, _Cur_idx, _Is_greater); // Remember their vertical indices + _Cur_vals_max = _Traits::_Max(_Cur_vals_max, _Cur_vals, _Is_greater); // Update the current maximum + } else if constexpr (_Mode == _Mode_both) { + // Looking for the last occurrence of maximum, do overwrite with newly found occurrences + const __m128i _Is_less = + _Traits::_Cmp_gt(_Cur_vals_max, _Cur_vals); // !(_Cur_vals >= _Cur_vals_max) + _Cur_idx_max = _mm_blendv_epi8(_Cur_idx, _Cur_idx_max, _Is_less); // Remember their vertical indices + _Cur_vals_max = _Traits::_Max(_Cur_vals, _Cur_vals_max, _Is_less); // Update the current maximum + } + } + } + + return _Minmax_tail<_Mode, typename _Traits::_Signed_t, typename _Traits::_Unsigned_t>( + _First, _Last, _Res, _Sign, _Cur_min_val, _Cur_max_val); + } + +} // unnamed namespace + +extern "C" { + +const void* __stdcall __std_min_element_1( + const void* const _First, const void* const _Last, const bool _Signed) noexcept { + return _Minmax_element<_Mode_min, _Minmax_traits_1>(_First, _Last, _Signed); +} + +const void* __stdcall __std_min_element_2( + const void* const _First, const void* const _Last, const bool _Signed) noexcept { + return _Minmax_element<_Mode_min, _Minmax_traits_2>(_First, _Last, _Signed); +} + +const void* __stdcall __std_min_element_4( + const void* const _First, const void* const _Last, const bool _Signed) noexcept { + return _Minmax_element<_Mode_min, _Minmax_traits_4>(_First, _Last, _Signed); +} + +const void* __stdcall __std_min_element_8( + const void* const _First, const void* const _Last, const bool _Signed) noexcept { + return _Minmax_element<_Mode_min, _Minmax_traits_8>(_First, _Last, _Signed); +} + +const void* __stdcall __std_max_element_1( + const void* const _First, const void* const _Last, const bool _Signed) noexcept { + return _Minmax_element<_Mode_max, _Minmax_traits_1>(_First, _Last, _Signed); +} + +const void* __stdcall __std_max_element_2( + const void* const _First, const void* const _Last, const bool _Signed) noexcept { + return _Minmax_element<_Mode_max, _Minmax_traits_2>(_First, _Last, _Signed); +} + +const void* __stdcall __std_max_element_4( + const void* const _First, const void* const _Last, const bool _Signed) noexcept { + return _Minmax_element<_Mode_max, _Minmax_traits_4>(_First, _Last, _Signed); +} + +const void* __stdcall __std_max_element_8( + const void* const _First, const void* const _Last, const bool _Signed) noexcept { + return _Minmax_element<_Mode_max, _Minmax_traits_8>(_First, _Last, _Signed); +} + +_Min_max_element_t __stdcall __std_minmax_element_1( + const void* const _First, const void* const _Last, const bool _Signed) noexcept { + return _Minmax_element<_Mode_both, _Minmax_traits_1>(_First, _Last, _Signed); +} + +_Min_max_element_t __stdcall __std_minmax_element_2( + const void* const _First, const void* const _Last, const bool _Signed) noexcept { + return _Minmax_element<_Mode_both, _Minmax_traits_2>(_First, _Last, _Signed); +} + +_Min_max_element_t __stdcall __std_minmax_element_4( + const void* const _First, const void* const _Last, const bool _Signed) noexcept { + return _Minmax_element<_Mode_both, _Minmax_traits_4>(_First, _Last, _Signed); +} + +_Min_max_element_t __stdcall __std_minmax_element_8( + const void* const _First, const void* const _Last, const bool _Signed) noexcept { + return _Minmax_element<_Mode_both, _Minmax_traits_8>(_First, _Last, _Signed); +} + +} // extern "C" + +namespace { + template + const void* _Find_trivial_unsized_fallback(const void* _First, _Ty _Val) { + auto _Ptr = static_cast(_First); + while (*_Ptr != _Val) { + ++_Ptr; + } + return _Ptr; + } + + template + const void* _Find_trivial_tail(const void* _First, const void* _Last, _Ty _Val) { + auto _Ptr = static_cast(_First); + while (_Ptr != _Last && *_Ptr != _Val) { + ++_Ptr; + } + return _Ptr; + } + + template + __declspec(noalias) size_t _Count_trivial_tail(const void* _First, const void* _Last, size_t _Current, _Ty _Val) { + auto _Ptr = static_cast(_First); + for (; _Ptr != _Last; ++_Ptr) { + if (*_Ptr == _Val) { + ++_Current; + } + } + return _Current; + } + + struct _Find_traits_1 { + static constexpr size_t _Shift = 0; + + static __m256i _Set_avx(const uint8_t _Val) noexcept { + return _mm256_set1_epi8(_Val); + } + + static __m128i _Set_sse(const uint8_t _Val) noexcept { + return _mm_set1_epi8(_Val); + } + + static __m256i _Cmp_avx(const __m256i _Lhs, const __m256i _Rhs) noexcept { + return _mm256_cmpeq_epi8(_Lhs, _Rhs); + } + + static __m128i _Cmp_sse(const __m128i _Lhs, const __m128i _Rhs) noexcept { + return _mm_cmpeq_epi8(_Lhs, _Rhs); + } + + static bool _Sse_available() noexcept { + return _Use_sse2(); + } + }; + + struct _Find_traits_2 { + static constexpr size_t _Shift = 1; + + static __m256i _Set_avx(const uint16_t _Val) noexcept { + return _mm256_set1_epi16(_Val); + } + + static __m128i _Set_sse(const uint16_t _Val) noexcept { + return _mm_set1_epi16(_Val); + } + + static __m256i _Cmp_avx(const __m256i _Lhs, const __m256i _Rhs) noexcept { + return _mm256_cmpeq_epi16(_Lhs, _Rhs); + } + + static __m128i _Cmp_sse(const __m128i _Lhs, const __m128i _Rhs) noexcept { + return _mm_cmpeq_epi16(_Lhs, _Rhs); + } + + static bool _Sse_available() noexcept { + return _Use_sse2(); + } + }; + + struct _Find_traits_4 { + static constexpr size_t _Shift = 2; + + static __m256i _Set_avx(const uint32_t _Val) noexcept { + return _mm256_set1_epi32(_Val); + } + + static __m128i _Set_sse(const uint32_t _Val) noexcept { + return _mm_set1_epi32(_Val); + } + + static __m256i _Cmp_avx(const __m256i _Lhs, const __m256i _Rhs) noexcept { + return _mm256_cmpeq_epi32(_Lhs, _Rhs); + } + + static __m128i _Cmp_sse(const __m128i _Lhs, const __m128i _Rhs) noexcept { + return _mm_cmpeq_epi32(_Lhs, _Rhs); + } + + static bool _Sse_available() noexcept { + return _Use_sse2(); + } + }; + + struct _Find_traits_8 { + static constexpr size_t _Shift = 3; + + static __m256i _Set_avx(const uint64_t _Val) noexcept { + return _mm256_set1_epi64x(_Val); + } + + static __m128i _Set_sse(const uint64_t _Val) noexcept { + return _mm_set1_epi64x(_Val); + } + + static __m256i _Cmp_avx(const __m256i _Lhs, const __m256i _Rhs) noexcept { + return _mm256_cmpeq_epi64(_Lhs, _Rhs); + } + + static __m128i _Cmp_sse(const __m128i _Lhs, const __m128i _Rhs) noexcept { + return _mm_cmpeq_epi64(_Lhs, _Rhs); // SSE4.1 + } + + static bool _Sse_available() noexcept { + return _Use_sse42(); // for pcmpeqq on _Cmp_sse + } + }; + + // The below functions have exactly the same signature as the extern "C" functions, up to calling convention. + // This makes sure the template specialization is fused with the extern "C" function. + // In optimized builds it avoids an extra call, as this function is too large to inline. + + template + const void* __stdcall __std_find_trivial_unsized(const void* _First, const _Ty _Val) noexcept { + if (_Use_avx2()) { + // We read by vector-sized pieces, and we align pointers to vector-sized boundary. + // From start partial piece we mask out matches that don't belong to the range. + // This makes sure we never cross page boundary, thus we read 'as if' sequentially. + constexpr size_t _Vector_pad_mask = 0x1F; + constexpr unsigned int _Full_mask = 0xFFFF'FFFF; + + const __m256i _Comparand = _Traits::_Set_avx(_Val); + const intptr_t _Pad_start = reinterpret_cast(_First) & _Vector_pad_mask; + const unsigned int _Mask = _Full_mask << _Pad_start; + _Advance_bytes(_First, -_Pad_start); + + __m256i _Data = _mm256_load_si256(static_cast(_First)); + unsigned int _Bingo = static_cast(_mm256_movemask_epi8(_Traits::_Cmp_avx(_Data, _Comparand))); + + if ((_Bingo &= _Mask) != 0) { + unsigned long _Offset = _tzcnt_u32(_Bingo); + _Advance_bytes(_First, _Offset); + return _First; + } + + for (;;) { + _Data = _mm256_load_si256(static_cast(_First)); + _Bingo = static_cast(_mm256_movemask_epi8(_Traits::_Cmp_avx(_Data, _Comparand))); + + if (_Bingo != 0) { + unsigned long _Offset = _tzcnt_u32(_Bingo); + _Advance_bytes(_First, _Offset); + return _First; + } + + _Advance_bytes(_First, 32); + } + } + + if (_Traits::_Sse_available()) { + // We read by vector-sized pieces, and we align pointers to vector-sized boundary. + // From start partial piece we mask out matches that don't belong to the range. + // This makes sure we never cross page boundary, thus we read 'as if' sequentially. + constexpr size_t _Vector_pad_mask = 0xF; + constexpr unsigned int _Full_mask = 0xFFFF; + + const __m128i _Comparand = _Traits::_Set_sse(_Val); + const intptr_t _Pad_start = reinterpret_cast(_First) & _Vector_pad_mask; + const unsigned int _Mask = _Full_mask << _Pad_start; + _Advance_bytes(_First, -_Pad_start); + + __m128i _Data = _mm_load_si128(static_cast(_First)); + unsigned int _Bingo = static_cast(_mm_movemask_epi8(_Traits::_Cmp_sse(_Data, _Comparand))); + + if ((_Bingo &= _Mask) != 0) { + unsigned long _Offset; + _BitScanForward(&_Offset, _Bingo); + _Advance_bytes(_First, _Offset); + return _First; + } + + for (;;) { + _Data = _mm_load_si128(static_cast(_First)); + _Bingo = static_cast(_mm_movemask_epi8(_Traits::_Cmp_sse(_Data, _Comparand))); + + if (_Bingo != 0) { + unsigned long _Offset; + _BitScanForward(&_Offset, _Bingo); + _Advance_bytes(_First, _Offset); + return _First; + } + + _Advance_bytes(_First, 16); + } + } + + return _Find_trivial_unsized_fallback(_First, _Val); + } + + + template + const void* __stdcall __std_find_trivial(const void* _First, const void* _Last, _Ty _Val) noexcept { + size_t _Size_bytes = _Byte_length(_First, _Last); + + const size_t _Avx_size = _Size_bytes & ~size_t{0x1F}; + if (_Avx_size != 0 && _Use_avx2()) { + const __m256i _Comparand = _Traits::_Set_avx(_Val); + const void* _Stop_at = _First; + _Advance_bytes(_Stop_at, _Avx_size); + do { + const __m256i _Data = _mm256_loadu_si256(static_cast(_First)); + const int _Bingo = _mm256_movemask_epi8(_Traits::_Cmp_avx(_Data, _Comparand)); + + if (_Bingo != 0) { + const unsigned long _Offset = _tzcnt_u32(_Bingo); + _Advance_bytes(_First, _Offset); + return _First; + } + + _Advance_bytes(_First, 32); + } while (_First != _Stop_at); + _Size_bytes &= 0x1F; + } + + const size_t _Sse_size = _Size_bytes & ~size_t{0xF}; + if (_Sse_size != 0 && _Traits::_Sse_available()) { + const __m128i _Comparand = _Traits::_Set_sse(_Val); + const void* _Stop_at = _First; + _Advance_bytes(_Stop_at, _Sse_size); + do { + const __m128i _Data = _mm_loadu_si128(static_cast(_First)); + const int _Bingo = _mm_movemask_epi8(_Traits::_Cmp_sse(_Data, _Comparand)); + + if (_Bingo != 0) { + unsigned long _Offset; + _BitScanForward(&_Offset, _Bingo); + _Advance_bytes(_First, _Offset); + return _First; + } + + _Advance_bytes(_First, 16); + } while (_First != _Stop_at); + } + + return _Find_trivial_tail(_First, _Last, _Val); + } + + template + __declspec(noalias) size_t + __stdcall __std_count_trivial(const void* _First, const void* const _Last, const _Ty _Val) noexcept { + size_t _Size_bytes = _Byte_length(_First, _Last); + size_t _Result = 0; + + const size_t _Avx_size = _Size_bytes & ~size_t{0x1F}; + if (_Avx_size != 0 && _Use_avx2()) { + const __m256i _Comparand = _Traits::_Set_avx(_Val); + const void* _Stop_at = _First; + _Advance_bytes(_Stop_at, _Avx_size); + do { + const __m256i _Data = _mm256_loadu_si256(static_cast(_First)); + const int _Bingo = _mm256_movemask_epi8(_Traits::_Cmp_avx(_Data, _Comparand)); + _Result += __popcnt(_Bingo); // Assume available with SSE4.2 + _Advance_bytes(_First, 32); + } while (_First != _Stop_at); + _Size_bytes &= 0x1F; + } + + const size_t _Sse_size = _Size_bytes & ~size_t{0xF}; + if (_Sse_size != 0 && _Use_sse42()) { + const __m128i _Comparand = _Traits::_Set_sse(_Val); + const void* _Stop_at = _First; + _Advance_bytes(_Stop_at, _Sse_size); + do { + const __m128i _Data = _mm_loadu_si128(static_cast(_First)); + const int _Bingo = _mm_movemask_epi8(_Traits::_Cmp_sse(_Data, _Comparand)); + _Result += __popcnt(_Bingo); // Assume available with SSE4.2 + _Advance_bytes(_First, 16); + } while (_First != _Stop_at); + } + + return _Count_trivial_tail(_First, _Last, _Result >> _Traits::_Shift, _Val); + } +} // unnamed namespace + +extern "C" { + +const void* __stdcall __std_find_trivial_unsized_1(const void* const _First, const uint8_t _Val) noexcept { + return __std_find_trivial_unsized<_Find_traits_1>(_First, _Val); +} + +const void* __stdcall __std_find_trivial_unsized_2(const void* const _First, const uint16_t _Val) noexcept { + return __std_find_trivial_unsized<_Find_traits_2>(_First, _Val); +} + +const void* __stdcall __std_find_trivial_unsized_4(const void* const _First, const uint32_t _Val) noexcept { + return __std_find_trivial_unsized<_Find_traits_4>(_First, _Val); +} + +const void* __stdcall __std_find_trivial_unsized_8(const void* const _First, const uint64_t _Val) noexcept { + return __std_find_trivial_unsized<_Find_traits_8>(_First, _Val); +} + +const void* __stdcall __std_find_trivial_1( + const void* const _First, const void* const _Last, const uint8_t _Val) noexcept { + return __std_find_trivial<_Find_traits_1>(_First, _Last, _Val); +} + +const void* __stdcall __std_find_trivial_2( + const void* const _First, const void* const _Last, const uint16_t _Val) noexcept { + return __std_find_trivial<_Find_traits_2>(_First, _Last, _Val); +} + +const void* __stdcall __std_find_trivial_4( + const void* const _First, const void* const _Last, const uint32_t _Val) noexcept { + return __std_find_trivial<_Find_traits_4>(_First, _Last, _Val); +} + +const void* __stdcall __std_find_trivial_8( + const void* const _First, const void* const _Last, const uint64_t _Val) noexcept { + return __std_find_trivial<_Find_traits_8>(_First, _Last, _Val); +} + +__declspec(noalias) size_t + __stdcall __std_count_trivial_1(const void* const _First, const void* const _Last, const uint8_t _Val) noexcept { + return __std_count_trivial<_Find_traits_1>(_First, _Last, _Val); +} + +__declspec(noalias) size_t + __stdcall __std_count_trivial_2(const void* const _First, const void* const _Last, const uint16_t _Val) noexcept { + return __std_count_trivial<_Find_traits_2>(_First, _Last, _Val); +} + +__declspec(noalias) size_t + __stdcall __std_count_trivial_4(const void* const _First, const void* const _Last, const uint32_t _Val) noexcept { + return __std_count_trivial<_Find_traits_4>(_First, _Last, _Val); +} + +__declspec(noalias) size_t + __stdcall __std_count_trivial_8(const void* const _First, const void* const _Last, const uint64_t _Val) noexcept { + return __std_count_trivial<_Find_traits_8>(_First, _Last, _Val); +} } // extern "C" -#endif // defined(_M_IX86) || defined(_M_X64) +#endif // (defined(_M_IX86) || defined(_M_X64)) && !defined(_M_ARM64EC) diff --git a/src/crt/stl/xdtest.cpp b/src/crt/stl/xdtest.cpp index 5a2549a..8ea68c3 100644 --- a/src/crt/stl/xdtest.cpp +++ b/src/crt/stl/xdtest.cpp @@ -21,10 +21,6 @@ _CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _Dtest(double* px) { // categorize * } } -unsigned short* _Plsw(double* px) { // get pointer to lsw - return &reinterpret_cast<_Dval*>(px)->_Sh[_Dg]; -} - unsigned short* _Pmsw(double* px) { // get pointer to msw return &reinterpret_cast<_Dval*>(px)->_Sh[_D0]; } diff --git a/src/crt/stl/xfdtest.cpp b/src/crt/stl/xfdtest.cpp index 5a0385e..968d87e 100644 --- a/src/crt/stl/xfdtest.cpp +++ b/src/crt/stl/xfdtest.cpp @@ -19,10 +19,6 @@ _CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _FDtest(float* px) { // categorize * } } -unsigned short* _FPlsw(float* px) { // get pointer to lsw - return &reinterpret_cast<_Fval*>(px)->_Sh[_Fg]; -} - unsigned short* _FPmsw(float* px) { // get pointer to msw return &reinterpret_cast<_Fval*>(px)->_Sh[_F0]; } diff --git a/src/crt/stl/xldtest.cpp b/src/crt/stl/xldtest.cpp index b0ee55e..e6e5e1c 100644 --- a/src/crt/stl/xldtest.cpp +++ b/src/crt/stl/xldtest.cpp @@ -11,10 +11,6 @@ _CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _LDtest(long double* px) { // catego return _Dtest(reinterpret_cast(px)); } -unsigned short* _LPlsw(long double* px) { // get pointer to lsw - return &reinterpret_cast<_Lval*>(px)->_Sh[_L3]; -} - unsigned short* _LPmsw(long double* px) { // get pointer to msw return &reinterpret_cast<_Lval*>(px)->_Sh[_L0]; } diff --git a/src/crt/stl/xmath.hpp b/src/crt/stl/xmath.hpp index 02e083f..4c1f16e 100644 --- a/src/crt/stl/xmath.hpp +++ b/src/crt/stl/xmath.hpp @@ -10,7 +10,6 @@ // macros for _Feraise argument #define _FE_DIVBYZERO 0x04 -#define _FE_INEXACT 0x20 #define _FE_INVALID 0x01 #define _FE_OVERFLOW 0x08 #define _FE_UNDERFLOW 0x10 @@ -42,9 +41,6 @@ #define FSIGN(x) (reinterpret_cast<_Fval*>(&(x))->_Sh[_F0] & _FSIGN) #define LSIGN(x) (reinterpret_cast<_Lval*>(&(x))->_Sh[_L0] & _LSIGN) -#define _Fg _F1 // least-significant 16-bit word -#define _Dg _D3 - // return values for _Stopfx/_Stoflt #define FL_ERR 0 #define FL_DEC 1 @@ -53,8 +49,43 @@ #define FL_NAN 4 #define FL_NEG 8 +// macros for _Dtest return (0 => ZERO) +#define _DENORM (-2) // C9X only +#define _FINITE (-1) + _EXTERN_C_UNLESS_PURE +void __CLRCALL_PURE_OR_CDECL _Feraise(int); + +#if _MSC_VER >= 1934 // 17.4 +union _Dconst { // pun float types as integer array + unsigned short _Word[8]; // TRANSITION, ABI: Twice as large as necessary. + float _Float; + double _Double; + long double _Long_double; +}; +#endif + +_CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _Dtest(double*); + +extern _CRTIMP2_PURE _Dconst _Denorm; +extern _CRTIMP2_PURE _Dconst _Hugeval; +extern _CRTIMP2_PURE _Dconst _Inf; +extern _CRTIMP2_PURE _Dconst _Nan; +extern _CRTIMP2_PURE _Dconst _Snan; + +_CRTIMP2_PURE short __CLRCALL_PURE_OR_CDECL _FDtest(float*); + +extern _CRTIMP2_PURE _Dconst _FDenorm; +extern _CRTIMP2_PURE _Dconst _FInf; +extern _CRTIMP2_PURE _Dconst _FNan; +extern _CRTIMP2_PURE _Dconst _FSnan; + +extern _CRTIMP2_PURE _Dconst _LDenorm; +extern _CRTIMP2_PURE _Dconst _LInf; +extern _CRTIMP2_PURE _Dconst _LNan; +extern _CRTIMP2_PURE _Dconst _LSnan; + int _Stopfx(const char**, char**); _In_range_(0, maxsig) int _Stoflt( const char*, const char*, char**, _Out_writes_(maxsig) long[], _In_range_(1, 4) int maxsig); @@ -72,7 +103,6 @@ union _Dval { // pun floating type as integer array double _Val; }; -unsigned short* _Plsw(double*); unsigned short* _Pmsw(double*); short _Dint(double*, short); @@ -93,11 +123,8 @@ double* _Xp_addh(double*, int, double); double* _Xp_mulh(double*, int, double); double* _Xp_movx(double*, int, const double*); double* _Xp_addx(double*, int, const double*, int); -double* _Xp_subx(double*, int, const double*, int); double* _Xp_ldexpx(double*, int, int); double* _Xp_mulx(double*, int, const double*, int, double*); -double* _Xp_invx(double*, int, double*); -double* _Xp_sqrtx(double*, int, double*); // float declarations union _Fval { // pun floating type as integer array @@ -105,7 +132,6 @@ union _Fval { // pun floating type as integer array float _Val; }; -unsigned short* _FPlsw(float*); unsigned short* _FPmsw(float*); short _FDint(float*, short); @@ -126,11 +152,8 @@ float* _FXp_addh(float*, int, float); float* _FXp_mulh(float*, int, float); float* _FXp_movx(float*, int, const float*); float* _FXp_addx(float*, int, const float*, int); -float* _FXp_subx(float*, int, const float*, int); float* _FXp_ldexpx(float*, int, int); float* _FXp_mulx(float*, int, const float*, int, float*); -float* _FXp_invx(float*, int, float*); -float* _FXp_sqrtx(float*, int, float*); // long double declarations union _Lval { // pun floating type as integer array @@ -138,7 +161,6 @@ union _Lval { // pun floating type as integer array long double _Val; }; -unsigned short* _LPlsw(long double*); unsigned short* _LPmsw(long double*); short _LDint(long double*, short); @@ -158,11 +180,8 @@ long double* _LXp_addh(long double*, int, long double); long double* _LXp_mulh(long double*, int, long double); long double* _LXp_movx(long double*, int, const long double*); long double* _LXp_addx(long double*, int, const long double*, int); -long double* _LXp_subx(long double*, int, const long double*, int); long double* _LXp_ldexpx(long double*, int, int); long double* _LXp_mulx(long double*, int, const long double*, int, long double*); -long double* _LXp_invx(long double*, int, long double*); -long double* _LXp_sqrtx(long double*, int, long double*); _END_EXTERN_C_UNLESS_PURE diff --git a/src/crt/stl/xrngdev.cpp b/src/crt/stl/xrngdev.cpp index 9542add..4495db7 100644 --- a/src/crt/stl/xrngdev.cpp +++ b/src/crt/stl/xrngdev.cpp @@ -3,16 +3,17 @@ // implement random_device -#include // for out_of_range - -#include +#include +#include _STD_BEGIN -_CRTIMP2_PURE unsigned int __CLRCALL_PURE_OR_CDECL _Random_device(); - _CRTIMP2_PURE unsigned int __CLRCALL_PURE_OR_CDECL _Random_device() { // return a random value - unsigned long ans = 0; - return RtlRandomEx(&ans); + unsigned int ans; + if (_CSTD rand_s(&ans)) { + _Xout_of_range("invalid random_device value"); + } + + return ans; } _STD_END diff --git a/src/crt/stl/xxxprec.hpp b/src/crt/stl/xxxprec.hpp index 0401779..13288e2 100644 --- a/src/crt/stl/xxxprec.hpp +++ b/src/crt/stl/xxxprec.hpp @@ -27,7 +27,7 @@ _EXTERN_C } // STET #if 0 -#include +#include static void printit(const char* s, FTYPE* p, int n) { // print xp array int i; @@ -310,16 +310,6 @@ FTYPE* FNAME(Xp_addx)(FTYPE* p, int n, const FTYPE* q, int m) { // add an extend return p; } -FTYPE* FNAME(Xp_subx)(FTYPE* p, int n, const FTYPE* q, int m) { // subtract an extended precision value - int k; - - for (k = 0; k < m && q[k] != FLIT(0.0); ++k) { - FNAME(Xp_addh)(p, n, -q[k]); - } - - return p; -} - FTYPE* FNAME(Xp_ldexpx)(FTYPE* p, int n, int m) { // scale an extended precision value int k; for (k = 0; k < n; ++k) { @@ -354,80 +344,6 @@ FTYPE* FNAME(Xp_mulx)(FTYPE* p, int n, const FTYPE* q, int m, FTYPE* ptemp2) { return p; } -FTYPE* FNAME(Xp_invx)(FTYPE* p, int n, FTYPE* ptemp4) { // invert an extended precision value (needs 4 * n temp) - short errx; - - if (n != 0) { - if (0 <= (errx = FNAME(Dtest)(&p[0]))) { // not finite, return special value - if (errx == _INFCODE) { - p[0] = FLIT(0.0); // 1/Inf == 0 - } else if (errx == 0) { - p[0] = FCONST(Inf); // 1/0 == Inf - } - // else 1/NaN == NaN - } else { // p[0] is finite nonzero, invert it - FTYPE* pac = ptemp4; - FTYPE* py = ptemp4 + n; - FTYPE* ptemp2 = py + n; - FTYPE x0 = p[0]; - int k; - - FNAME(Xp_movx)(py, n, p); - FNAME(Xp_mulh)(py, n, -FLIT(1.0)); // py = -x - - if (1 < n) { - x0 += p[1]; - } - - FNAME(Xp_setw)(p, n, FLIT(1.0) / x0); // p = y - for (k = 1; k < n; k <<= 1) { // iterate to double previous precision of 1/x - FNAME(Xp_movx)(pac, n, p); - FNAME(Xp_mulx)(pac, n, py, n, ptemp2); - FNAME(Xp_addh)(pac, n, FLIT(1.0)); // 1 - x * y - FNAME(Xp_mulx)(pac, n, p, n, ptemp2); // y * (1 - x * y) - FNAME(Xp_addx)(p, n, pac, n); // y += y * (1 - x * y) - } - } - } - - return p; -} - -FTYPE* FNAME(Xp_sqrtx)(FTYPE* p, int n, FTYPE* ptemp4) { - // find square root of an extended precision value (needs 4 * n temp) - if (n != 0) { - if (0 <= FNAME(Dtest)(&p[0]) || p[0] < FLIT(0.0)) { // not finite nonnegative, return special value - if (p[0] < FLIT(0.0)) { // sqrt(negative), report domain error - _Feraise(_FE_INVALID); - p[0] = FCONST(Nan); - } - } else { // worth iterating, compute x * sqrt(1/x) - FTYPE* pac = ptemp4; - FTYPE* py = ptemp4 + n; - FTYPE* ptemp2 = py + n; - FTYPE x0 = p[0]; - int k; - - if (1 < n) { - x0 += p[1]; - } - - FNAME(Xp_setw)(py, n, static_cast(FLIT(1.0) / FFUN(sqrt)(x0))); // py = y - for (k = 2; k < n; k <<= 1) { // iterate to double previous precision of sqrt(1/x) - FNAME(Xp_movx)(pac, n, py); - FNAME(Xp_mulh)(pac, n, -FLIT(0.5)); - FNAME(Xp_mulx)(pac, n, p, n, ptemp2); - FNAME(Xp_mulx)(pac, n, py, n, ptemp2); - FNAME(Xp_addh)(pac, n, FLIT(1.5)); // 3/2 - x * y * y / 2 - FNAME(Xp_mulx)(py, n, pac, n, ptemp2); // y *= 3/2 - x * y * y / 2 - } - - FNAME(Xp_mulx)(p, n, py, n, ptemp2); // x * sqrt(1/x) - } - } - - return p; -} #if !defined(MRTDLL) _END_EXTERN_C #endif // !defined(MRTDLL) diff --git a/src/crt/vcruntime/ehhelpers.h b/src/crt/vcruntime/ehhelpers.h index 3b6d92f..1151d5f 100644 --- a/src/crt/vcruntime/ehhelpers.h +++ b/src/crt/vcruntime/ehhelpers.h @@ -72,7 +72,7 @@ extern "C" _VCRTIMP int __cdecl RENAME_EH_EXTERN(__TypeMatch)( // template -EXCEPTION_DISPOSITION __InternalCxxFrameHandler( +EXCEPTION_DISPOSITION __InternalCxxFrameHandlerWrapper( EHExceptionRecord *pExcept, EHRegistrationNode *pRN, CONTEXT *pContext, diff --git a/src/crt/vcruntime/ehvccctr.cpp b/src/crt/vcruntime/ehvccctr.cpp index 22c22a2..c5ccda9 100644 --- a/src/crt/vcruntime/ehvccctr.cpp +++ b/src/crt/vcruntime/ehvccctr.cpp @@ -14,14 +14,26 @@ #include - -#define CALLEETYPE __stdcall -#define __RELIABILITY_CONTRACT - -#if defined _M_IX86 -#define CALLTYPE __thiscall +/* + * Note that we will be compiling all this with /clr option not /clr:pure + */ +#if defined _M_CEE + #define CALLTYPE __clrcall + #define CALLEETYPE __clrcall + #define __RELIABILITY_CONTRACT \ + [System::Runtime::ConstrainedExecution::ReliabilityContract( \ + System::Runtime::ConstrainedExecution::Consistency::WillNotCorruptState, \ + System::Runtime::ConstrainedExecution::Cer::Success \ + )] #else -#define CALLTYPE __stdcall + #define CALLEETYPE __stdcall + #define __RELIABILITY_CONTRACT + + #if defined _M_IX86 + #define CALLTYPE __thiscall + #else + #define CALLTYPE __stdcall + #endif #endif using constructor_type = void (CALLTYPE*)(void*, void*); diff --git a/src/crt/vcruntime/ehvcccvb.cpp b/src/crt/vcruntime/ehvcccvb.cpp index b4f85b6..52b8ef3 100644 --- a/src/crt/vcruntime/ehvcccvb.cpp +++ b/src/crt/vcruntime/ehvcccvb.cpp @@ -14,13 +14,23 @@ #include -#define CALLEETYPE __stdcall -#define __RELIABILITY_CONTRACT - -#if defined _M_IX86 -#define CALLTYPE __thiscall +#if defined _M_CEE + #define CALLTYPE __clrcall + #define CALLEETYPE __clrcall + #define __RELIABILITY_CONTRACT \ + [System::Runtime::ConstrainedExecution::ReliabilityContract( \ + System::Runtime::ConstrainedExecution::Consistency::WillNotCorruptState, \ + System::Runtime::ConstrainedExecution::Cer::Success \ + )] #else -#define CALLTYPE __stdcall + #define CALLEETYPE __stdcall + #define __RELIABILITY_CONTRACT + + #if defined _M_IX86 + #define CALLTYPE __thiscall + #else + #define CALLTYPE __stdcall + #endif #endif using constructor_type = void (CALLTYPE*)(void*, void*); diff --git a/src/crt/vcruntime/ehvecctr.cpp b/src/crt/vcruntime/ehvecctr.cpp index cc91fe5..73850b4 100644 --- a/src/crt/vcruntime/ehvecctr.cpp +++ b/src/crt/vcruntime/ehvecctr.cpp @@ -14,13 +14,23 @@ #include -#define CALLEETYPE __stdcall -#define __RELIABILITY_CONTRACT - -#if defined _M_IX86 -#define CALLTYPE __thiscall +#if defined _M_CEE + #define CALLTYPE __clrcall + #define CALLEETYPE __clrcall + #define __RELIABILITY_CONTRACT \ + [System::Runtime::ConstrainedExecution::ReliabilityContract( \ + System::Runtime::ConstrainedExecution::Consistency::WillNotCorruptState, \ + System::Runtime::ConstrainedExecution::Cer::Success \ + )] #else -#define CALLTYPE __stdcall + #define CALLEETYPE __stdcall + #define __RELIABILITY_CONTRACT + + #if defined _M_IX86 + #define CALLTYPE __thiscall + #else + #define CALLTYPE __stdcall + #endif #endif using constructor_type = void (CALLTYPE*)(void*); diff --git a/src/crt/vcruntime/ehveccvb.cpp b/src/crt/vcruntime/ehveccvb.cpp index d5537bb..f7c3833 100644 --- a/src/crt/vcruntime/ehveccvb.cpp +++ b/src/crt/vcruntime/ehveccvb.cpp @@ -21,13 +21,23 @@ #include -#define CALLEETYPE __stdcall -#define __RELIABILITY_CONTRACT - -#if defined _M_IX86 -#define CALLTYPE __thiscall +#if defined _M_CEE + #define CALLTYPE __clrcall + #define CALLEETYPE __clrcall + #define __RELIABILITY_CONTRACT \ + [System::Runtime::ConstrainedExecution::ReliabilityContract( \ + System::Runtime::ConstrainedExecution::Consistency::WillNotCorruptState, \ + System::Runtime::ConstrainedExecution::Cer::Success \ + )] #else -#define CALLTYPE __stdcall + #define CALLEETYPE __stdcall + #define __RELIABILITY_CONTRACT + + #if defined _M_IX86 + #define CALLTYPE __thiscall + #else + #define CALLTYPE __stdcall + #endif #endif using constructor_type = void (CALLTYPE*)(void*); diff --git a/src/crt/vcruntime/ehvecdtr.cpp b/src/crt/vcruntime/ehvecdtr.cpp index 82cfc31..4d4b75a 100644 --- a/src/crt/vcruntime/ehvecdtr.cpp +++ b/src/crt/vcruntime/ehvecdtr.cpp @@ -16,15 +16,28 @@ #include #include -#define CALLEETYPE __stdcall -#define __RELIABILITY_CONTRACT -#define ASSERT_UNMANAGED_CODE_ATTRIBUTE -#define SECURITYCRITICAL_ATTRIBUTE +#if defined _M_CEE + #define CALLTYPE __clrcall + #define CALLEETYPE __clrcall + #define __RELIABILITY_CONTRACT \ + [System::Runtime::ConstrainedExecution::ReliabilityContract( \ + System::Runtime::ConstrainedExecution::Consistency::WillNotCorruptState, \ + System::Runtime::ConstrainedExecution::Cer::Success \ + )] -#if defined _M_IX86 -#define CALLTYPE __thiscall + #define ASSERT_UNMANAGED_CODE_ATTRIBUTE [System::Security::Permissions::SecurityPermissionAttribute(System::Security::Permissions::SecurityAction::Assert, UnmanagedCode = true)] + #define SECURITYCRITICAL_ATTRIBUTE [System::Security::SecurityCritical] #else -#define CALLTYPE __stdcall + #define CALLEETYPE __stdcall + #define __RELIABILITY_CONTRACT + #define ASSERT_UNMANAGED_CODE_ATTRIBUTE + #define SECURITYCRITICAL_ATTRIBUTE + + #if defined _M_IX86 + #define CALLTYPE __thiscall + #else + #define CALLTYPE __stdcall + #endif #endif using destructor_type = void (CALLTYPE*)(void*); diff --git a/src/crt/vcruntime/frame.cpp b/src/crt/vcruntime/frame.cpp index ea5e9e3..17ddd65 100644 --- a/src/crt/vcruntime/frame.cpp +++ b/src/crt/vcruntime/frame.cpp @@ -202,6 +202,61 @@ inline ESTypeList* RENAME_EH_EXTERN(__FrameHandler3)::getESTypes(FuncInfo* pFunc return FUNC_PESTYPES(pFuncInfo); } +//////////////////////////////////////////////////////////////////////////////// +// +// __InternalCxxFrameHandlerWrapper - Wraps the frame handler so we have a place +// to apply cleanup on this function + +template +EXCEPTION_DISPOSITION __InternalCxxFrameHandler( + EHExceptionRecord* pExcept, // Information for this exception + EHRegistrationNode* pRN, // Dynamic information for this frame + CONTEXT* pContext, // Context info + DispatcherContext* pDC, // Context within subject frame + typename T::FuncInfo* pFuncInfo, // Static information for this frame + int CatchDepth, // How deeply nested are we? + EHRegistrationNode* pMarkerRN, // Marker node for when checking inside catch block + BOOLEAN recursive // Are we handling a translation? +); + +template +EXCEPTION_DISPOSITION __InternalCxxFrameHandlerWrapper( + EHExceptionRecord* pExcept, // Information for this exception + EHRegistrationNode* pRN, // Dynamic information for this frame + CONTEXT* pContext, // Context info + DispatcherContext* pDC, // Context within subject frame + typename T::FuncInfo* pFuncInfo, // Static information for this frame + int CatchDepth, // How deeply nested are we? + EHRegistrationNode* pMarkerRN, // Marker node for when checking inside catch block + BOOLEAN recursive // Are we handling a translation? +) { + +#if defined(_M_HYBRID_X86_ARM64) && !defined(_CHPE_X86_ARM64_EH_) + _HybridGenerateThunks(__InternalCxxFrameHandlerWrapper, 1); +#endif + + if constexpr (std::is_same_v) + { + __try + { + return __InternalCxxFrameHandler(pExcept, pRN, pContext, pDC, pFuncInfo, CatchDepth, pMarkerRN, recursive); + } + __finally + { +#if _VCRT_BUILD_FH4 + // For FrameHandler4, this value should always be invalid past an invocation of this function. + CatchStateInParent = INVALID_CATCH_SPECIFIC_STATE; +#endif + } + } + else + { + // Compile-time disable the __try/__finally unless we need it. On x86 even a no-op finally triggers a call + // to local_unwind and can change behavior of the handler. + return __InternalCxxFrameHandler(pExcept, pRN, pContext, pDC, pFuncInfo, CatchDepth, pMarkerRN, recursive); + } +} + //////////////////////////////////////////////////////////////////////////////// // // __InternalCxxFrameHandler - the frame handler for all functions with C++ EH @@ -227,8 +282,7 @@ EXCEPTION_DISPOSITION __InternalCxxFrameHandler( DispatcherContext *pDC, // Context within subject frame typename T::FuncInfo *pFuncInfo, // Static information for this frame int CatchDepth, // How deeply nested are we? - EHRegistrationNode *pMarkerRN, // Marker node for when checking inside - // catch block + EHRegistrationNode *pMarkerRN, // Marker node for when checking inside catch block BOOLEAN recursive // Are we handling a translation? ) { @@ -352,7 +406,7 @@ EXCEPTION_DISPOSITION __InternalCxxFrameHandler( } // __InternalCxxFrameHandler -template EXCEPTION_DISPOSITION __InternalCxxFrameHandler( +template EXCEPTION_DISPOSITION __InternalCxxFrameHandlerWrapper( EHExceptionRecord *pExcept, EHRegistrationNode *pRN, CONTEXT *pContext, @@ -364,7 +418,7 @@ template EXCEPTION_DISPOSITION __InternalCxxFrameHandler( +template EXCEPTION_DISPOSITION __InternalCxxFrameHandlerWrapper( EHExceptionRecord *pExcept, EHRegistrationNode *pRN, CONTEXT *pContext, diff --git a/src/crt/vcruntime/gs_report.cpp b/src/crt/vcruntime/gs_report.cpp index ecc7c6a..97de940 100644 --- a/src/crt/vcruntime/gs_report.cpp +++ b/src/crt/vcruntime/gs_report.cpp @@ -59,11 +59,11 @@ BEGIN_PRAGMA_OPTIMIZE_DISABLE("", DevDivVSO:162582, "Optimizations must be disab // __fastcall, it isn't a true argument, and we must flush ECX to the context // record quickly. #if defined _M_IX86 - #define GSFAILURE_PARAMETER void + #define GSFAILURE_PARAMETER #elif defined _M_X64 - #define GSFAILURE_PARAMETER ULONGLONG stack_cookie + #define GSFAILURE_PARAMETER _In_ ULONGLONG stack_cookie #elif defined _M_ARM || defined _M_ARM64 - #define GSFAILURE_PARAMETER uintptr_t stack_cookie + #define GSFAILURE_PARAMETER _In_ uintptr_t stack_cookie #else #error Unsupported architecture #endif @@ -72,7 +72,7 @@ BEGIN_PRAGMA_OPTIMIZE_DISABLE("", DevDivVSO:162582, "Optimizations must be disab #pragma warning(push) #pragma warning(disable: 4100) // unreferenced formal parameter -__declspec(noreturn) void __cdecl __report_gsfailure(_In_ GSFAILURE_PARAMETER) +__declspec(noreturn) void __cdecl __report_gsfailure(GSFAILURE_PARAMETER) { __fastfail(FAST_FAIL_STACK_COOKIE_CHECK_FAILURE); } diff --git a/src/crt/vcruntime/guard_support.cpp b/src/crt/vcruntime/guard_support.cpp index faef6b2..3631563 100644 --- a/src/crt/vcruntime/guard_support.cpp +++ b/src/crt/vcruntime/guard_support.cpp @@ -221,29 +221,29 @@ Return Value: static_assert(CAST_GUARD_SECTION_ALIGNMENT_IN_PTRS * sizeof(void*) == CAST_GUARD_SECTION_ALIGNMENT, "Invalid alignment"); // -// CastGuard checks lowered by the compiler, for efficiency, have an assumption that vftables laid out -// by CastGuard start at a 128-byte alignment for 64-bit and 64-byte alignment for 32-bit. The section these -// vftables are placed have this alignment specified by the compiler. -// -// __CastGuardVftableStart is a very special symbol. In order to do AppCompat checks correctly, -// we need to know the precise distance of __CastGuardVftablesStart variable from the first -// vftable laid out by CastGuard. The CastGuardVftablesB section (created by the compiler) -// is aligned by 16*sizeof(void*). The start variable therefore must have the exact same +// CastGuard checks lowered by the compiler, for efficiency, have an assumption that vftables laid out +// by CastGuard start at a 128-byte alignment for 64-bit and 64-byte alignment for 32-bit. The section these +// vftables are placed have this alignment specified by the compiler. +// +// __CastGuardVftableStart is a very special symbol. In order to do AppCompat checks correctly, +// we need to know the precise distance of __CastGuardVftablesStart variable from the first +// vftable laid out by CastGuard. The CastGuardVftablesB section (created by the compiler) +// is aligned by 16*sizeof(void*). The start variable therefore must have the exact same // alignment as the section such that there's always 16*sizeof(void*) bytes between the address -// of this variable and the address of the first vftable. -// -// If no vftables are laid out, __CastGuardVftablesStart will be 64/128 bytes away from the -// __CastGuardVftablesEnd global variable. The code in __castguard_compat_check explicitly -// adds this 64/128 bytes to the __CastGuardVftablesStart, so it's important to ensure that the -// alignment is always respected. -// +// of this variable and the address of the first vftable. +// +// If no vftables are laid out, __CastGuardVftablesStart will be 64/128 bytes away from the +// __CastGuardVftablesEnd global variable. The code in __castguard_compat_check explicitly +// adds this 64/128 bytes to the __CastGuardVftablesStart, so it's important to ensure that the +// alignment is always respected. +// struct __declspec(align(CAST_GUARD_SECTION_ALIGNMENT)) CastGuardVftables { char padding[CAST_GUARD_SECTION_ALIGNMENT]; }; __declspec(allocate(".rdata$CastGuardVftablesA")) -DECLSPEC_SELECTANY +DECLSPEC_SELECTANY struct CastGuardVftables __CastGuardVftablesStart; __declspec(allocate(".rdata$CastGuardVftablesC")) @@ -272,8 +272,8 @@ __cdecl __castguard_check_failure_os_handled_wrapper( { // - // This function is opted out of CFG because the os handled function pointer - // is allocated within ".00cfg" section. This section benefits from the same + // This function is opted out of CFG because the os handled function pointer + // is allocated within ".00cfg" section. This section benefits from the same // level of protection as a CFG pointer would. // diff --git a/src/crt/vcruntime/initialization.cpp b/src/crt/vcruntime/initialization.cpp index 12212e0..0b35be3 100644 --- a/src/crt/vcruntime/initialization.cpp +++ b/src/crt/vcruntime/initialization.cpp @@ -28,7 +28,7 @@ bool __cdecl __vcrt_initialize() return true; } -bool __cdecl __vcrt_uninitialize(_In_ bool terminating) +bool __cdecl __vcrt_uninitialize(_In_ bool const terminating) { UNREFERENCED_PARAMETER(terminating); diff --git a/src/crt/vcruntime/internal_shared.h b/src/crt/vcruntime/internal_shared.h index 0d163e3..c06de47 100644 --- a/src/crt/vcruntime/internal_shared.h +++ b/src/crt/vcruntime/internal_shared.h @@ -30,13 +30,32 @@ extern IMAGE_DOS_HEADER __ImageBase; // //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // Attributes for managed declarations in the CRT -#define _CRT_SUPPRESS_UNMANAGED_CODE_SECURITY -#define _CRT_CALLING_CONVENTION_CDECL -#define _CRT_CALLING_CONVENTION_WINAPI -#define _CRT_RELIABILITY_CONTRACT -#define _CRT_ASSERT_UNMANAGED_CODE_ATTRIBUTE -#define _CRT_SECURITYCRITICAL_ATTRIBUTE -#define _CRT_SECURITYSAFECRITICAL_ATTRIBUTE +#ifdef _M_CEE + #define _CRT_INTEROPSERVICES_DLLIMPORT(_DllName , _EntryPoint , _CallingConvention) \ + [System::Runtime::InteropServices::DllImport( \ + _DllName , EntryPoint = _EntryPoint, CallingConvention = _CallingConvention)] + #define _CRT_SUPPRESS_UNMANAGED_CODE_SECURITY [System::Security::SuppressUnmanagedCodeSecurity] + #define _CRT_CALLING_CONVENTION_CDECL System::Runtime::InteropServices::CallingConvention::Cdecl + #define _CRT_CALLING_CONVENTION_WINAPI System::Runtime::InteropServices::CallingConvention::Winapi + #define _CRT_RELIABILITY_CONTRACT \ + [System::Runtime::ConstrainedExecution::ReliabilityContract( \ + System::Runtime::ConstrainedExecution::Consistency::WillNotCorruptState, \ + System::Runtime::ConstrainedExecution::Cer::Success)] + #define _CRT_ASSERT_UNMANAGED_CODE_ATTRIBUTE \ + [System::Security::Permissions::SecurityPermissionAttribute( \ + System::Security::Permissions::SecurityAction::Assert, UnmanagedCode = true)] + #define _CRT_SECURITYCRITICAL_ATTRIBUTE [System::Security::SecurityCritical] + #define _CRT_SECURITYSAFECRITICAL_ATTRIBUTE [System::Security::SecuritySafeCritical] +#else + #define _CRT_INTEROPSERVICES_DLLIMPORT(_DllName , _EntryPoint , _CallingConvention) + #define _CRT_SUPPRESS_UNMANAGED_CODE_SECURITY + #define _CRT_CALLING_CONVENTION_CDECL + #define _CRT_CALLING_CONVENTION_WINAPI + #define _CRT_RELIABILITY_CONTRACT + #define _CRT_ASSERT_UNMANAGED_CODE_ATTRIBUTE + #define _CRT_SECURITYCRITICAL_ATTRIBUTE + #define _CRT_SECURITYSAFECRITICAL_ATTRIBUTE +#endif @@ -525,6 +544,14 @@ extern "C++" { return __crt_fast_encoded_nullptr_t(); } + + + //template + //T __crt_get_proc_address(HMODULE const m, char const* const f) noexcept + //{ + // return reinterpret_cast(::GetProcAddress(m, f)); + //} + template T* __crt_interlocked_exchange_pointer(T* const volatile* target, V const value) noexcept { @@ -543,7 +570,7 @@ extern "C++" { UNREFERENCED_PARAMETER(comparand); // unreferenced formal parameter warnings. static_assert(sizeof(T) == sizeof(LONG), "Type being compared must be same size as a LONG."); - return static_cast(InterlockedCompareExchange( + return static_cast(_InterlockedCompareExchange( reinterpret_cast(target), (LONG)exchange, (LONG)comparand)); } @@ -554,64 +581,69 @@ extern "C++" { UNREFERENCED_PARAMETER(exchange); // These are required to silence spurious UNREFERENCED_PARAMETER(comparand); // unreferenced formal parameter warnings. - return reinterpret_cast(InterlockedCompareExchangePointer( + return reinterpret_cast(_InterlockedCompareExchangePointer( (void**)target, (void*)exchange, (void*)comparand)); } - #if defined _M_ARM - #define __crt_interlocked_memory_barrier() (__dmb(_ARM_BARRIER_ISH)) - #elif defined _M_ARM64 - #define __crt_interlocked_memory_barrier() (__dmb(_ARM64_BARRIER_ISH)) - #endif + #ifndef _M_CEE_PURE - inline __int32 __crt_interlocked_read_32(__int32 const volatile* target) noexcept - { - #if defined _M_IX86 || defined _M_X64 - __int32 const result = *target; - _ReadWriteBarrier(); - return result; - #elif defined _M_ARM || defined _M_ARM64 - __int32 const result = __iso_volatile_load32(reinterpret_cast(target)); - __crt_interlocked_memory_barrier(); - return result; - #else - #error Unsupported architecture + #if defined _M_ARM + #define __crt_interlocked_memory_barrier() (__dmb(_ARM_BARRIER_ISH)) + #elif defined _M_ARM64 + #define __crt_interlocked_memory_barrier() (__dmb(_ARM64_BARRIER_ISH)) #endif - } - #if defined _WIN64 - inline __int64 __crt_interlocked_read_64(__int64 const volatile* target) noexcept + inline __int32 __crt_interlocked_read_32(__int32 const volatile* target) noexcept { - #if defined _M_X64 - __int64 const result = *target; + #if defined _M_IX86 || defined _M_X64 + __int32 const result = *target; _ReadWriteBarrier(); return result; - #elif defined _M_ARM64 - __int64 const result = __iso_volatile_load64(target); + #elif defined _M_ARM || defined _M_ARM64 + __int32 const result = __iso_volatile_load32(reinterpret_cast(target)); __crt_interlocked_memory_barrier(); return result; #else #error Unsupported architecture #endif } - #endif // _WIN64 - template - T __crt_interlocked_read(T const volatile* target) noexcept - { - static_assert(sizeof(T) == sizeof(__int32), "Type being read must be 32 bits in size."); - return (T)__crt_interlocked_read_32((__int32*)target); - } + #if defined _WIN64 + inline __int64 __crt_interlocked_read_64(__int64 const volatile* target) noexcept + { + #if defined _M_X64 + __int64 const result = *target; + _ReadWriteBarrier(); + return result; + #elif defined _M_ARM64 + __int64 const result = __iso_volatile_load64(target); + __crt_interlocked_memory_barrier(); + return result; + #else + #error Unsupported architecture + #endif + } + #endif // _WIN64 - template - T* __crt_interlocked_read_pointer(T* const volatile* target) noexcept - { - #ifdef _WIN64 - return (T*)__crt_interlocked_read_64((__int64*)target); - #else - return (T*)__crt_interlocked_read_32((__int32*)target); - #endif - } + template + T __crt_interlocked_read(T const volatile* target) noexcept + { + static_assert(sizeof(T) == sizeof(__int32), "Type being read must be 32 bits in size."); + return (T)__crt_interlocked_read_32((__int32*)target); + } + + + template + T* __crt_interlocked_read_pointer(T* const volatile* target) noexcept + { + #ifdef _WIN64 + return (T*)__crt_interlocked_read_64((__int64*)target); + #else + return (T*)__crt_interlocked_read_32((__int32*)target); + #endif + } + + #endif // _M_CEE_PURE } // extern "C++" #endif // __cplusplus diff --git a/src/crt/vcruntime/riscchandler.cpp b/src/crt/vcruntime/riscchandler.cpp index fac2773..2e6e59e 100644 --- a/src/crt/vcruntime/riscchandler.cpp +++ b/src/crt/vcruntime/riscchandler.cpp @@ -83,7 +83,7 @@ __C_ExecuteTerminationHandler( #define DC_TARGETPC(DispatcherContext) ((DispatcherContext)->TargetIp) __forceinline -LONG +LONG EXECUTE_EXCEPTION_FILTER( _In_ PEXCEPTION_POINTERS ExceptionPointers, _In_ PVOID EstablisherFrame, @@ -207,3 +207,317 @@ __except_validate_context_record ( #error Unknown processor architecture. #endif + +#if 0 +extern "C" +#if defined(_M_X64) + +__declspec(guard(ignore)) + +#endif + +DECLSPEC_GUARD_SUPPRESS +EXCEPTION_DISPOSITION +__C_specific_handler ( + _In_ PEXCEPTION_RECORD ExceptionRecord, + _In_ PVOID EstablisherFrame, + _Inout_ PCONTEXT ContextRecord, + _Inout_ PDISPATCHER_CONTEXT DispatcherContext + ) + +/*++ + +Routine Description: + + This function scans the scope tables associated with the specified + procedure and calls exception and termination handlers as necessary. + +Arguments: + + ExceptionRecord - Supplies a pointer to an exception record. + + EstablisherFrame - Supplies a pointer to frame of the establisher function. + + ContextRecord - Supplies a pointer to a context record. + + DispatcherContext - Supplies a pointer to the exception dispatcher or + unwind dispatcher context. + + N.B. SHRINK WRAPPING MUST BE DISABLED FOR THIS FUNCTION. + +Return Value: + + If an exception is being dispatched and the exception is handled by one + of the exception filter routines, then there is no return from this + routine and RtlUnwind is called. Otherwise, an exception disposition + value of continue execution or continue search is returned. + + If an unwind is being dispatched, then each termination handler is called + and a value of continue search is returned. + +--*/ + +{ + + ULONG_PTR ControlPc; + PEXCEPTION_FILTER ExceptionFilter; + EXCEPTION_POINTERS ExceptionPointers; + ULONG_PTR ImageBase; + ULONG_PTR Handler; + ULONG Index; + PSCOPE_TABLE ScopeTable; + ULONG TargetIndex; + ULONG_PTR TargetPc; + PTERMINATION_HANDLER TerminationHandler; + LONG Value; + + DISABLE_SHRINK_WRAPPING(); + +#if defined(_M_X64) + + // + // Validate integrity of context record. + // + __except_validate_context_record(ContextRecord); + +#endif + + // + // Get the image base address. compute the relative address of where + // control left the establisher, and get the address of the scope table. + // + + ImageBase = DispatcherContext->ImageBase; + ControlPc = DispatcherContext->ControlPc - ImageBase; + ScopeTable = (PSCOPE_TABLE)(DispatcherContext->HandlerData); + +#if defined(_M_ARM64EC) + + if (RtlIsEcCode((DispatcherContext->ControlPc))) { + PDISPATCHER_CONTEXT_ARM64EC DispatcherContextEc; + DispatcherContextEc = (PDISPATCHER_CONTEXT_ARM64EC)DispatcherContext; + + if ((ScopeTable->Count & (1 << 31)) != 0) { + ScopeTable = (PSCOPE_TABLE)(ImageBase + (ScopeTable->Count & ~(1 << 31))); + } + + if (DispatcherContextEc->ControlPcIsUnwound != FALSE) { + ControlPc -= 4; + } + } + +#elif defined(_M_ARM_NT) || defined(_M_ARM64) || defined(_CHPE_X86_ARM64_EH_) + + // + // Do we have an indirect scope table? + // + + if ((ScopeTable->Count & (1 << 31)) != 0) { + ScopeTable = (PSCOPE_TABLE)(ImageBase + (ScopeTable->Count & ~(1 << 31))); + } + + // + // If this context came from an unwind to a call, then the ControlPc points + // to a return address, which could put us at the start of a neighboring + // scope. To correct for this, back the PC up by the minimum instruction + // size to ensure we are in the same scope as the original branch opcode. + // + + if (DispatcherContext->ControlPcIsUnwound != FALSE) { + +#if defined(_M_ARM_NT) + + ControlPc -= 2; + +#else + + ControlPc -= 4; + +#endif + + } + +#endif // defined(_M_ARM_NT) || defined(_M_ARM64) || defined(_CHPE_X86_ARM64_EH_) + + // + // If an unwind is not in progress, then scan the scope table and call + // the appropriate exception filter routines. Otherwise, scan the scope + // table and call the appropriate termination handlers using the target + // PC obtained from the dispatcher context. + // + + if (IS_DISPATCHING(ExceptionRecord->ExceptionFlags)) { + + // + // Scan the scope table and call the appropriate exception filter + // routines. + // + + ExceptionPointers.ExceptionRecord = ExceptionRecord; + ExceptionPointers.ContextRecord = ContextRecord; + for (Index = DispatcherContext->ScopeIndex; Index < ScopeTable->Count; Index += 1) { + if ((ControlPc >= ScopeTable->ScopeRecord[Index].BeginAddress) && + (ControlPc < ScopeTable->ScopeRecord[Index].EndAddress) && + (ScopeTable->ScopeRecord[Index].JumpTarget != 0)) { + + // + // If the filter function address is the distinguished value + // one, then set the disposition value to execute handler. + // Otherwise, call the exception filter function to get the + // disposition value. + // + + if (ScopeTable->ScopeRecord[Index].HandlerAddress == 1) { + Value = EXCEPTION_EXECUTE_HANDLER; + + } else { + ExceptionFilter = + (PEXCEPTION_FILTER)(ScopeTable->ScopeRecord[Index].HandlerAddress + ImageBase); + + Value = EXECUTE_EXCEPTION_FILTER(&ExceptionPointers, + EstablisherFrame, + ExceptionFilter, + DispatcherContext); + } + + // + // If the return value is less than zero, then dismiss the + // exception. Otherwise, if the value is greater than zero, + // then unwind to the target exception handler. Otherwise, + // continue the search for an exception filter. + // + + if (Value < 0) { + return ExceptionContinueExecution; + + } else if (Value > 0) { + + // + // If a thrown C++ exception is being handled, then let + // the C++ exception handler destruct the thrown object. + // + +#ifndef _NTSUBSET_ + + if ((ExceptionRecord->ExceptionCode == EH_EXCEPTION_NUMBER) && + (_pDestructExceptionObject != NULL) && + (_IsNonwritableInCurrentImage(&_pDestructExceptionObject))) { + + (*_pDestructExceptionObject)(ExceptionRecord, TRUE); + } + +#endif + + // + // Inform the debugger that control is about to be passed + // to an exception handler and pass the handler's address + // to NLG_Notify. + // + + Handler = ImageBase + ScopeTable->ScopeRecord[Index].JumpTarget; + _NLG_Notify((PVOID)Handler, EstablisherFrame, 0x1); + RtlUnwindEx(EstablisherFrame, + (PVOID)(ScopeTable->ScopeRecord[Index].JumpTarget + ImageBase), + ExceptionRecord, + (PVOID)((ULONG_PTR)ExceptionRecord->ExceptionCode), + (PCONTEXT)DispatcherContext->ContextRecord, + DispatcherContext->HistoryTable); + + + // + // Notify debugger : return from exception handler + // + + __NLG_Return2(); + } + } + } + + } else { + + // + // Scan the scope table and call the appropriate termination handler + // routines. + // + + TargetPc = DC_TARGETPC(DispatcherContext) - ImageBase; + for (Index = DispatcherContext->ScopeIndex; Index < ScopeTable->Count; Index += 1) { + if ((ControlPc >= ScopeTable->ScopeRecord[Index].BeginAddress) && + (ControlPc < ScopeTable->ScopeRecord[Index].EndAddress)) { + + if (IS_TARGET_UNWIND(ExceptionRecord->ExceptionFlags)) { + + // + // If the target PC is within the same scope as the control PC, + // then this is an uplevel goto out of an inner try scope or a + // long jump back into a try scope. Terminate the scan for a + // termination handler. + // + // N.B. Due to a bug in the AMD64 compiler, try scopes may + // be split into multiple regions, requiring a scan + // of the earlier region of the table to verify that + // the target PC is not within the same try scope. + // The split scopes could reside both before or after + // the currently searched scope in the scope table. + // + // N.B. The target PC can be just beyond the end of the + // scope in which case it is a leave from a scope. + // The "leave from a scope" case is subsequently + // handled before control is transferred. + // + + for (TargetIndex = 0; TargetIndex < ScopeTable->Count; TargetIndex += 1) { + if ((TargetPc >= ScopeTable->ScopeRecord[TargetIndex].BeginAddress) && + (TargetPc < ScopeTable->ScopeRecord[TargetIndex].EndAddress) && + (ScopeTable->ScopeRecord[TargetIndex].JumpTarget == ScopeTable->ScopeRecord[Index].JumpTarget) && + (ScopeTable->ScopeRecord[TargetIndex].HandlerAddress == ScopeTable->ScopeRecord[Index].HandlerAddress)) { + + break; + } + } + + if (TargetIndex != ScopeTable->Count) { + break; + } + } + + // + // If the scope table entry describes an exception filter + // and the associated exception handler is the target of + // the unwind, then terminate the scan for termination + // handlers. Otherwise, if the scope table entry describes + // a termination handler, then record the address of the + // end of the scope as the new control PC address and call + // the termination handler. + // + + if (ScopeTable->ScopeRecord[Index].JumpTarget != 0) { + if ((TargetPc == ScopeTable->ScopeRecord[Index].JumpTarget) && + (IS_TARGET_UNWIND(ExceptionRecord->ExceptionFlags))) { + + break; + } + + } else { + DispatcherContext->ScopeIndex = Index + 1; + TerminationHandler = + (PTERMINATION_HANDLER)(ScopeTable->ScopeRecord[Index].HandlerAddress + ImageBase); + + EXECUTE_TERMINATION_HANDLER(TRUE, + EstablisherFrame, + TerminationHandler, + DispatcherContext); + } + } + } + } + + // + // Continue search for exception or termination handlers. + // + + ENABLE_SHRINK_WRAPPING(); + + return ExceptionContinueSearch; +} +#endif \ No newline at end of file diff --git a/src/crt/vcruntime/risctrnsctrl.cpp b/src/crt/vcruntime/risctrnsctrl.cpp index 75be875..0934284 100644 --- a/src/crt/vcruntime/risctrnsctrl.cpp +++ b/src/crt/vcruntime/risctrnsctrl.cpp @@ -278,7 +278,7 @@ extern "C" DECLSPEC_GUARD_SUPPRESS EXCEPTION_DISPOSITION __cdecl RENAME_EH_EXTER _ThrowImageBase = (uintptr_t)pExcept->params.pThrowImageBase; #endif pFuncInfo = (FuncInfo*)(_ImageBase +*(PULONG)pDC->HandlerData); - result = __InternalCxxFrameHandler(pExcept, &EstablisherFrame, pContext, pDC, pFuncInfo, 0, nullptr, FALSE); + result = __InternalCxxFrameHandlerWrapper(pExcept, &EstablisherFrame, pContext, pDC, pFuncInfo, 0, nullptr, FALSE); return result; } @@ -301,7 +301,7 @@ extern "C" DECLSPEC_GUARD_SUPPRESS EXCEPTION_DISPOSITION __cdecl RENAME_EH_EXTER FH4::DecompFuncInfo(buffer, FuncInfo, pDC->ImageBase, pDC->FunctionEntry->BeginAddress); - result = __InternalCxxFrameHandler(pExcept, &EstablisherFrame, pContext, pDC, &FuncInfo, 0, nullptr, FALSE); + result = __InternalCxxFrameHandlerWrapper(pExcept, &EstablisherFrame, pContext, pDC, &FuncInfo, 0, nullptr, FALSE); return result; } #endif // _VCRT_BUILD_FH4 @@ -348,6 +348,7 @@ static int SehTransFilter( UNREFERENCED_PARAMETER(curState); _pForeignExcept = pExcept; + _ImageBase = pDC->ImageBase; #ifdef _ThrowImageBase _ThrowImageBase = (uintptr_t)((EHExceptionRecord *)ExPtrs->ExceptionRecord)->params.pThrowImageBase; #endif @@ -355,13 +356,13 @@ static int SehTransFilter( #if _VCRT_BUILD_FH4 if constexpr (std::is_same_v) { - // For FH4, the catch state from rethrow is transient and only readable one time before being reset. + // For FH4, the catch state from rethrow is transient and only readable one time before being reset. // This path reprocesses a throw which means the transient state needs to be set again so the correct state is used. CatchStateInParent = curState; } #endif - __InternalCxxFrameHandler((EHExceptionRecord *)ExPtrs->ExceptionRecord, + __InternalCxxFrameHandlerWrapper((EHExceptionRecord *)ExPtrs->ExceptionRecord, pRN, pContext, pDC, @@ -647,7 +648,7 @@ void RENAME_EH_EXTERN(__FrameHandler4)::UnwindNestedFrames( ExceptionRecord.ExceptionInformation[7] = (ULONG_PTR)recursive; // Used for translated Exceptions ExceptionRecord.ExceptionInformation[8] = EH_MAGIC_NUMBER1; - // Used in __InternalCxxFrameHandler to detected if it's being + // Used in __InternalCxxFrameHandler to detect if it's being // called from _UnwindNestedFrames. // TODO: make these contiguous @@ -729,7 +730,7 @@ void RENAME_EH_EXTERN(__FrameHandler3)::UnwindNestedFrames( ExceptionRecord.ExceptionInformation[7] = (ULONG_PTR)recursive; // Used for translated Exceptions ExceptionRecord.ExceptionInformation[8] = EH_MAGIC_NUMBER1; - // Used in __InternalCxxFrameHandler to detected if it's being + // Used in __InternalCxxFrameHandler to detect if it's being // called from _UnwindNestedFrames. #if defined(_M_ARM64EC) diff --git a/src/crt/vcruntime/undname.cxx b/src/crt/vcruntime/undname.cxx index f951916..7126347 100644 --- a/src/crt/vcruntime/undname.cxx +++ b/src/crt/vcruntime/undname.cxx @@ -101,7 +101,7 @@ class UnDecorator; const unsigned int memBlockSize = 4096; // Dev10 bug 662979 -// undname will be pullled into libcmt.lib. Prefix with underscore to prevent potential conflict with user code. +// undname will be pulled into libcmt.lib. Prefix with underscore to prevent potential conflict with user code. class _HeapManager { private: @@ -609,6 +609,57 @@ class UnDecorator static bool fExplicitTemplateParams; static bool fGetTemplateArgumentList; + // Increment the internal buffer 'gName' by 'count' characters. + // If it passes the terminating null, return false. Otherwise, return true. + static [[nodiscard]] bool increment_buffer(size_t count) + { + DASSERT(count > 0); + + for (size_t i = 0; i < count; ++i) + { + if (*gName == 0) + { + return false; + } + + ++gName; + } + + return true; + } + + // Increment the internal buffer 'gName' by 'count' characters. + // The caller ensures that it won't pass the terminating null. + static void increment_buffer_no_check(size_t count) + { + DASSERT(count > 0); + + for (size_t i = 0; i < count; ++i) + { + DASSERT(gName[i] != 0); + } + + gName += count; + } + + // Increment the internal buffer 'gName' by one character. + // The caller ensures that it won't pass the terminating null. + static void increment_buffer_no_check() + { + DASSERT(*gName != 0); + ++gName; + } + + // Get the current character pointed by the internal buffer 'gName'. + // If the current character isn't the terminating null, increment the buffer + // by one character. + static [[nodiscard]] char get_current_character_and_increment_buffer() + { + char c = *gName; + if (c) ++gName; + return c; + } + static DName getDecoratedName(void); static DName getSymbolName(void); static DName getZName(bool fUpdateCachedNames, bool fAllowEmptyName = false); @@ -890,6 +941,8 @@ inline UnDecorator::UnDecorator( DName UnDecorator::parseDecoratedName(void) { + DASSERT(name == gName); + DName result; // Find out if the name is a decorated name or not. Could be a reserved @@ -900,7 +953,7 @@ DName UnDecorator::parseDecoratedName(void) if ((*name == '?') && (name[1] == '@')) { #if ( !NO_COMPILER_NAMES ) - gName += 2; + gName = name + 2; result = "CV: "_l + getDecoratedName(); #else // elif NO_COMPILER_NAMES result = DN_invalid; @@ -1111,7 +1164,7 @@ DName UnDecorator::getDecoratedName(void) { // Extract the basic symbol name - gName++; // Advance the original name pointer + increment_buffer_no_check(); // Advance the original name pointer // What!?!? we have a name that starts with '???' how is this possible? // Easy: consider code like the following: @@ -1141,7 +1194,7 @@ DName UnDecorator::getDecoratedName(void) // to keep the CLR happy while (*gName != '\0') { - ++gName; + increment_buffer_no_check(); } return result; @@ -1196,7 +1249,7 @@ DName UnDecorator::getDecoratedName(void) else if(!*gName || (*gName == '@')) { if (*gName) - gName++; + increment_buffer_no_check(); if (doNameOnly() && !udcSeen && !symbolName.isVCallThunk()) { @@ -1234,7 +1287,7 @@ inline DName UnDecorator::getSymbolName() } else { - gName += 1; + increment_buffer_no_check(); return getOperatorName(false, NULL); } @@ -1255,7 +1308,7 @@ DName UnDecorator::getZName(bool fUpdateCachedNames, bool fAllowEmptyName) if ((zNameIndex >= 0) && (zNameIndex <= 9)) { - gName++; // Skip past the replicator + increment_buffer_no_check(); // Skip past the replicator // And return the indexed name @@ -1270,8 +1323,15 @@ DName UnDecorator::getZName(bool fUpdateCachedNames, bool fAllowEmptyName) { zName = getTemplateName(false); - if (*gName++ != '@') - zName = *--gName ? DN_invalid : DN_truncated; + char c = *gName; + if (c == '@') + { + increment_buffer_no_check(); + } + else + { + zName = c ? DN_invalid : DN_truncated; + } } else { @@ -1288,13 +1348,13 @@ DName UnDecorator::getZName(bool fUpdateCachedNames, bool fAllowEmptyName) { isGenericType = true; genericType = TEMPLATE_PARAMETER_STRING_LITERAL; - gName += TEMPLATE_PARAMETER_LEN; + increment_buffer_no_check(TEMPLATE_PARAMETER_LEN); } else if (und_strncmp(gName, GENERIC_TYPE, GENERIC_TYPE_LEN) == 0) { isGenericType = true; genericType = GENERIC_TYPE_STRING_LITERAL; - gName += GENERIC_TYPE_LEN; + increment_buffer_no_check(GENERIC_TYPE_LEN); } if (isGenericType) @@ -1325,7 +1385,7 @@ DName UnDecorator::getZName(bool fUpdateCachedNames, bool fAllowEmptyName) { // Empty zname is used in old-style template function decorated names zName = DName(); - gName += 1; + increment_buffer_no_check(); } else { @@ -1359,11 +1419,9 @@ inline DName UnDecorator::getOperatorName(bool fIsTemplate, bool *pfReadTemplate // So what type of operator is it ? - switch (*gName++) + switch (get_current_character_and_increment_buffer()) { case 0: - gName--; // End of string, better back-track - return DName(DN_truncated); case OC_ctor: @@ -1408,7 +1466,7 @@ inline DName UnDecorator::getOperatorName(bool fIsTemplate, bool *pfReadTemplate return templateArguments; } - gName += 1; + increment_buffer_no_check(); } // @@ -1481,11 +1539,9 @@ inline DName UnDecorator::getOperatorName(bool fIsTemplate, bool *pfReadTemplate break; case '_': - switch (*gName++) + switch (get_current_character_and_increment_buffer()) { case 0: - gName--; // End of string, better back-track - return DName(DN_truncated); case OC_asdiv: @@ -1560,7 +1616,7 @@ inline DName UnDecorator::getOperatorName(bool fIsTemplate, bool *pfReadTemplate tmpName = rttiTable[index]; - switch (*gName++) + switch (get_current_character_and_increment_buffer()) { case OC_rtti_TD: { @@ -1583,10 +1639,11 @@ inline DName UnDecorator::getOperatorName(bool fIsTemplate, bool *pfReadTemplate case OC_rtti_COL: return operatorName + tmpName; break; + case 0: + return DName(DN_truncated); default: gName--; return DName(DN_truncated); - break; } break; @@ -1603,12 +1660,10 @@ inline DName UnDecorator::getOperatorName(bool fIsTemplate, bool *pfReadTemplate // Yet another level of nested encodings.... case '?': - switch (*gName++) + switch (get_current_character_and_increment_buffer()) { case 0: - gName--; // End of string, better back-track - return DName(DN_truncated); case OC_anonymousNamespace: @@ -1633,7 +1688,7 @@ inline DName UnDecorator::getOperatorName(bool fIsTemplate, bool *pfReadTemplate // A double extended operator // case '_': - switch (*gName++) + switch (get_current_character_and_increment_buffer()) { case OC_man_vec_ctor: case OC_man_vec_dtor: @@ -1677,7 +1732,7 @@ inline DName UnDecorator::getOperatorName(bool fIsTemplate, bool *pfReadTemplate // the next section if (*gName == '@') { - gName += 1; + increment_buffer_no_check(); } } else @@ -1700,20 +1755,23 @@ inline DName UnDecorator::getOperatorName(bool fIsTemplate, bool *pfReadTemplate while (*gName != '\0' && *gName != '@') { - result += *gName++; + result += *gName; + increment_buffer_no_check(); } if (*gName == '@') { - gName += 1; + increment_buffer_no_check(); } return result; } break; case OC_NTTP_class_type: - if (*gName++ == TC_value_object) + if (get_current_character_and_increment_buffer() == TC_value_object) + { return getValueObject(); + } return DName(DN_invalid); default: return DName(DN_invalid); @@ -1747,13 +1805,17 @@ DName UnDecorator::getStringEncoding(PrefixKind kind, int /*unused*/) DName result(PrefixName[static_cast(kind)]); // First @ comes right after operator code - if (*gName++ != '@' || *gName++ != '_') + if (get_current_character_and_increment_buffer() != '@' || + get_current_character_and_increment_buffer() != '_') { return DName(DN_invalid); } // Skip the string kind - gName++; + if (!increment_buffer(1)) + { + return DName(DN_truncated); + } // Get (& discard) the length getDimension(); @@ -1764,7 +1826,7 @@ DName UnDecorator::getStringEncoding(PrefixKind kind, int /*unused*/) while (*gName && *gName != '@') { // For now, we'll just skip it - gName++; + increment_buffer_no_check(); } if (!*gName) @@ -1774,7 +1836,7 @@ DName UnDecorator::getStringEncoding(PrefixKind kind, int /*unused*/) } // Eat the terminating '@' - gName++; + increment_buffer_no_check(); return result; } @@ -1809,7 +1871,9 @@ DName UnDecorator::getScope(void) // Determine what kind of scope it is if (*gName == '?') - switch (*++gName) + { + increment_buffer_no_check(); + switch (*gName) { case '?': if (gName[1] == '_' && gName[2] == '?') @@ -1817,13 +1881,13 @@ DName UnDecorator::getScope(void) // // Anonymous namespace name (new style) // - gName++; + increment_buffer_no_check(); scope = getOperatorName(false, NULL) + scope; // There should be a zname termination @... if (*gName == '@') { - gName++; + increment_buffer_no_check(); } } else @@ -1865,7 +1929,7 @@ DName UnDecorator::getScope(void) // This is the interface whose method the class is // implementing // - gName++; + increment_buffer_no_check(); scope = getZName(true) + ']' + scope; fNeedBracket = true; break; @@ -1874,7 +1938,7 @@ DName UnDecorator::getScope(void) { DName explicitScope; - ++gName; + increment_buffer_no_check(); do { DName scopeName = getZName(true); @@ -1899,7 +1963,8 @@ DName UnDecorator::getScope(void) if (explicitScope.status() == DN_valid) { scope = '[' + explicitScope + ']'; - ++gName; + DASSERT(*gName == '@'); + increment_buffer_no_check(); } else { @@ -1912,6 +1977,7 @@ DName UnDecorator::getScope(void) break; } // End of SWITCH + } else scope = getZName(true) + scope; @@ -1950,7 +2016,7 @@ DName UnDecorator::getSignedDimension(void) return DName(DN_truncated); else if(*gName == '?') { - gName++; // skip the '?' + increment_buffer_no_check(); // skip the '?' return '-' + getDimension(); } else @@ -1967,22 +2033,24 @@ DName UnDecorator::getDimension(bool is_signed) if (*gName == TC_nontype_dummy) { has_prefix = true; - ++gName; + increment_buffer_no_check(); } if (*gName == '\0') return DName(DN_truncated); if ((*gName >= '0') && (*gName <= '9')) - return has_prefix ? - (prefix + DName(static_cast(*gName++ - '0' + 1))) : - DName(static_cast(*gName++ - '0' + 1)); + { + uint64_t dim = static_cast(*gName - '0' + 1); + increment_buffer_no_check(); + return has_prefix ? (prefix + DName(dim)) : DName(dim); + } if (auto result = getValue()) { // Consume the terminating '@' DASSERT(*gName == '@'); - ++gName; + increment_buffer_no_check(); auto value = *result; if (is_signed) { @@ -2012,7 +2080,7 @@ std::optional UnDecorator::getValue() value = (value << 4) + (c - 'A'); else return { }; - ++gName; + increment_buffer_no_check(); } } @@ -2032,12 +2100,16 @@ DName UnDecorator::getFloatingPoint(int type_category) return DName(DN_truncated); if ((*gName >= '0') && (*gName <= '9')) - return DName(static_cast(*gName++ - '0' + 1)); - + { + uint64_t dim = static_cast(*gName - '0' + 1); + increment_buffer_no_check(); + return DName(dim); + } + if (auto result = getValue()) { // Skip the terminator - ++gName; + increment_buffer_no_check(); auto value = *result; if (type_category == TC_double) @@ -2078,15 +2150,15 @@ DName UnDecorator::getValueObject() switch (*gName) { case TC_value_object: - ++gName; // Consume 'TC_value_object' + increment_buffer_no_check(); // Consume 'TC_value_object' encoding += getValueObject(); break; case TC_array_object: - ++gName; // Consume 'TC_array_object' + increment_buffer_no_check(); // Consume 'TC_array_object' encoding += getArrayObject(); break; case TC_string_object: - ++gName; // Consume 'TC_string_object' + increment_buffer_no_check(); // Consume 'TC_string_object' encoding += getStringObject(); break; case '@': @@ -2105,7 +2177,7 @@ DName UnDecorator::getValueObject() if (*gName == '@') { - ++gName; // Consume the '@' + increment_buffer_no_check(); // Consume the '@' break; } need_comma = true; @@ -2134,11 +2206,11 @@ DName UnDecorator::getArrayObject() if (*gName != '@') return DName(DN_invalid); - ++gName; // Consume the separator '@' character + increment_buffer_no_check(); // Consume the separator '@' character if (*gName == '@') { - ++gName; // Consume the final '@' + increment_buffer_no_check(); // Consume the final '@' break; } @@ -2159,7 +2231,7 @@ DName UnDecorator::getStringObject() // First we need to skip the string literal prefix which is "??_C" if (strncmp(gName, "??_C", std::size("??_C") - 1) == 0) { - gName += std::size("??_C") - 1; + increment_buffer_no_check(std::size("??_C") - 1); return getStringEncoding(PrefixKind::StringLiteral, true); } return DName(DN_invalid); @@ -2174,7 +2246,7 @@ DName UnDecorator::getAddressOf() if (*gName == '@') { // Consume the terminating '@' - ++gName; + increment_buffer_no_check(); return encoding; } return DName(DN_invalid); @@ -2190,7 +2262,7 @@ DName UnDecorator::getMemberAccess() if (*gName == '@') { // Consume the terminating '@' - ++gName; + increment_buffer_no_check(); return encoding; } return DName(DN_invalid); @@ -2207,7 +2279,7 @@ DName UnDecorator::getArrayAccess() if (*gName == '@') { // Consume the terminating '@' - ++gName; + increment_buffer_no_check(); return encoding; } @@ -2230,7 +2302,7 @@ DName UnDecorator::getUnionObject() if (*gName == '@') { // Consume the terminating '@' - ++gName; + increment_buffer_no_check(); return encoding; } return DName(DN_invalid); @@ -2245,13 +2317,13 @@ DName UnDecorator::getPointerToMember() if (encoding.isValid() && (*gName == '@')) { // Consume the '@' that terminates the scope encoding - gName++; + increment_buffer_no_check(); encoding += "::"_l; encoding += getZName(false, false); if (*gName == '@') { // Consume the terminating '@' - ++gName; + increment_buffer_no_check(); return encoding; } } @@ -2263,8 +2335,12 @@ int UnDecorator::getNumberOfDimensions(void) { if (!*gName) return 0; - else if((*gName >= '0') && (*gName <= '9')) - return ((*gName++ - '0') + 1); + else if ((*gName >= '0') && (*gName <= '9')) + { + int dim = (*gName - '0') + 1; + increment_buffer_no_check(); + return dim; + } else { int dim = 0; @@ -2281,15 +2357,14 @@ int UnDecorator::getNumberOfDimensions(void) else return -1; - gName++; + increment_buffer_no_check(); } // End of WHILE // Ensure integrity, and return - if (*gName++ != '@') - return -1; // Should never get here - + DASSERT(*gName == '@'); + increment_buffer_no_check(); return dim; } // End of else if else @@ -2304,7 +2379,7 @@ DName UnDecorator::getTemplateName(bool fReadTerminator) if (gName[0] != '?' || gName[1] != '$') return DName(DN_invalid); - gName += 2; // Skip the marker characters + increment_buffer_no_check(2); // Skip the marker characters // // Stack the replicators, since template names are their own replicator scope: @@ -2327,7 +2402,7 @@ DName UnDecorator::getTemplateName(bool fReadTerminator) if (*gName == '?') { - gName += 1; + increment_buffer_no_check(); templateName = getOperatorName(true, &fReadTemplateArguments); } @@ -2359,7 +2434,7 @@ DName UnDecorator::getTemplateName(bool fReadTerminator) if (fReadTerminator && *gName) { - gName += 1; + increment_buffer_no_check(); } } @@ -2408,7 +2483,7 @@ DName UnDecorator::getTemplateArgumentList(void) if ((argIndex >= 0) && (argIndex <= 9)) { - gName++; // Skip past the replicator + increment_buffer_no_check(); // Skip past the replicator // Argument to append to the argument list @@ -2426,21 +2501,21 @@ DName UnDecorator::getTemplateArgumentList(void) { case PDT_packExpansion: havePackExpansion = true; - gName += 3; + increment_buffer_no_check(3); break; case PDT_placeHolder: - gName += 3; + increment_buffer_no_check(3); break; case PDT_empty: case PDT_terminator: - gName += 3; + increment_buffer_no_check(3); skipArgument = true; break; case PDT_extend: // We have a bug (in older builds of the compiler) in which 'empty' is encoded with an extra '$' if (*(gName + 3) == PDT_empty) { - gName += 4; + increment_buffer_no_check(4); skipArgument = true; } break; @@ -2457,7 +2532,7 @@ DName UnDecorator::getTemplateArgumentList(void) // Extract the 'argument' type if ((*gName == '$') && (gName[1] != '$')) { - gName++; + increment_buffer_no_check(); arg = getTemplateNonTypeArgument(); } else @@ -2528,7 +2603,7 @@ DName UnDecorator::getTemplateNonTypeArgument(void) // '1' // '2' // - char type_category = *gName++; + char type_category = get_current_character_and_increment_buffer(); switch (type_category) { // @@ -2546,7 +2621,7 @@ DName UnDecorator::getTemplateNonTypeArgument(void) case TC_address: if (*gName == TC_nullptr) { - gName++; + increment_buffer_no_check(); return DName("NULL"_l); } else @@ -2684,12 +2759,9 @@ DName UnDecorator::getTemplateNonTypeArgument(void) (void) getDimension(); return DName("lambda"_l); case '\0': - --gName; return DName(DN_truncated); - break; default: return DName(DN_invalid); - break; } } @@ -2697,7 +2769,7 @@ DName UnDecorator::getTemplateTypeArgument(void) { if (*gName == BDT_void) { - gName++; + increment_buffer_no_check(); return DName("void"_l); } else if (*gName == '?') @@ -3064,7 +3136,7 @@ inline int UnDecorator::getTypeEncoding(void) { TE_setisbased(typeCode); - gName++; + increment_buffer_no_check(); } // End of IF @@ -3072,8 +3144,8 @@ inline int UnDecorator::getTypeEncoding(void) if ((*gName >= 'A') && (*gName <= 'Z')) // Is it some sort of function ? { - int code = *gName++ - 'A'; - + int code = *gName - 'A'; + increment_buffer_no_check(); // Now determine the function type @@ -3144,9 +3216,11 @@ inline int UnDecorator::getTypeEncoding(void) } // End of IF then else if(*gName == '$') // Extended set ? Special handling { + increment_buffer_no_check(); + // What type of symbol is it ? bool isVtorDispThunkEx = false; - switch (*(++gName)) + switch (*gName) { case SHF_localdtor: // A destructor helper for a local static ? TE_setislocaldtor(typeCode); @@ -3169,12 +3243,13 @@ inline int UnDecorator::getTypeEncoding(void) case '$': { - if (*(gName + 1) == SHF_AnyDLLImportMethod) + increment_buffer_no_check(); + if (*gName == SHF_AnyDLLImportMethod) { - gName += 1; + increment_buffer_no_check(); } - switch (*(++gName)) + switch (*gName) { case SHF_CPPManagedILFunction: // C++ managed-IL function case SHF_CPPManagedILMain: // C++ managed-IL main @@ -3183,7 +3258,7 @@ inline int UnDecorator::getTypeEncoding(void) // // Skip the encoding // - gName += 1; + increment_buffer_no_check(); return getTypeEncoding(); case SHF_CManagedILFunction: // C (or extern "C") managed-IL function @@ -3193,7 +3268,7 @@ inline int UnDecorator::getTypeEncoding(void) // // Skip the encoding // - gName += 1; + increment_buffer_no_check(); // // The next character should be the number of characters @@ -3205,12 +3280,22 @@ inline int UnDecorator::getTypeEncoding(void) // Skip the character count and the byte-count // itself // - gName += ((*gName - '0') + 1); + size_t count = (*gName - '0') + 1; + if (!increment_buffer(count)) + { + TE_setistruncated(typeCode); + return typeCode; + } typeCode = getTypeEncoding(); TE_setisisexternc(typeCode); return typeCode; } + else if (*gName == 0) + { + TE_setistruncated(typeCode); + return typeCode; + } else { TE_setisbadtype(typeCode); @@ -3220,37 +3305,36 @@ inline int UnDecorator::getTypeEncoding(void) case MGD_AppDomain: { - gName += 1; // this is __declspec(appdomain), but we won't say it + increment_buffer_no_check(); // this is __declspec(appdomain), but we won't say it return getTypeEncoding(); } case SHF_Hybrid: { - m_CHPENameOffset = 0; // clear the chpe name offset because this name is already chpe - gName += 1; + m_CHPENameOffset = 0; // clear the chpe name offset because this name is already chpe + increment_buffer_no_check(); return getTypeEncoding(); } case 0: - TE_setistruncated ( typeCode ); - return typeCode; + TE_setistruncated(typeCode); + return typeCode; default: TE_setisbadtype(typeCode); - return typeCode; + return typeCode; } } break; case 0: TE_setistruncated(typeCode); - --gName; // back up, we advance back to the NUL below - break; + return typeCode; case SHF_VtorDispThunkEx: isVtorDispThunkEx = true; - ++gName; + increment_buffer_no_check(); if (*gName < '0' || *gName > '5') // case labels below { if (*gName) @@ -3319,13 +3403,13 @@ inline int UnDecorator::getTypeEncoding(void) // Advance past the code character - gName++; + increment_buffer_no_check(); } // End of else if then else if((*gName >= TE_static_d) && (*gName <= TE_metatype)) // Non function decorations ? { - int code = *gName++; - + int code = *gName; + increment_buffer_no_check(); TE_setisdata(typeCode); @@ -3381,13 +3465,13 @@ inline int UnDecorator::getTypeEncoding(void) } // End of else if then else if(*gName == '9') { - gName++; + increment_buffer_no_check(); TE_setisCident(typeCode); } else if (*gName == TE_structured_binding) { - ++gName; + increment_buffer_no_check(); TE_setisstructuredbinding(typeCode); } else if(*gName) @@ -3410,60 +3494,58 @@ DName UnDecorator::getBasedType(void) // What type of 'based' is it ? - if (*gName) + switch (get_current_character_and_increment_buffer()) { - switch (*gName++) - { #if !VERS_32BIT - case BT_segname: - basedDecl += UScore(TOK_segnameLpQ) + getSegmentName() + "\")"; - break; + case BT_segname: + basedDecl += UScore(TOK_segnameLpQ) + getSegmentName() + "\")"; + break; - case BT_segment: - basedDecl += DName("NYI:") + UScore(TOK_segment); - break; + case BT_segment: + basedDecl += DName("NYI:") + UScore(TOK_segment); + break; #endif - case BT_void: - basedDecl += "void"_l; - break; + case BT_void: + basedDecl += "void"_l; + break; #if !VERS_32BIT - case BT_self: - basedDecl += UScore(TOK_self); - break; + case BT_self: + basedDecl += UScore(TOK_self); + break; - case BT_nearptr: - basedDecl += DName("NYI:") + UScore(TOK_nearP); - break; + case BT_nearptr: + basedDecl += DName("NYI:") + UScore(TOK_nearP); + break; - case BT_farptr: - basedDecl += DName("NYI:") + UScore(TOK_farP); - break; + case BT_farptr: + basedDecl += DName("NYI:") + UScore(TOK_farP); + break; - case BT_hugeptr: - basedDecl += DName("NYI:") + UScore(TOK_hugeP); - break; + case BT_hugeptr: + basedDecl += DName("NYI:") + UScore(TOK_hugeP); + break; - case BT_segaddr: - basedDecl += "NYI:"; - break; + case BT_segaddr: + basedDecl += "NYI:"; + break; #else - case BT_nearptr: - basedDecl += getScopedName(); - break; + case BT_nearptr: + basedDecl += getScopedName(); + break; #endif - case BT_basedptr: - // - // Note: based pointer on based pointer is reserved - // - return DName(DN_invalid); + case BT_basedptr: + // + // Note: based pointer on based pointer is reserved + // + return DName(DN_invalid); - } // End of SWITCH - } // End of IF else - else + case 0: basedDecl += DN_truncated; + break; + } // End of SWITCH // Close the based syntax @@ -3494,7 +3576,7 @@ DName UnDecorator::getScopedName(void) // Skip the trailing '@' if (*gName == '@') - gName++; + increment_buffer_no_check(); else if(*gName) scopeName = DN_invalid; else if(scopeName.isEmpty()) @@ -3553,15 +3635,20 @@ inline DName UnDecorator::getEnumType(void) // Add the 'unsigned'ness if appropriate - switch (*gName++) + switch (*gName) { + case 0: + return DName(DN_truncated); case ET_uchar: case ET_ushort: case ET_uint: case ET_ulong: + increment_buffer_no_check(); ecsuName = "unsigned "_l + ecsuName; break; - + default: + increment_buffer_no_check(); + break; } // End of SWITCH // Now return the composed name @@ -3580,8 +3667,8 @@ DName UnDecorator::getCallingConvention(void) { if (*gName) { - unsigned int callCode = ((unsigned int)*gName++) - 'A'; - + unsigned int callCode = ((unsigned int)*gName) - 'A'; + increment_buffer_no_check(); // What is the primary calling convention @@ -3677,7 +3764,7 @@ DName UnDecorator::getReturnType(DName * pDeclarator) { if (*gName == '@') // Return type for constructors and destructors ? { - gName++; + increment_buffer_no_check(); return DName(pDeclarator); @@ -3702,7 +3789,7 @@ DName UnDecorator::getDataType(DName * pDeclarator) return (DN_truncated + superType); case BDT_void: - gName++; + increment_buffer_no_check(); if (superType.isEmpty()) return DName("void"_l); @@ -3712,7 +3799,7 @@ DName UnDecorator::getDataType(DName * pDeclarator) case '?': { - gName++; // Skip the '?' + increment_buffer_no_check(); // Skip the '?' superType = getDataIndirectType(superType, IndirectionKind::None, DName(), 0); return getPrimaryDataType(superType); @@ -3754,7 +3841,7 @@ DName UnDecorator::getPrimaryDataType(const DName & superType) { DName superName(superType); - gName++; + increment_buffer_no_check(); return getReferenceType(cvType, superName.setPtrRef(), IndirectionKind::LvalueReference); @@ -3772,21 +3859,21 @@ DName UnDecorator::getPrimaryDataType(const DName & superType) else return DName(DN_invalid); - gName += 2; + increment_buffer_no_check(2); switch (*gName) { case PDT_ex_function: - gName++; + increment_buffer_no_check(); return getFunctionIndirectType(superType); case PDT_ex_other: - gName++; + increment_buffer_no_check(); return getPtrRefDataType(superType, /* isPtr = */ TRUE); case PDT_ex_qualified: { - gName++; + increment_buffer_no_check(); return getBasicDataType(getDataIndirectType(superType, IndirectionKind::None, DName(), 0)); } @@ -3808,18 +3895,18 @@ DName UnDecorator::getPrimaryDataType(const DName & superType) { DName superName(superType); - gName++; + increment_buffer_no_check(); return getReferenceType(cvType, superName.setPtrRef(), IndirectionKind::RvalueReference); } case PDT_ex_nullptr: - gName++; + increment_buffer_no_check(); return DName(DN_invalid); break; case PDT_ex_nullptr_t: - gName++; + increment_buffer_no_check(); if (!superType.isEmpty()) { @@ -3832,13 +3919,13 @@ DName UnDecorator::getPrimaryDataType(const DName & superType) break; case PDT_aliasTemplate: - gName++; + increment_buffer_no_check(); return getScopedName(); case PDT_empty: // This is the representation of a variadic type that was expanded to nothing so just return whatever the // super-type is - ++gName; + increment_buffer_no_check(); return superType; case 0: @@ -3862,10 +3949,12 @@ DName UnDecorator::getArgumentTypes(void) switch (*gName) { case AT_ellipsis: - return DName((gName++, doEllipsis() ? "..."_l : UNDNAME_ELLIPSIS_ALTERNATE_STRINGLITERAL_1)); + increment_buffer_no_check(); + return DName(doEllipsis() ? "..."_l : UNDNAME_ELLIPSIS_ALTERNATE_STRINGLITERAL_1); case AT_void: - return DName((gName++, "void"_l)); + increment_buffer_no_check(); + return DName("void"_l); default: { @@ -3881,10 +3970,12 @@ DName UnDecorator::getArgumentTypes(void) return arguments; case AT_ellipsis: - return DName((gName++, arguments + (doEllipsis() ? ",..."_l : UNDNAME_ELLIPSIS_ALTERNATE_STRINGLITERAL_2))); + increment_buffer_no_check(); + return DName(arguments + (doEllipsis() ? ",..."_l : UNDNAME_ELLIPSIS_ALTERNATE_STRINGLITERAL_2)); case AT_endoflist: - return (gName++, arguments); + increment_buffer_no_check(); + return arguments; default: return DName(DN_invalid); @@ -3925,7 +4016,7 @@ DName UnDecorator::getArgumentList(void) if ((argIndex >= 0) && (argIndex <= 9)) { - gName++; // Skip past the replicator + increment_buffer_no_check(); // Skip past the replicator // Append to the argument list @@ -3985,16 +4076,18 @@ DName UnDecorator::getThrowTypes(void) // Top-level noexcept functions still have the ellipsis encoded, however, to maintain // ABI compatibility with C++14 and earlier code. if (*gName == AT_ellipsis) - return (gName++, DName()); - else - return DName(); + { + increment_buffer_no_check(); + } + + return DName(); } // End of "UnDecorator" FUNCTION "getThrowTypes" DName UnDecorator::getNoexcept() { - if (*gName && *gName == '_' && *(gName + 1) && *(gName + 1) == FT_noexcept) + if (*gName == '_' && *(gName + 1) == FT_noexcept) { - gName += 2; + increment_buffer_no_check(2); return DName(" noexcept"_l); } @@ -4004,12 +4097,13 @@ DName UnDecorator::getNoexcept() #if CC_RESTRICTION_SPEC DName UnDecorator::getRestrictionSpec(void) { - if (*gName && *gName == '_' && *(gName+1) && *(gName+1) <= 'D') + if (*gName == '_' && *(gName+1) && *(gName+1) <= 'D') { // Skip the escape char '_' first - gName++; + increment_buffer_no_check(); - unsigned int rstCode = ((unsigned int)*gName++) - 'A'; + unsigned int rstCode = ((unsigned int)*gName) - 'A'; + increment_buffer_no_check(); if (rstCode <= RST_MASK) { @@ -4058,13 +4152,18 @@ DName UnDecorator::getRestrictionSpec(void) DName UnDecorator::getDispatchTarget(void) { - if (*gName && *gName == '_' && *(gName + 1) && *(gName + 1) == '_') + if (*gName == '_' && *(gName + 1) == '_') { // Skip the escape prefix '__' first - gName++; - gName++; + increment_buffer_no_check(2); - unsigned int rstCode = ((unsigned int)*gName++) - 'A'; + if (*gName == 0) + { + return DName(DN_truncated); + } + + unsigned int rstCode = ((unsigned int)*gName) - 'A'; + increment_buffer_no_check(); if (rstCode > RST_MASK) { // not a valid dispatch target @@ -4083,7 +4182,9 @@ DName UnDecorator::getBasicDataType(const DName & superType) { if (*gName) { - unsigned char bdtCode = *gName++; + unsigned char bdtCode = *gName; + increment_buffer_no_check(); + unsigned char extended_bdtCode = 0x0; int pCvCode = -1; DName basicDataType; @@ -4140,7 +4241,7 @@ DName UnDecorator::getBasicDataType(const DName & superType) pCvCode = (bdtCode & (BDT_const | BDT_volatile)); break; case BDT_extend: - switch (extended_bdtCode = *gName++) + switch (extended_bdtCode = get_current_character_and_increment_buffer()) { case BDT_array: pCvCode = -2; @@ -4212,7 +4313,6 @@ DName UnDecorator::getBasicDataType(const DName & superType) return "__w64 "_l + getBasicDataType(superType); case '\0': - gName--; // End of string, better back-up basicDataType = DN_truncated; break; @@ -4358,7 +4458,7 @@ DName UnDecorator::getECSUDataType(void) { DName Prefix; - switch (*gName++) + switch (get_current_character_and_increment_buffer()) { case BDT_union: Prefix = "union "_l; @@ -4385,15 +4485,26 @@ DName UnDecorator::getECSUDataType(void) case BDT_enum: Prefix = "enum "_l + getEnumType(); break; + + case 0: + return DName(DN_truncated); } // End of SWITCH ecsuDataType = Prefix; } else { + char c = *gName; + if (c == 0) + { + return DName(DN_truncated); + } + + increment_buffer_no_check(); + // We don't need to output the prefix, but we still need to // skip the corresponding characters - if (*gName++ == BDT_enum) + if (c == BDT_enum) { // Skip the characters for the underlying type getEnumType(); @@ -4425,13 +4536,15 @@ DName UnDecorator::getFunctionIndirectType(const DName & superType) return DName(DN_invalid); - int fitCode = *gName++ - '6'; + int fitCode = *gName - '6'; + increment_buffer_no_check(); if (fitCode == ('_' - '6')) { if (*gName) { - fitCode = *gName++ - 'A' + FIT_based; + fitCode = *gName - 'A' + FIT_based; + increment_buffer_no_check(); if ((fitCode < FIT_based) || (fitCode > (FIT_based | FIT_far | FIT_member))) fitCode = -1; @@ -4471,12 +4584,12 @@ DName UnDecorator::getFunctionIndirectType(const DName & superType) else { // Pseudo this pointer - gName++; + increment_buffer_no_check(); } if (*gName) if (*gName == '@') - gName++; + increment_buffer_no_check(); else return DName(DN_invalid); else @@ -4621,7 +4734,7 @@ DName UnDecorator::getExtendedDataIndirectType(IndirectionKind& kind, bool& fIsP DASSERT(*gName == '$'); - gName++; // swallow up the dollar + increment_buffer_no_check(); // swallow up the dollar switch (*gName) { @@ -4638,7 +4751,7 @@ DName UnDecorator::getExtendedDataIndirectType(IndirectionKind& kind, bool& fIsP kind = IndirectionKind::Handle; } } - gName++; + increment_buffer_no_check(); break; case DIT_PinPointer: @@ -4648,13 +4761,13 @@ DName UnDecorator::getExtendedDataIndirectType(IndirectionKind& kind, bool& fIsP fIsPinPtr = true; szComPlusIndirSpecifier = '>'; - gName++; + increment_buffer_no_check(); break; case DIT_InteriorPointer: // this pointer of value class is interior_ptr kind = IndirectionKind::Percent; - gName++; + increment_buffer_no_check(); break; default: @@ -4665,7 +4778,7 @@ DName UnDecorator::getExtendedDataIndirectType(IndirectionKind& kind, bool& fIsP return DName(DN_invalid); unsigned int nRank = ((gName[0] - '0') << 4) + (gName[1] - '0'); - gName += 2; + increment_buffer_no_check(2); if (nRank > 1) { @@ -4684,7 +4797,7 @@ DName UnDecorator::getExtendedDataIndirectType(IndirectionKind& kind, bool& fIsP // array^ // and: array - gName++; + increment_buffer_no_check(); } else { @@ -4692,7 +4805,7 @@ DName UnDecorator::getExtendedDataIndirectType(IndirectionKind& kind, bool& fIsP } if (*gName) - gName++; + increment_buffer_no_check(); else szComPlusIndirSpecifier += DN_truncated; @@ -4782,7 +4895,12 @@ DName UnDecorator::getDataIndirectType(const DName & superType, IndirectionKind if (fContinue) { - gName++; + increment_buffer_no_check(); + + if (*gName == 0) + { + return DName(DN_truncated); + } if (gName[0] == '$') { @@ -4799,7 +4917,7 @@ DName UnDecorator::getDataIndirectType(const DName & superType, IndirectionKind } while (fContinue); if (*gName) - gName++; // Skip to next character in name + increment_buffer_no_check(); // Skip to next character in name // Is it a valid 'data-indirection-type' ? @@ -4852,9 +4970,10 @@ DName UnDecorator::getDataIndirectType(const DName & superType, IndirectionKind // Now skip the scope terminator - if (!*gName) + char c = get_current_character_and_increment_buffer(); + if (!c) ditType += DN_truncated; - else if(*gName++ != '@') + else if (c != '@') return DName(DN_invalid); } // End of IF @@ -4972,7 +5091,7 @@ DName UnDecorator::getPtrRefDataType(const DName& superType, int isPtr) { if (*gName == PoDT_void) { - gName++; // Skip this character + increment_buffer_no_check(); // Skip this character if (superType.isEmpty()) { @@ -4985,14 +5104,14 @@ DName UnDecorator::getPtrRefDataType(const DName& superType, int isPtr) // If this is the encoding for a boxed type then skip over it and continue with the underlying type if ((gName[0] == BDT_extend) && (gName[1] == BDT_extend) && (gName[2] == BDT_boxed)) { - gName += 3; + increment_buffer_no_check(3); } } // Otherwise it may be std::nullptr_t which has special decoration if ((gName[0] == PDT_extend) && (gName[1] == PDT_extend) && (gName[2] == PDT_ex_nullptr_t)) { - gName += 3; + increment_buffer_no_check(3); if (superType.isEmpty()) { return DName("std::nullptr_t"_l); @@ -5006,7 +5125,7 @@ DName UnDecorator::getPtrRefDataType(const DName& superType, int isPtr) // Otherwise it may be a 'reference-data-type' if (*gName == RDT_array) // An array ? { - gName++; + increment_buffer_no_check(); return getArrayType(superType); } @@ -5125,7 +5244,7 @@ inline DName UnDecorator::getVCallThunkType(void) switch (*gName) { case VMT_nTnCnV: - ++gName; + increment_buffer_no_check(); return DName("{flat}"_l); case 0: return DName(DN_truncated); @@ -5200,7 +5319,7 @@ inline DName UnDecorator::getVCallThunkType(void) // Get the 'vfptr' model - switch (*gName++) // Last time, so advance the pointer + switch (get_current_character_and_increment_buffer()) // Last time, so advance the pointer { case VMT_nTnCnV: case VMT_nTfCnV: @@ -5223,6 +5342,8 @@ inline DName UnDecorator::getVCallThunkType(void) vcallType += getBasedType(); break; + case 0: + return DName(DN_truncated); } // End of SWITCH // Always append 'vfptr' @@ -5259,7 +5380,7 @@ inline DName UnDecorator::getVfTableType(const DName & superType) // Skip the scope delimiter if (*gName == '@') - gName++; + increment_buffer_no_check(); // Close the current scope, and add a conjunction for the next (if any) @@ -5281,7 +5402,7 @@ inline DName UnDecorator::getVfTableType(const DName & superType) // Skip the 'vpath-name' terminator if (*gName == '@') - gName++; + increment_buffer_no_check(); } // End of IF } // End of IF then @@ -5301,7 +5422,7 @@ inline DName UnDecorator::getVdispMapType(const DName & superType) vdispMapName += '}'; if (*gName == '@') - gName++; + increment_buffer_no_check(); return vdispMapName; } #endif // !NO_COMPILER_NAMES @@ -5309,7 +5430,7 @@ inline DName UnDecorator::getVdispMapType(const DName & superType) inline DName UnDecorator::getExternalDataType(const DName & superType) { - // Create an indirect declarator for the the rest + // Create an indirect declarator for the rest DName * pDeclarator = gnew DName(); DName declaration = getDataType(pDeclarator); diff --git a/src/crt/vcruntime/vcruntime_internal.h b/src/crt/vcruntime/vcruntime_internal.h index e73eb35..feb08f5 100644 --- a/src/crt/vcruntime/vcruntime_internal.h +++ b/src/crt/vcruntime/vcruntime_internal.h @@ -191,7 +191,7 @@ typedef struct RENAME_BASE_PTD(__vcrt_ptd) { // C++ Exception Handling (EH) state unsigned long _NLG_dwCode; // Required by NLG routines - unexpected_handler _unexpected; // unexpected() routine + void (__CRTDECL* _unexpected)(void); // unexpected() routine void* _translator; // S.E. translator void* _purecall; // called when pure virtual happens void* _curexception; // current exception diff --git a/src/crt/vcruntime/vcstartup_internal.h b/src/crt/vcruntime/vcstartup_internal.h index 36f5c66..2255063 100644 --- a/src/crt/vcruntime/vcstartup_internal.h +++ b/src/crt/vcruntime/vcstartup_internal.h @@ -34,7 +34,6 @@ extern "C" int __cdecl _seh_filter_sys( // of specifying /alternatename comments to the linker. It prepends the leading // decoration character for x86 and hybrid and leaves names unmodified for other // architectures. - #if defined _M_IX86 #if defined _M_HYBRID #define _VCRT_DECLARE_ALTERNATE_NAME_PREFIX "#" diff --git a/src/version.txt b/src/version.txt index 2229a7c..ef9ccbe 100644 --- a/src/version.txt +++ b/src/version.txt @@ -1,2 +1,2 @@ -MSVC: 14.32.31326 -SDK : 10.0.22621.1 \ No newline at end of file +MSVC: 14.34.31933 +SDK : 10.0.22621.755 \ No newline at end of file