From f47341fbe6a3d12944cd63b01216cbf8cab314dd Mon Sep 17 00:00:00 2001 From: mingkuang Date: Sun, 8 Aug 2021 17:26:19 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E6=AD=A5=E6=B7=BB=E5=8A=A0=E5=9F=BA?= =?UTF-8?q?=E4=BA=8Eucrtbase=E7=9A=84VC-LTL=E6=A8=A1=E5=BC=8F=EF=BC=88http?= =?UTF-8?q?s://github.com/mingkuang-Chuyu/VC-LTL5/issues/1=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 3 +- Build.proj | 196 ++ Readme.md | 16 + VC-LTL helper for Visual Studio.props | 70 + YY.Windows.CRT.sln | 43 + _msvcrt.h | 0 config/1033/VC-LTL-Options.xml | 47 + config/1033/config.string.props | 28 + config/2052/VC-LTL-Options.xml | 47 + config/2052/config.string.props | 28 + config/config.props | 151 ++ vcruntime.src/Shared/PTD_Downlevel.cpp | 2 + vcruntime.src/Shared/chandler4.cpp | 32 + vcruntime.src/Shared/chandler_noexcept.cpp | 33 + vcruntime.src/Shared/ehassert.h | 3 + vcruntime.src/Shared/ehhelpers.cpp | 252 ++ vcruntime.src/Shared/ehhelpers.h | 91 + vcruntime.src/Shared/ehhooks.h | 105 + vcruntime.src/Shared/ehstate.cpp | 242 ++ vcruntime.src/Shared/frame.cpp | 2109 +++++++++++++++++ vcruntime.src/Shared/framework.h | 50 + vcruntime.src/Shared/internal_shared.h | 771 ++++++ vcruntime.src/Shared/risctrnsctrl.cpp | 546 +++++ vcruntime.src/Shared/telemetry.cpp | 16 + vcruntime.src/Shared/trnsctrl.h | 270 +++ vcruntime.src/Shared/uncaught_exceptions.cpp | 16 + vcruntime.src/Shared/vcruntime_internal.h | 439 ++++ vcruntime.src/Shared/winapi_downlevel.cpp | 16 + vcruntime.src/Shared/winapi_thunks.cpp | 88 + .../ucrt.vcruntime/ucrt.vcruntime.vcxproj | 430 ++++ .../ucrt.vcruntime.vcxproj.filters | 63 + 31 files changed, 6202 insertions(+), 1 deletion(-) create mode 100644 Build.proj create mode 100644 Readme.md create mode 100644 VC-LTL helper for Visual Studio.props create mode 100644 YY.Windows.CRT.sln create mode 100644 _msvcrt.h create mode 100644 config/1033/VC-LTL-Options.xml create mode 100644 config/1033/config.string.props create mode 100644 config/2052/VC-LTL-Options.xml create mode 100644 config/2052/config.string.props create mode 100644 config/config.props create mode 100644 vcruntime.src/Shared/PTD_Downlevel.cpp create mode 100644 vcruntime.src/Shared/chandler4.cpp create mode 100644 vcruntime.src/Shared/chandler_noexcept.cpp create mode 100644 vcruntime.src/Shared/ehassert.h create mode 100644 vcruntime.src/Shared/ehhelpers.cpp create mode 100644 vcruntime.src/Shared/ehhelpers.h create mode 100644 vcruntime.src/Shared/ehhooks.h create mode 100644 vcruntime.src/Shared/ehstate.cpp create mode 100644 vcruntime.src/Shared/frame.cpp create mode 100644 vcruntime.src/Shared/framework.h create mode 100644 vcruntime.src/Shared/internal_shared.h create mode 100644 vcruntime.src/Shared/risctrnsctrl.cpp create mode 100644 vcruntime.src/Shared/telemetry.cpp create mode 100644 vcruntime.src/Shared/trnsctrl.h create mode 100644 vcruntime.src/Shared/uncaught_exceptions.cpp create mode 100644 vcruntime.src/Shared/vcruntime_internal.h create mode 100644 vcruntime.src/Shared/winapi_downlevel.cpp create mode 100644 vcruntime.src/Shared/winapi_thunks.cpp create mode 100644 vcruntime.src/ucrt.vcruntime/ucrt.vcruntime.vcxproj create mode 100644 vcruntime.src/ucrt.vcruntime/ucrt.vcruntime.vcxproj.filters diff --git a/.gitignore b/.gitignore index 9491a2f..c3eb08e 100644 --- a/.gitignore +++ b/.gitignore @@ -360,4 +360,5 @@ MigrationBackup/ .ionide/ # Fody - auto-generated XML schema -FodyWeavers.xsd \ No newline at end of file +FodyWeavers.xsd +*.7z diff --git a/Build.proj b/Build.proj new file mode 100644 index 0000000..ae54cc4 --- /dev/null +++ b/Build.proj @@ -0,0 +1,196 @@ + + + + + + + $(MSBuildThisFileDirectory) + .sln + YY.Windows.CRT.sln + YY.Windows.CRT + $(SolutionDir)$(SolutionFileName) + $([Microsoft.Build.Utilities.ToolLocationHelper]::GetLatestSDKTargetPlatformVersion('Windows', '10.0')) + + + + + False + Static + Win32 + 10.0.10240.0 + Configuration=%(Configuration); Platform=%(Platform); WindowsTargetPlatformMinVersion=%(WindowsTargetPlatformMinVersion) + + + False + Static + x64 + 10.0.10240.0 + Configuration=%(Configuration); Platform=%(Platform); WindowsTargetPlatformMinVersion=%(WindowsTargetPlatformMinVersion) + + + False + Static + ARM + 10.0.10240.0 + Configuration=%(Configuration); Platform=%(Platform); WindowsTargetPlatformMinVersion=%(WindowsTargetPlatformMinVersion) + + + False + Static + ARM64 + 10.0.10240.0 + Configuration=%(Configuration); Platform=%(Platform); WindowsTargetPlatformMinVersion=%(WindowsTargetPlatformMinVersion) + + + + False + Dynamic + Win32 + 10.0.10240.0 + Configuration=%(Configuration); Platform=%(Platform); WindowsTargetPlatformMinVersion=%(WindowsTargetPlatformMinVersion) + + + False + Dynamic + x64 + 10.0.10240.0 + Configuration=%(Configuration); Platform=%(Platform); WindowsTargetPlatformMinVersion=%(WindowsTargetPlatformMinVersion) + + + False + Dynamic + ARM + 10.0.10240.0 + Configuration=%(Configuration); Platform=%(Platform); WindowsTargetPlatformMinVersion=%(WindowsTargetPlatformMinVersion) + + + False + Dynamic + ARM64 + 10.0.10240.0 + Configuration=%(Configuration); Platform=%(Platform); WindowsTargetPlatformMinVersion=%(WindowsTargetPlatformMinVersion) + + + + + + False + Static + Win32 + 10.0.19041.0 + Configuration=%(Configuration); Platform=%(Platform); WindowsTargetPlatformMinVersion=%(WindowsTargetPlatformMinVersion) + + + False + Static + x64 + 10.0.19041.0 + Configuration=%(Configuration); Platform=%(Platform); WindowsTargetPlatformMinVersion=%(WindowsTargetPlatformMinVersion) + + + False + Static + ARM + 10.0.19041.0 + Configuration=%(Configuration); Platform=%(Platform); WindowsTargetPlatformMinVersion=%(WindowsTargetPlatformMinVersion) + + + False + Static + ARM64 + 10.0.19041.0 + Configuration=%(Configuration); Platform=%(Platform); WindowsTargetPlatformMinVersion=%(WindowsTargetPlatformMinVersion) + + + + False + Dynamic + Win32 + 10.0.19041.0 + Configuration=%(Configuration); Platform=%(Platform); WindowsTargetPlatformMinVersion=%(WindowsTargetPlatformMinVersion) + + + False + Dynamic + x64 + 10.0.19041.0 + Configuration=%(Configuration); Platform=%(Platform); WindowsTargetPlatformMinVersion=%(WindowsTargetPlatformMinVersion) + + + False + Dynamic + ARM + 10.0.19041.0 + Configuration=%(Configuration); Platform=%(Platform); WindowsTargetPlatformMinVersion=%(WindowsTargetPlatformMinVersion) + + + False + Dynamic + ARM64 + 10.0.19041.0 + Configuration=%(Configuration); Platform=%(Platform); WindowsTargetPlatformMinVersion=%(WindowsTargetPlatformMinVersion) + + + + + + + + + + + + + + + + + + + + + + + + + + + + VC-LTL-Binary.7z + VC-LTL-$(TagVersion)-Binary.7z + + + + + \ No newline at end of file diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..e24f7b8 --- /dev/null +++ b/Readme.md @@ -0,0 +1,16 @@ +# VC-LTL - An elegant way to compile lighter binaries. + +> 这是VC-LTL 5.0版本,代码完全重构,仍然在试水中!如果是生产力环境中请使用[VC-LTL 4](https://github.com/Chuyu-Team/VC-LTL/releases/latest)。 + + +* QQ群: [633710173](https://shang.qq.com/wpa/qunwpa?idkey=21d51d8ad1d77b99ea9544b399e080ec347ca6a1bc04267fb59cebf22644a42a) + + +## 设计目标 +1. ABI与微软完全兼容,无需重新构建现有静态库即可使用。 +2. 计划提供二个模式,一种是ucrt模式『优先级更高』,直接使用微软的 ucrtbase,另外一种是msvcrt。 +3. 兼容 Windows Vista以及更高版本。疑问,是否需要支持Windows XP? + + +## 其他 +有更好的意见请跟我沟通。 \ No newline at end of file diff --git a/VC-LTL helper for Visual Studio.props b/VC-LTL helper for Visual Studio.props new file mode 100644 index 0000000..af7df07 --- /dev/null +++ b/VC-LTL helper for Visual Studio.props @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + $(MSBuildThisFileDirectory) + + + $(ProjectDir)VC-LTL + + + $(SolutionDir)VC-LTL + + + $(ProjectDir)..\VC-LTL + + + $(SolutionDir)..\VC-LTL + + + $(Registry:HKEY_CURRENT_USER\Code\VC-LTL@Root) + + + + + + + + + \ No newline at end of file diff --git a/YY.Windows.CRT.sln b/YY.Windows.CRT.sln new file mode 100644 index 0000000..b3cdb66 --- /dev/null +++ b/YY.Windows.CRT.sln @@ -0,0 +1,43 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31515.178 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ucrt.vcruntime", "vcruntime.src\ucrt.vcruntime\ucrt.vcruntime.vcxproj", "{FEC996ED-01E9-4258-862F-58BF3AEFA893}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Dynamic|ARM = Dynamic|ARM + Dynamic|ARM64 = Dynamic|ARM64 + Dynamic|x64 = Dynamic|x64 + Dynamic|x86 = Dynamic|x86 + Static|ARM = Static|ARM + Static|ARM64 = Static|ARM64 + Static|x64 = Static|x64 + Static|x86 = Static|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {FEC996ED-01E9-4258-862F-58BF3AEFA893}.Dynamic|ARM.ActiveCfg = Dynamic|ARM + {FEC996ED-01E9-4258-862F-58BF3AEFA893}.Dynamic|ARM.Build.0 = Dynamic|ARM + {FEC996ED-01E9-4258-862F-58BF3AEFA893}.Dynamic|ARM64.ActiveCfg = Dynamic|ARM64 + {FEC996ED-01E9-4258-862F-58BF3AEFA893}.Dynamic|ARM64.Build.0 = Dynamic|ARM64 + {FEC996ED-01E9-4258-862F-58BF3AEFA893}.Dynamic|x64.ActiveCfg = Dynamic|x64 + {FEC996ED-01E9-4258-862F-58BF3AEFA893}.Dynamic|x64.Build.0 = Dynamic|x64 + {FEC996ED-01E9-4258-862F-58BF3AEFA893}.Dynamic|x86.ActiveCfg = Dynamic|Win32 + {FEC996ED-01E9-4258-862F-58BF3AEFA893}.Dynamic|x86.Build.0 = Dynamic|Win32 + {FEC996ED-01E9-4258-862F-58BF3AEFA893}.Static|ARM.ActiveCfg = Static|ARM + {FEC996ED-01E9-4258-862F-58BF3AEFA893}.Static|ARM.Build.0 = Static|ARM + {FEC996ED-01E9-4258-862F-58BF3AEFA893}.Static|ARM64.ActiveCfg = Static|ARM64 + {FEC996ED-01E9-4258-862F-58BF3AEFA893}.Static|ARM64.Build.0 = Static|ARM64 + {FEC996ED-01E9-4258-862F-58BF3AEFA893}.Static|x64.ActiveCfg = Static|x64 + {FEC996ED-01E9-4258-862F-58BF3AEFA893}.Static|x64.Build.0 = Static|x64 + {FEC996ED-01E9-4258-862F-58BF3AEFA893}.Static|x86.ActiveCfg = Static|Win32 + {FEC996ED-01E9-4258-862F-58BF3AEFA893}.Static|x86.Build.0 = Static|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {EC2630C9-26D4-4C44-9112-5F8D7EC4568E} + EndGlobalSection +EndGlobal diff --git a/_msvcrt.h b/_msvcrt.h new file mode 100644 index 0000000..e69de29 diff --git a/config/1033/VC-LTL-Options.xml b/config/1033/VC-LTL-Options.xml new file mode 100644 index 0000000..1e3be95 --- /dev/null +++ b/config/1033/VC-LTL-Options.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + diff --git a/config/1033/config.string.props b/config/1033/config.string.props new file mode 100644 index 0000000..c5b322c --- /dev/null +++ b/config/1033/config.string.props @@ -0,0 +1,28 @@ + + + + + + VC-LTL is disabled because VC-LTL isn't compatible with Debug configuration, please switch to Release configuration and continue. + + VC-LTL is disabled because VC-LTL isn't compatible with MFC projects. + + VC-LTL is disabled because VC-LTL isn't compatible with $(PlatformShortName) platforms. + + VC-LTL is disabled because VC-LTL isn't compatible with the $(PlatformToolset) toolset. Please switch to Visual Studio 2015/2017/2019 and continue. + + VC-LTL is disabled because VC-LTL isn't compatible with Windows 10 Universal Driver. + + + VC-LTL doesn't support VC $(VCToolsVersion) and has been switched to VC $(VCLTLToolsVersion). This may be that your IDE version is too low, it's recommended to upgrade to the latest IDE and continue. + + VC-LTL doesn't support UCRT $(TargetUniversalCRTVersion) and has been switched to UCRT $(VCLTLTargetUniversalCRTVersion). This may be that your SDK version is too low, it's recommended to switch to the latest SDK and continue. + + VC-LTL doesn't support the simultaneous use of UCRT mode and Windows XP mode, and Windows XP mode has been ignored. + + VC-LTL doesn't support the $(SpectreMitigation). It's recommended to upgrade to the latest VC-LTL and continue. + + + VC-LTL cannot find the lib files, please reinstall the NuGet package, or download it again from https://github.com/Chuyu-Team/VC-LTL/releases/latest and continue. + + \ No newline at end of file diff --git a/config/2052/VC-LTL-Options.xml b/config/2052/VC-LTL-Options.xml new file mode 100644 index 0000000..d262db3 --- /dev/null +++ b/config/2052/VC-LTL-Options.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + diff --git a/config/2052/config.string.props b/config/2052/config.string.props new file mode 100644 index 0000000..57ae47e --- /dev/null +++ b/config/2052/config.string.props @@ -0,0 +1,28 @@ + + + + + + VC-LTL不兼容 Debug 配置,VC-LTL已经自动禁用,请切换到 Release 配置然后继续。 + + VC-LTL不兼容 MFC 项目,VC-LTL已经自动禁用。 + + VC-LTL不兼容 $(PlatformShortName) 平台,已经自动禁用VC-LTL。 + + VC-LTL不兼容 $(PlatformToolset) 工具集,请切换到 Visual Studio 2015/2017/2019 然后继续。 + + VC-LTL不兼容 Windows 10 Universal Driver,VC-LTL已经自动禁用。 + + + VC-LTL不支持 VC $(VCToolsVersion),已临时切换到 VC $(VCLTLToolsVersion) 来维持基础功能。这可能是你的IDE版本过低,建议升级到最新IDE然后继续! + + VC-LTL不支持 UCRT $(TargetUniversalCRTVersion),目前已临时切换到 UCRT $(VCLTLTargetUniversalCRTVersion) 来维持基础功能。这可能是你的SDK版本过低,建议切换到最新SDK然后继续! + + VC-LTL不支持 UCRT模式与Windows XP兼容模式同时使用,已临时禁用Windows XP兼容模式。 + + VC-LTL不完全支持 $(SpectreMitigation) 缓解方案,建议升级到最新VC-LTL然后继续。 + + + VC-LTL不找不到lib文件,请重新安装 NuGet 包,或者从 https://github.com/Chuyu-Team/VC-LTL/releases/latest 下载完整二进制文件然后继续。 + + \ No newline at end of file diff --git a/config/config.props b/config/config.props new file mode 100644 index 0000000..750e9db --- /dev/null +++ b/config/config.props @@ -0,0 +1,151 @@ + + + + + + + $(LangID) + + 1033 + + + + $([System.Version]::Parse('$(WindowsTargetPlatformMinVersion)').Build) + 10240 + + + + + + + 10.0.19041.0 + + + + + + 10.0.10240.0 + + + + + + + true + true + true + true + true + + true + true + true + true + true + true + true + true + true + true + true + + + true + + + true + + + true + + + + + 5 + Light + Advanced + + false + ucrt + + true + + + false + + WinXP + Vista + + $(MSBuildThisFileDirectory)..\ucrt\$(VCLTLTargetUniversalCRTVersion)\lib\$(Platform) + + + + $(VC_LTL_Library);$(LibraryPath) + $(VC_LTL_Library);$(VC_LibraryPath_x86) + $(VC_LTL_Library);$(VC_LibraryPath_x64) + + + + + _ACRTIMP=__declspec(dllimport);_DCRTIMP=__declspec(dllimport);_Build_By_LTL=1;_LTL_Core_Version=$(LTL_CoreVersion);%(PreprocessorDefinitions) + _ATL_XP_TARGETING=1;%(PreprocessorDefinitions) + + /Zc:threadSafeInit- %(AdditionalOptions) + + + 5.01 + 5.02 + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vcruntime.src/Shared/PTD_Downlevel.cpp b/vcruntime.src/Shared/PTD_Downlevel.cpp new file mode 100644 index 0000000..8339115 --- /dev/null +++ b/vcruntime.src/Shared/PTD_Downlevel.cpp @@ -0,0 +1,2 @@ + +thread_local int VC_LTL_UCRT_CatchStateInParent; \ No newline at end of file diff --git a/vcruntime.src/Shared/chandler4.cpp b/vcruntime.src/Shared/chandler4.cpp new file mode 100644 index 0000000..e84684e --- /dev/null +++ b/vcruntime.src/Shared/chandler4.cpp @@ -0,0 +1,32 @@ +#define WIN32_LEAN_AND_MEAN // 从 Windows 头文件中排除极少使用的内容 +#include + +#if defined(_X86_) && !defined(_DLL) + +typedef void(__fastcall *PCOOKIE_CHECK)(UINT_PTR); + +EXTERN_C __declspec(dllimport) EXCEPTION_DISPOSITION __cdecl _except_handler4_common( + IN PUINT_PTR CookiePointer, + IN PCOOKIE_CHECK CookieCheckFunction, + IN PEXCEPTION_RECORD ExceptionRecord, + IN PEXCEPTION_REGISTRATION_RECORD EstablisherFrame, + IN OUT PCONTEXT ContextRecord, + IN OUT PVOID DispatcherContext + ); + +EXTERN_C +DECLSPEC_GUARD_SUPPRESS +EXCEPTION_DISPOSITION +__cdecl +_except_handler4( + IN PEXCEPTION_RECORD ExceptionRecord, + IN PEXCEPTION_REGISTRATION_RECORD EstablisherFrame, + IN OUT PCONTEXT ContextRecord, + IN OUT PVOID DispatcherContext + ) +{ + return _except_handler4_common(&__security_cookie, &__security_check_cookie, ExceptionRecord, EstablisherFrame, ContextRecord, DispatcherContext); +} + + +#endif \ No newline at end of file diff --git a/vcruntime.src/Shared/chandler_noexcept.cpp b/vcruntime.src/Shared/chandler_noexcept.cpp new file mode 100644 index 0000000..b6dcd7a --- /dev/null +++ b/vcruntime.src/Shared/chandler_noexcept.cpp @@ -0,0 +1,33 @@ +#include +#include +#include + +#if defined _M_AMD64 || defined _M_ARM || defined _M_ARM64 + +#if WindowsTargetPlatformMinVersion < __MakeVersion(10, 0, 17134) + +extern "C" EXCEPTION_DISPOSITION __cdecl __C_specific_handler_noexcept( + _In_ struct _EXCEPTION_RECORD* ExceptionRecord, + _In_ void* EstablisherFrame, + _Inout_ struct _CONTEXT* ContextRecord, + _Inout_ struct _DISPATCHER_CONTEXT* DispatcherContext +) +{ + auto Excption = __C_specific_handler(ExceptionRecord, EstablisherFrame, ContextRecord, DispatcherContext); + + if (IS_DISPATCHING(ExceptionRecord->ExceptionFlags) + && ExceptionRecord->ExceptionCode == EH_EXCEPTION_NUMBER + && Excption == ExceptionContinueSearch) + { + //结束进程 + terminate(); + } + + return Excption; +} + +_LCRT_DEFINE_IAT_SYMBOL(__C_specific_handler_noexcept); + +#endif + +#endif \ No newline at end of file diff --git a/vcruntime.src/Shared/ehassert.h b/vcruntime.src/Shared/ehassert.h new file mode 100644 index 0000000..2c4fbb3 --- /dev/null +++ b/vcruntime.src/Shared/ehassert.h @@ -0,0 +1,3 @@ +#pragma once + +#include diff --git a/vcruntime.src/Shared/ehhelpers.cpp b/vcruntime.src/Shared/ehhelpers.cpp new file mode 100644 index 0000000..b1be8fa --- /dev/null +++ b/vcruntime.src/Shared/ehhelpers.cpp @@ -0,0 +1,252 @@ +/*** +*ehhelpers.cpp - Some target-independent helper routines used by the EH frame handler. +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +****/ + +#include // User-visible routines for eh +#include // This project's versions of standard assert macros +#include // Declarations of all types used for EH +#include +#include // Declarations of hook variables and callbacks +#include // Routines to handle transfer of control (trnsctrl.asm) +#include +#include + +#include +#include + +#include "ehhelpers.h" +#include "framework.h" + +// If we call DestructExceptionObject directly from C_Specific_Handler/ +// _except_handler3, then this obj file will be pulled in by the linker +// even in programs which do not have C++ exceptions. So we call it using a +// function pointer _pDestructExceptionObject which gets initialized to 0 by +// default. If C++ exceptions are present, this file will be pulled in naturally +// and _pDestructExceptionObject will point to __DestructExceptionObject. + +#if 0 +extern "C" void (__cdecl * const _pDestructExceptionObject)(EHExceptionRecord *,BOOLEAN) + = &__DestructExceptionObject; +#endif + +//////////////////////////////////////////////////////////////////////////////// +// +// __FrameUnwindFilter - Allows possibility of continuing through SEH during +// unwind. +// +#if 0 +extern "C" _VCRTIMP int __cdecl __FrameUnwindFilter( + EXCEPTION_POINTERS *pExPtrs +) { + EHExceptionRecord *pExcept = (EHExceptionRecord *)pExPtrs->ExceptionRecord; + + switch (PER_CODE(pExcept)) { + case EH_EXCEPTION_NUMBER: + _pCurrentException = pExcept; + _pCurrentExContext = pExPtrs->ContextRecord; + terminate(); + + case MANAGED_EXCEPTION_CODE: + case MANAGED_EXCEPTION_CODE_V4: + /* + See VSW#544593 for more details. __ProcessingThrow is used to implement + std::uncaught_exception(). The interaction between C++, SEH and managed + exception wrt __ProcessingThrow is unspec'ed. From code inspection, it + looks like that __ProcessingThrow works ok with all C++ exceptions. + + In this case, when we encounter a managed exception thrown from a destructor + during unwind, we choose to decrement the count. This means that the previous + C++ exception which incremented the count won't be considered any longer. + In fact, the managed exception will be thrown, and the native C++ one will + not have any possibility to be caught any longer. + + We should revisit std::uncaught_exception() and SEH/managed exception in the + next version. + */ + if (__ProcessingThrow > 0) + { + --__ProcessingThrow; + } + return EXCEPTION_CONTINUE_SEARCH; + + default: + return EXCEPTION_CONTINUE_SEARCH; + } +} +#endif + +#if 0 + +PGETWINRT_OOM_EXCEPTION __WinRTOutOfMemoryExceptionCallback = nullptr; + +extern "C" _VCRTIMP void __cdecl _SetWinRTOutOfMemoryExceptionCallback(PGETWINRT_OOM_EXCEPTION pCallback) +{ + __WinRTOutOfMemoryExceptionCallback = pCallback; +} +#endif + +////////////////////////////////////////////////////////////////////////////////// +// __std_terminate: Helper function referenced by the front-end to assist in +// implementing noexcept. Noexcept termination semantics are generally handled +// by FindHandler() above, when we cross a function with the noexcept bit set +// in the xdata when looking for a handler. When noexcept functions are inlined, +// though, we may no longer cross a noexcept function boundary when searching for +// a handler. In this case the inlined code contains an EH state that will invoke +// this function should an exception occur. +#if WindowsTargetPlatformMinVersion < __MakeVersion(10, 0, 14393) +extern "C" __declspec(noreturn) void __cdecl __std_terminate() +{ + terminate(); +} + +_LCRT_DEFINE_IAT_SYMBOL(__std_terminate); +#endif + +//////////////////////////////////////////////////////////////////////////////// +// +// __DestructExceptionObject - Call the destructor (if any) of the original +// exception object. +// +// Returns: None. +// +// Side-effects: +// Original exception object is destructed. +// +// Notes: +// If destruction throws any exception, and we are destructing the exception +// object as a result of a new exception, we give up. If the destruction +// throws otherwise, we let it be. + +#if 0 +static DWORD _FilterSetCurrentException(EXCEPTION_POINTERS* pointers, BOOLEAN fThrowNotAllowed) +{ + if (fThrowNotAllowed) { + const auto eRecord = reinterpret_cast(pointers->ExceptionRecord); + if (PER_IS_MSVC_EH(eRecord)) + { + // Can't have new exceptions when we're unwinding due to another + // exception. + _pCurrentException = eRecord; + _pCurrentExContext = pointers->ContextRecord; + terminate(); + } + } + + return EXCEPTION_CONTINUE_SEARCH; +} + +extern "C" _VCRTIMP void __cdecl __DestructExceptionObject( + EHExceptionRecord *pExcept, // The original exception record + BOOLEAN fThrowNotAllowed // TRUE if destructor not allowed to + // throw +) { + // Ignore if not a C++ exception (since this is now called from + // _except_handler3) + if (pExcept == nullptr || !(PER_IS_MSVC_EH(pExcept))) + { + return; + } + + EHTRACE_FMT1("Destroying object @ 0x%p", PER_PEXCEPTOBJ(pExcept)); + + /*UNDONE:Is this _SYSCRT specific */ +#pragma prefast(suppress:__WARNING_REDUNDANT_POINTER_TEST, "Current definition of PER_CODE ensures that pExcept cannot be nullptr") + if (PER_PTHROW(pExcept)) { + if (THROW_UNWINDFUNC(*PER_PTHROW(pExcept)) != 0) { + + __try { + +#if _EH_RELATIVE_TYPEINFO + _CallMemberFunction0(PER_PEXCEPTOBJ(pExcept), + THROW_UNWINDFUNC_IB(*PER_PTHROW(pExcept),(ptrdiff_t)PER_PTHROWIB(pExcept))); +#else + _CallMemberFunction0(PER_PEXCEPTOBJ(pExcept), + THROW_UNWINDFUNC(*PER_PTHROW(pExcept))); +#endif + + } __except(_FilterSetCurrentException(GetExceptionInformation(), fThrowNotAllowed)) {} + } + else if (THROW_ISWINRT(*PER_PTHROW(pExcept))) { + // Release if WinRT reference type exception + IUnknown* const pUnknown = *static_cast(PER_PEXCEPTOBJ(pExcept)); + if (pUnknown) { + pUnknown->Release(); + } + } + } +} +#endif + +///////////////////////////////////////////////////////////////////////////// +// +// _IsExceptionObjectToBeDestroyed - Determine if an exception object is still +// in use by a more deeply nested catch frame, or if it unused and should be +// destroyed on exiting from the current catch block. +// +// Returns: +// TRUE if exception object not found and should be destroyed. +// +#if 0 +extern "C" BOOL __cdecl _IsExceptionObjectToBeDestroyed( + PVOID pExceptionObject +) { + FRAMEINFO * pFrameInfo; + + for (pFrameInfo = pFrameInfoChain; pFrameInfo; pFrameInfo = pFrameInfo->pNext ) { + if (pFrameInfo->pExceptionObject == pExceptionObject) { + return FALSE; + } + } + return TRUE; +} +#endif + +////////////////////////////////////////////////////////////////////////////////// +// _is_exception_typeof - checks if the thrown exception is the type, the caller +// has passed in. +// +#if 0 +extern "C" _VCRTIMP int __cdecl _is_exception_typeof(const type_info & type, struct _EXCEPTION_POINTERS * ep) +{ + _VCRT_VERIFY(ep); + + EHExceptionRecord *pExcept = (EHExceptionRecord *)ep->ExceptionRecord; + + // Is this our Exception? + _VCRT_VERIFY(pExcept && PER_IS_MSVC_EH(pExcept)); + +#if _EH_RELATIVE_TYPEINFO + __int32 const *ppCatchable; + ptrdiff_t imgBase = (ptrdiff_t)pExcept->params.pThrowImageBase; + ppCatchable = THROW_CTLIST_IB(*PER_PTHROW(pExcept), imgBase ); + int catchables = THROW_COUNT_IB(*PER_PTHROW(pExcept), imgBase ); +#else + CatchableType * const *ppCatchable; + ppCatchable = THROW_CTLIST(*PER_PTHROW(pExcept)); + int catchables = THROW_COUNT(*PER_PTHROW(pExcept)); +#endif + + CatchableType *pCatchable; + + // Scan all types that thrown object can be converted to. + for (; catchables > 0; catchables--, ppCatchable++) + { +#if _EH_RELATIVE_TYPEINFO + pCatchable = (CatchableType *)(imgBase + *ppCatchable); + if(strcmp(type.raw_name(), CT_NAME_IB(*pCatchable, imgBase)) == 0) +#else + pCatchable = *ppCatchable; + if(strcmp(type.raw_name(), CT_NAME(*pCatchable)) == 0) +#endif + { + // Found a Match. + return 1; + } + } + + return 0; +} +#endif \ No newline at end of file diff --git a/vcruntime.src/Shared/ehhelpers.h b/vcruntime.src/Shared/ehhelpers.h new file mode 100644 index 0000000..2b685f9 --- /dev/null +++ b/vcruntime.src/Shared/ehhelpers.h @@ -0,0 +1,91 @@ +// +// Copyright (c) Microsoft Corporation. All Rights reserved. +// + +#pragma once + +#if defined(_M_X64) || defined(_M_ARM_NT) || defined(_M_ARM64) || defined(_CHPE_X86_ARM64_EH_) + +#define _pForeignExcept (*((EHExceptionRecord **)&(RENAME_BASE_PTD(__vcrt_getptd)()->_pForeignException))) + +#endif + +#define pFrameInfoChain (*((FRAMEINFO **) &(RENAME_BASE_PTD(__vcrt_getptd)()->_pFrameInfoChain))) + +// Pre-V4 managed exception code +#define MANAGED_EXCEPTION_CODE 0XE0434F4D + +// V4 and later managed exception code +#define MANAGED_EXCEPTION_CODE_V4 0XE0434352 + +//extern "C" void +//__except_validate_context_record( +// _In_ PCONTEXT ContextRecord +// ); +//这个函数仅仅是验证内存是否在堆栈中,而且要开启 guard ICall才行,所以直接砍掉吧 +#define __except_validate_context_record(ContextRecord) + +extern "C" _VCRTIMP void * __AdjustPointer( + void *, + const PMD& +); + +extern "C" _VCRTIMP void * __GetPlatformExceptionInfo( + int * +); + +extern "C" _VCRTIMP int __cdecl __FrameUnwindFilter( + EXCEPTION_POINTERS * +); + +//extern PGETWINRT_OOM_EXCEPTION __WinRTOutOfMemoryExceptionCallback; +//考虑到实际WinRT很少,而且也确实无法很好的处理它,因此,屏蔽 +#define __WinRTOutOfMemoryExceptionCallback PGETWINRT_OOM_EXCEPTION(NULL) + +extern "C" _VCRTIMP void __cdecl __DestructExceptionObject( + EHExceptionRecord *, + BOOLEAN +); + +extern "C" _VCRTIMP void __cdecl RENAME_EH_EXTERN(__BuildCatchObject)( + EHExceptionRecord *, + void *, + HandlerType *, + CatchableType * +); + +extern "C" _VCRTIMP int __cdecl RENAME_EH_EXTERN(__TypeMatch4)( + FH4::HandlerType4 *, + CatchableType *, + ThrowInfo * + ); + +extern "C" _VCRTIMP int __cdecl RENAME_EH_EXTERN(__TypeMatch)( + HandlerType *, + CatchableType *, + ThrowInfo * +); + +// +// Prototype for the internal handler +// + +template +EXCEPTION_DISPOSITION __InternalCxxFrameHandler( + EHExceptionRecord *pExcept, + EHRegistrationNode *pRN, + CONTEXT *pContext, + DispatcherContext *pDC, + typename T::FuncInfo *pFuncInfo, + int CatchDepth, + EHRegistrationNode *pMarkerRN, + BOOLEAN recursive); + +#if _EH_RELATIVE_TYPEINFO + +#undef THROW_COUNT +#define THROW_COUNT(ti) THROW_COUNT_IB(ti, _GetThrowImageBase()) +#undef THROW_CTLIST +#define THROW_CTLIST(ti) THROW_CTLIST_IB(ti, _GetThrowImageBase()) + +#endif // _EH_RELATIVE_TYPEINFO diff --git a/vcruntime.src/Shared/ehhooks.h b/vcruntime.src/Shared/ehhooks.h new file mode 100644 index 0000000..4c29715 --- /dev/null +++ b/vcruntime.src/Shared/ehhooks.h @@ -0,0 +1,105 @@ +#pragma once +#include +//#include +#include + +#define EHTRACE_ENTER_FMT1(...) +#define EHTRACE_ENTER_FMT2(...) +#define EHTRACE_FMT1(...) +#define EHTRACE_FMT2(...) + +#define EHTRACE_ENTER +#define EHTRACE_EXIT +#define EHTRACE_EXCEPT(x) x +#define EHTRACE_HANDLER_EXIT(x) + +#define EHTRACE_RESET + +#define DASSERT(x) +#define _VCRT_VERIFY(x) + +#define _ValidateRead(ptr) (ptr != NULL) +#define _ValidateWrite(ptr) (ptr != NULL) +#define _ValidateExecute(ptr) (ptr != NULL) + + +#define RENAME_EH_EXTERN(x) x + +#if _EH_RELATIVE_FUNCINFO + +EXTERN_C uintptr_t __cdecl _GetImageBase(); + +EXTERN_C void __cdecl _SetImageBase(uintptr_t ImageBaseToRestore); +#endif + +#if _EH_RELATIVE_TYPEINFO +EXTERN_C uintptr_t __cdecl _GetThrowImageBase(); + +EXTERN_C void __cdecl _SetThrowImageBase(uintptr_t NewThrowImageBase); +#endif + + +EXTERN_C _VCRTIMP FRAMEINFO * __cdecl _CreateFrameInfo( + FRAMEINFO * pFrameInfo, + PVOID pExceptionObject +); + +EXTERN_C _VCRTIMP void __cdecl _FindAndUnlinkFrame( + FRAMEINFO * pFrameInfo +); + + +EXTERN_C _VCRTIMP BOOL __cdecl _IsExceptionObjectToBeDestroyed( + PVOID pExceptionObject +); + + +#define __pSETranslator (*(_se_translator_function*)&(__vcrt_getptd()->_translator)) + + +#ifdef _EH_RELATIVE_FUNCINFO +template +BOOL _CallSETranslator( + EHExceptionRecord *pExcept, // The exception to be translated + EHRegistrationNode *pRN, // Dynamic info of function with catch + CONTEXT *pContext, // Context info + DispatcherContext *pDC, // More dynamic info of function with catch (ignored) + typename T::FuncInfo *pFuncInfo, // Static info of function with catch + ULONG CatchDepth, // How deeply nested in catch blocks are we? + EHRegistrationNode *pMarkerRN // Marker for parent context + ); +#endif + +#if defined(_M_X64) +EXTERN_C void* __cdecl _CallSettingFrame( + void* handler, + EHRegistrationNode* pEstablisher, + ULONG NLG_CODE + ); + +EXTERN_C void* __cdecl _CallSettingFrameEncoded( + void* handler, + EHRegistrationNode pEstablisher, + void* object, + ULONG NLG_CODE + ); + +EXTERN_C void* __cdecl _CallSettingFrame_LookupContinuationIndex( + void* handler, + EHRegistrationNode *pEstablisher, + ULONG NLG_CODE + ); + +EXTERN_C void* __cdecl _CallSettingFrame_NotifyContinuationAddr( + void* handler, + EHRegistrationNode *pEstablisher + ); + +#elif defined(_M_ARM_NT) || defined(_M_ARM64) || defined(_CHPE_X86_ARM64_EH_) +EXTERN_C void* __cdecl _CallSettingFrame( + void* handler, + EHRegistrationNode* pRN, + PULONG pNonVolatiles, + ULONG NLG_CODE + ); +#endif diff --git a/vcruntime.src/Shared/ehstate.cpp b/vcruntime.src/Shared/ehstate.cpp new file mode 100644 index 0000000..fc48bcd --- /dev/null +++ b/vcruntime.src/Shared/ehstate.cpp @@ -0,0 +1,242 @@ +/*** +* ehstate.cpp +* +* Copyright (c) Microsoft Corporation. All rights reserved. +*Purpose: +* Contains state management code for all platforms. +* +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "ehhelpers.h" + +#if _EH_RELATIVE_FUNCINFO +#if defined(_M_ARM_NT) || defined(_M_ARM64) || defined(_CHPE_X86_ARM64_EH_) +static uintptr_t adjustIp(DispatcherContext *pDC, uintptr_t Ip) +{ + // + // 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 call opcode. + // + + if (pDC->ControlPcIsUnwound) { + +#if defined(_M_ARM_NT) + + Ip -= 2; + +#else + + Ip -= 4; + +#endif + + } + + return Ip; +} + +#else +static uintptr_t adjustIp(DispatcherContext* /*pDC*/, uintptr_t Ip) +{ + return Ip; +} +#endif + +__ehstate_t RENAME_EH_EXTERN(__FrameHandler4)::StateFromIp( + FuncInfo *pFuncInfo, + DispatcherContext *pDC, + uintptr_t Ip +) +{ + unsigned int index; // loop control variable + unsigned int nIPMapEntry; // # of IpMapEntry; must be > 0 + + Ip = adjustIp(pDC, Ip); + + if (pFuncInfo->dispIPtoStateMap == 0) + { + return EH_EMPTY_STATE; + } + + PBYTE buffer = (PBYTE)__RVAtoRealOffset(pDC, pFuncInfo->dispIPtoStateMap); + + nIPMapEntry = FH4::ReadUnsigned(&buffer); + + __ehstate_t prevState = EH_EMPTY_STATE; + unsigned int funcRelIP = 0; + for (index = 0; index < nIPMapEntry; index++) { + // States are delta-encoded relative to start of the function + funcRelIP += FH4::ReadUnsigned(&buffer); + if (Ip < __FuncRelToRealOffset(pDC, funcRelIP)) { + break; + } + // States are encoded +1 so as to not encode a negative + prevState = FH4::ReadUnsigned(&buffer) - 1; + } + + if (index == 0) { + // We are at the first entry, could be an error + return EH_EMPTY_STATE; + } + + // We over-shot one iteration; return state from the previous slot + return prevState; +} + +#if 0 +__ehstate_t RENAME_EH_EXTERN(__FrameHandler3)::StateFromIp( + FuncInfo *pFuncInfo, + DispatcherContext *pDC, + uintptr_t Ip +) +{ + + unsigned int index; // loop control variable + unsigned int nIPMapEntry; // # of IpMapEntry; must be > 0 + + Ip = adjustIp(pDC, Ip); + + _VCRT_VERIFY(pFuncInfo); + nIPMapEntry = FUNC_NIPMAPENT(*pFuncInfo); + + _VCRT_VERIFY(FUNC_IPMAP(*pFuncInfo, pDC->ImageBase)); + + for (index = 0; index < nIPMapEntry; index++) { + IptoStateMapEntry *pIPtoStateMap = FUNC_PIPTOSTATE(*pFuncInfo, index, pDC->ImageBase); + if (Ip < (uintptr_t)__RVAtoRealOffset(pDC, pIPtoStateMap->Ip)) { + break; + } + } + + if (index == 0) { + // We are at the first entry, could be an error + + return EH_EMPTY_STATE; + } + + // We over-shot one iteration; return state from the previous slot + + return FUNC_IPTOSTATE(*pFuncInfo, index - 1, pDC->ImageBase).State; + +} +#endif + +#if 0 +__ehstate_t RENAME_EH_EXTERN(__FrameHandler3)::StateFromControlPc( + FuncInfo *pFuncInfo, + DispatcherContext *pDC +) +{ + uintptr_t Ip = pDC->ControlPc; + + return StateFromIp(pFuncInfo, pDC, Ip); +} +#endif + +__ehstate_t RENAME_EH_EXTERN(__FrameHandler4)::StateFromControlPc( + FuncInfo *pFuncInfo, + DispatcherContext *pDC +) +{ + uintptr_t Ip = pDC->ControlPc; + + return StateFromIp(pFuncInfo, pDC, Ip); +} + +#if 0 +void RENAME_EH_EXTERN(__FrameHandler3)::SetUnwindTryBlock( + EHRegistrationNode *pRN, + DispatcherContext *pDC, + FuncInfo *pFuncInfo, + int curState +) +{ + EHRegistrationNode EstablisherFramePointers; + EstablisherFramePointers = *RENAME_EH_EXTERN(__FrameHandler3)::GetEstablisherFrame(pRN, pDC, pFuncInfo, &EstablisherFramePointers); + if (curState > UNWINDTRYBLOCK(EstablisherFramePointers, FUNC_DISPUNWINDHELP(*pFuncInfo))) { + UNWINDTRYBLOCK(EstablisherFramePointers, FUNC_DISPUNWINDHELP(*pFuncInfo)) = (int)curState; + } +} +#endif + +#if 0 +__ehstate_t RENAME_EH_EXTERN(__FrameHandler3)::GetUnwindTryBlock( + EHRegistrationNode *pRN, + DispatcherContext *pDC, + FuncInfo *pFuncInfo +) +{ + EHRegistrationNode EstablisherFramePointers; + EstablisherFramePointers = *RENAME_EH_EXTERN(__FrameHandler3)::GetEstablisherFrame(pRN, pDC, pFuncInfo, &EstablisherFramePointers); + return UNWINDTRYBLOCK(EstablisherFramePointers, FUNC_DISPUNWINDHELP(*pFuncInfo)); +} +#endif + +#if 0 +__ehstate_t RENAME_EH_EXTERN(__FrameHandler3)::GetCurrentState( + EHRegistrationNode *pRN, + DispatcherContext *pDC, + FuncInfo *pFuncInfo +) +{ + if (UNWINDSTATE(*pRN, FUNC_DISPUNWINDHELP(*pFuncInfo)) == -2) { + return RENAME_EH_EXTERN(__FrameHandler3)::StateFromControlPc(pFuncInfo, pDC); + } + else { + return UNWINDSTATE(*pRN, FUNC_DISPUNWINDHELP(*pFuncInfo)); + } +} +#endif + +#if 0 +void RENAME_EH_EXTERN(__FrameHandler3)::SetState( + EHRegistrationNode *pRN, + FuncInfo *pFuncInfo, + __ehstate_t newState +) +{ + UNWINDSTATE(*pRN, FUNC_DISPUNWINDHELP(*pFuncInfo)) = newState; +} +#endif + +#if 0 +__ehstate_t RENAME_EH_EXTERN(__FrameHandler3)::GetCurrentState( + EHRegistrationNode *pRN, + DispatcherContext* /*pDC*/, + FuncInfo *pFuncInfo +) +{ + // In the initial implementation, the state is simply stored in the registration node. + // Added support for byte states when max state <= 128. Note that max state is 1+real max state + if (pFuncInfo->maxState <= 128) + { + return (__ehstate_t)(signed char)((pRN)->state & 0xff); + } + else { + return (pRN)->state; + } +} +#endif + +#if 0 +void RENAME_EH_EXTERN(__FrameHandler3)::SetState( + EHRegistrationNode *pRN, + FuncInfo* /*pFuncInfo*/, + __ehstate_t newState +) +{ + pRN->state = newState; +} +#endif + +#endif diff --git a/vcruntime.src/Shared/frame.cpp b/vcruntime.src/Shared/frame.cpp new file mode 100644 index 0000000..ac1ece4 --- /dev/null +++ b/vcruntime.src/Shared/frame.cpp @@ -0,0 +1,2109 @@ +/*** +*frame.cpp - The frame handler and everything associated with it. +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +*Purpose: +* The frame handler and everything associated with it. +* +* Entry points: +* _CxxFrameHandler - the frame handler. +* +* Open issues: +* Handling re-throw from dynamically nested scope. +* Fault-tolerance (checking for data structure validity). +****/ + +#include // User-visible routines for eh +#include // This project's versions of standard assert macros +#include // Declarations of all types used for EH +#include +#include // Declarations of hook variables and callbacks +#include // Routines to handle transfer of control (trnsctrl.asm) +#include +#include + +#include +#include +#include "ehhelpers.h" + +#if defined(_M_ARM64EC) +#include //PDISPATCHER_CONTEXT_ARM64EC +#include +#endif + +// Make non-namespace prefixed names available for FH4 +using namespace FH4; + +// The CallUnexpected function is only called in some build configurations. +#pragma warning(disable: 4505) // unreferenced local function has been removed +#pragma warning(disable: 4702) // unreachable code + +#define cxxReThrow (RENAME_BASE_PTD(__vcrt_getptd)()->_cxxReThrow) + + +//////////////////////////////////////////////////////////////////////////////// +// +// Intel x86-specific definitions +// +#if defined(_M_IX86) && !defined(_CHPE_X86_ARM64_EH_) + +void RENAME_EH_EXTERN(__FrameHandler3)::FrameUnwindToEmptyState( + EHRegistrationNode *pRN, + DispatcherContext *pDC, + FuncInfo *pFuncInfo +) +{ + FrameUnwindToState(pRN, pDC, pFuncInfo, EH_EMPTY_STATE); +} + +//////////////////////////////////////////////////////////////////////////////// +// +// x64/arm/arm64-specific definitions +// +#elif _EH_RELATIVE_FUNCINFO + +#define FUNC_ESTYPES(fi) ((fi).dispESTypeList ? FUNC_ESTYPES_IB(fi, _GetImageBase()) : nullptr ) +#define FUNC_PESTYPES(fi) ((*(fi)).dispESTypeList ? FUNC_PESTYPES_IB((fi), _GetImageBase()) : nullptr ) + +#if _EH_RELATIVE_TYPEINFO + +// The throw site +#undef CT_PTD +#define CT_PTD(ct) (CT_PTD_IB(ct, _GetThrowImageBase())) +#undef CT_COPYFUNC +#define CT_COPYFUNC(ct) ((ct).copyFunction? CT_COPYFUNC_IB(ct, _GetThrowImageBase()):nullptr) + +#define EST_ARRAY(x,n) EST_ARRAY_IB(x, _GetImageBase(), n) + +#undef THROW_FORWARDCOMPAT +#define THROW_FORWARDCOMPAT(ti) ((ti).pForwardCompat? THROW_FORWARDCOMPAT_IB(ti, _GetThrowImageBase()):nullptr) + +#endif // _EH_RELATIVE_TYPEINFO + +// The catch site +#undef HT_HANDLER +#define HT_HANDLER(ht) (HT_HANDLER_IB(ht, _GetImageBase())) +#undef UWE_ACTION +#define UWE_ACTION(uwe) ((uwe).action? UWE_ACTION_IB(uwe, _GetImageBase()):nullptr) + +#undef FUNC_UNWIND +#define FUNC_UNWIND(fi,st) (FUNC_PUNWINDMAP(fi,_GetImageBase())[st]) +#undef TBME_CATCH +#define TBME_CATCH(hm,n) (TBME_PLIST(hm,_GetImageBase())[n]) +#undef TBME_PCATCH +#define TBME_PCATCH(hm,n) (&(TBME_PLIST(hm,_GetImageBase())[n])) + +#undef HT_PTD +#define HT_PTD(ht) ((TypeDescriptor*)((ht).dispType? HT_PTD_IB(ht,_GetImageBase()):nullptr)) + +#undef abnormal_termination +#define abnormal_termination() FALSE + +#else +#error Unrecognized platform +#endif + +extern "C" { +typedef struct { + unsigned long dwSig; + unsigned long uoffDestination; + unsigned long dwCode; + unsigned long uoffFramePointer; +} _NLG_INFO; + +extern _NLG_INFO _NLG_Destination; +} + +//////////////////////////////////////////////////////////////////////////////// +// +// Forward declaration of local functions: +// + +template +static void FindHandler( + EHExceptionRecord *, + EHRegistrationNode *, + CONTEXT *, + DispatcherContext *, + typename T::FuncInfo *, + BOOLEAN, + int, + EHRegistrationNode* +); + +template +static void CatchIt( + EHExceptionRecord *, + EHRegistrationNode *, + CONTEXT *, + DispatcherContext *, + typename T::FuncInfo *, + typename T::HandlerType *, + CatchableType *, + typename T::TryBlockMapEntry *, + int, + EHRegistrationNode *, + BOOLEAN, + BOOLEAN +); + +static void * CallCatchBlock( + EHExceptionRecord *, + EHRegistrationNode *, + CONTEXT *, + FuncInfo *, + void *, + int, + unsigned long +); + +template +static void FindHandlerForForeignException( + EHExceptionRecord *, + EHRegistrationNode *, CONTEXT *, + DispatcherContext *, + typename T::FuncInfo *, + __ehstate_t, + int, + EHRegistrationNode * +); + +static int ExFilterRethrow( + EXCEPTION_POINTERS * +#if _EH_RELATIVE_FUNCINFO + ,EHExceptionRecord *, + int * +#endif +); + +#if _EH_RELATIVE_FUNCINFO +static int ExFilterRethrowFH4( + EXCEPTION_POINTERS *, + EHExceptionRecord *, + __ehstate_t, + int * +); +#endif + +static BOOLEAN IsInExceptionSpec( + EHExceptionRecord *pExcept, // Information for this (logical) + // exception + ESTypeList *pFuncInfo // Static information for subject frame +); + +static void CallUnexpected(ESTypeList* pESTypeList); + +static BOOLEAN Is_bad_exception_allowed(ESTypeList *pExceptionSpec); + +// +// This describes the most recently handled exception, in case of a rethrow: +// +#define _pCurrentFuncInfo (*((ESTypeList **)&(RENAME_BASE_PTD(__vcrt_getptd)()->_curexcspec))) + +inline ESTypeList* RENAME_EH_EXTERN(__FrameHandler3)::getESTypes(FuncInfo* pFuncInfo) +{ + return FUNC_PESTYPES(pFuncInfo); +} + +//////////////////////////////////////////////////////////////////////////////// +// +// __InternalCxxFrameHandler - the frame handler for all functions with C++ EH +// information. +// +// If exception is handled, this doesn't return; otherwise, it returns +// ExceptionContinueSearch. +// +// Note that this is called three ways: +// From __CxxFrameHandler: primary usage, called to inspect whole function. +// CatchDepth == 0, pMarkerRN == nullptr +// From CatchGuardHandler: If an exception occurred within a catch, this is +// called to check for try blocks within that catch only, and does not +// handle unwinds. +// From TranslatorGuardHandler: Called to handle the translation of a +// non-C++ EH exception. Context considered is that of parent. + +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? +) { + +#if defined(_M_HYBRID_X86_ARM64) && !defined(_CHPE_X86_ARM64_EH_) + _HybridGenerateThunks(__InternalCxxFrameHandler, 1); +#endif + + EHTRACE_FMT2("%s, pRN = 0x%p", + IS_UNWINDING(PER_FLAGS(pExcept)) ? "Unwinding" : "Searching", + pRN); + + __except_validate_context_record(pContext); + + if ((cxxReThrow == false) && (PER_CODE(pExcept) != EH_EXCEPTION_NUMBER) && +#if defined(_M_X64) || defined(_M_ARM) || defined(_M_ARM64) || defined(_M_HYBRID) + /* On the 64 bit/ARM platforms, ExceptionCode maybe set to STATUS_UNWIND_CONSOLIDATE + when called from _UnwindNestedFrames during Logical Unwind. _UnwindNestedFrames + will also set EH_MAGIC_NUMBER1 in the 8 element */ + (!((PER_CODE(pExcept) == STATUS_UNWIND_CONSOLIDATE) && (PER_NPARAMS(pExcept) == 15) && (PER_EXCEPTINFO(pExcept)[8] == EH_MAGIC_NUMBER1))) && +#endif + (PER_CODE(pExcept) != STATUS_LONGJUMP) && + (T::getMagicNum(pFuncInfo) >= EH_MAGIC_NUMBER3) && + (T::isEHs(pFuncInfo))) + { + /* + * This function was compiled /EHs so we don't need to do anything in + * this handler. + */ + return ExceptionContinueSearch; + } + + if (IS_UNWINDING(PER_FLAGS(pExcept))) + { + // We're at the unwinding stage of things. Don't care about the + // exception itself. (Check this first because it's easier) + + if (T::GetMaxState(pDC, pFuncInfo) != 0 && CatchDepth == 0) + { + // Only unwind if there's something to unwind + // AND we're being called through the primary RN. + +#if _EH_RELATIVE_FUNCINFO + if (IS_TARGET_UNWIND(PER_FLAGS(pExcept)) && PER_CODE(pExcept) == STATUS_LONGJUMP) { + __ehstate_t target_state = T::StateFromIp( + pFuncInfo, + pDC, +#if defined(_M_X64) + pDC->TargetIp +#elif defined(_M_ARM) || defined(_M_ARM64) || defined(_CHPE_X86_ARM64_EH_) + pDC->TargetPc +#endif + ); + + _VCRT_VERIFY(target_state >= EH_EMPTY_STATE && target_state < T::GetMaxState(pDC, pFuncInfo)); + T::FrameUnwindToState(pRN, pDC, pFuncInfo, target_state); + EHTRACE_HANDLER_EXIT(ExceptionContinueSearch); + return ExceptionContinueSearch; + } + + if(IS_TARGET_UNWIND(PER_FLAGS(pExcept)) && PER_CODE(pExcept) == STATUS_UNWIND_CONSOLIDATE) + { + PEXCEPTION_RECORD pSehExcept = (PEXCEPTION_RECORD)pExcept; + __ehstate_t target_state = (__ehstate_t)pSehExcept->ExceptionInformation[3]; + + _VCRT_VERIFY(target_state >= EH_EMPTY_STATE && target_state < T::GetMaxState(pDC, pFuncInfo)); + T::FrameUnwindToState((EHRegistrationNode *)pSehExcept->ExceptionInformation[1], + pDC, + pFuncInfo, + target_state); + EHTRACE_HANDLER_EXIT(ExceptionContinueSearch); + return ExceptionContinueSearch; + } +#endif // _EH_RELATIVE_FUNCINFO + T::FrameUnwindToEmptyState(pRN, pDC, pFuncInfo); + } + EHTRACE_HANDLER_EXIT(ExceptionContinueSearch); + return ExceptionContinueSearch; // I don't think this value matters + } + +#if _EH_RELATIVE_FUNCINFO + auto tryBlockMap = T::TryBlockMap(pFuncInfo, pDC->ImageBase); +#else + auto tryBlockMap = T::TryBlockMap(pFuncInfo, 0); +#endif + if (tryBlockMap.getNumTryBlocks() != 0 + // + // If the function has no try block, we still want to call the + // frame handler if there is an exception specification + // + || (T::getMagicNum(pFuncInfo) >= EH_MAGIC_NUMBER2 && (T::getESTypes(pFuncInfo))) + || (T::getMagicNum(pFuncInfo) >= EH_MAGIC_NUMBER3 && (T::isNoExcept(pFuncInfo) != 0))) + { + + // NT is looking for handlers. We've got handlers. + // Let's check this puppy out. Do we recognize it? + + if (PER_CODE(pExcept) == EH_EXCEPTION_NUMBER + && PER_NPARAMS(pExcept) >= 3 + && PER_MAGICNUM(pExcept) > EH_MAGIC_NUMBER3) + { + const auto pfn = THROW_FORWARDCOMPAT(*PER_PTHROW(pExcept)); + if (pfn) { + // Forward compatibility: The thrown object appears to have been + // created by a newer version of our compiler. Let that version's + // frame handler do the work (if one was specified). + + EXCEPTION_DISPOSITION result = (EXCEPTION_DISPOSITION)pfn(pExcept, pRN, pContext, pDC, pFuncInfo, + CatchDepth, pMarkerRN, recursive); + EHTRACE_HANDLER_EXIT(result); + return result; + } + } + + // Anything else: we'll handle it here. + FindHandler(pExcept, pRN, pContext, pDC, pFuncInfo, recursive, CatchDepth, pMarkerRN); + } + + // We had nothing to do with it or it was rethrown. Keep searching. + EHTRACE_HANDLER_EXIT(ExceptionContinueSearch); + return ExceptionContinueSearch; + +} // __InternalCxxFrameHandler + +#if 0 +template EXCEPTION_DISPOSITION __InternalCxxFrameHandler( + EHExceptionRecord *pExcept, + EHRegistrationNode *pRN, + CONTEXT *pContext, + DispatcherContext *pDC, + RENAME_EH_EXTERN(__FrameHandler3)::FuncInfo *pFuncInfo, + int CatchDepth, + EHRegistrationNode *pMarkerRN, + BOOLEAN recursive + ); +#endif + +#if _VCRT_BUILD_FH4 +template EXCEPTION_DISPOSITION __InternalCxxFrameHandler( + EHExceptionRecord *pExcept, + EHRegistrationNode *pRN, + CONTEXT *pContext, + DispatcherContext *pDC, + RENAME_EH_EXTERN(__FrameHandler4)::FuncInfo *pFuncInfo, + int CatchDepth, + EHRegistrationNode *pMarkerRN, + BOOLEAN recursive + ); +#endif // _VCRT_BUILD_FH4 + +/* +* Here We find what is the actual State of current function. The way we +* do this is first get State from ControlPc. +* +* Remember we have __GetUnwindTryBlock to remember the last State for which +* Exception was handled and __GetCurrentState for retriving the current +* state of the function. Please Note that __GetCurrentState is used +* primarily for unwinding purpose. +* +* Also remember that all the catch blocks act as funclets. This means that +* ControlPc for all the catch blocks are different from ControlPc of parent +* catch block or function. +* +* take a look at this example +* try { +* // STATE1 = 1 +* try { +* // STATE2 +* // THROW +* } catch (...) { // CatchB1 +* // STATE3 +* // RETHROW OR NEW THROW +* } +* } catch (...) { // CatchB2 +* } +* +* If we have an exception comming from STATE3, the FindHandler will be +* called for CatchB1, at this point we do the test which State is our +* real state, curState from ControlPc or state from __GetUnwindTryBlock. +* Since curState from ControlPc is greater, we know that real State is +* curState from ControlPc and thus we update the UnwindTryBlockState. +* +* On further examination, we found out that there is no handler within +* this catch block, we return without handling the exception. For more +* info on how we determine if we have handler, have a look at +* GetRangeOfTrysToCheck. +* +* Now FindHandler will again be called for parent function. Here again +* we test which is real State, state from ControlPc or State from +* __GetUnwindTryBlock. This time state from __GetUnwindTryBlock is correct. +* +* Also look at code in __CxxCallCatchBlock, you will se that as soon as we get +* out of last catch block, we reset __GetUnwindTryBlock state to -1. +*/ + +#if _EH_RELATIVE_FUNCINFO +#if 0 +inline __ehstate_t RENAME_EH_EXTERN(__FrameHandler3)::GetHandlerSearchState( + EHRegistrationNode *pRN, + DispatcherContext *pDC, + FuncInfo *pFuncInfo + ) +{ + __ehstate_t curState = StateFromControlPc(pFuncInfo, pDC); + EHRegistrationNode EstablisherFrame; + GetEstablisherFrame(pRN, pDC, pFuncInfo, &EstablisherFrame); + if (curState > GetUnwindTryBlock(pRN, pDC, pFuncInfo)) { + SetState(&EstablisherFrame, pFuncInfo, curState); + SetUnwindTryBlock(pRN, pDC, pFuncInfo, /*curTry*/ curState); + } else { + curState = GetUnwindTryBlock(pRN, pDC, pFuncInfo); + } + + return curState; +} +#endif + +#if _VCRT_BUILD_FH4 +inline __ehstate_t RENAME_EH_EXTERN(__FrameHandler4)::GetHandlerSearchState( + EHRegistrationNode* /*pRN*/, + DispatcherContext *pDC, + FuncInfo *pFuncInfo +) +{ + __ehstate_t curState = StateFromControlPc(pFuncInfo, pDC); + + if (pDC->ScopeIndex != 0) + { + // ScopeIndex state from collided unwinds take precedence-there should also + // be no _CatchStateInParent to use at all + _VCRT_VERIFY(CatchStateInParent == INVALID_CATCH_SPECIFIC_STATE); + curState = (__ehstate_t)pDC->ScopeIndex - SCOPE_INDEX_SHIFT_VALUE; + } + else if (CatchStateInParent != INVALID_CATCH_SPECIFIC_STATE) + { + curState = CatchStateInParent; + CatchStateInParent = INVALID_CATCH_SPECIFIC_STATE; + } + + return curState; +} +#endif // _VCRT_BUILD_FH4 +#endif // _EH_RELATIVE_FUNCINFO + +template +static void FindHandler( + EHExceptionRecord *pExcept, // Information for this (logical) + // exception + EHRegistrationNode *pRN, // Dynamic information for subject frame + CONTEXT *pContext, // Context info + DispatcherContext *pDC, // Context within subject frame + typename T::FuncInfo *pFuncInfo, // Static information for subject frame + BOOLEAN recursive, // TRUE if we're handling the + // translation + int CatchDepth, // Level of nested catch that is being + // checked + EHRegistrationNode *pMarkerRN // Extra marker RN for nested catch + // handling +) +{ + +#if defined(_M_HYBRID_X86_ARM64) && !defined(_CHPE_X86_ARM64_EH_) + _HybridGenerateThunks(FindHandler, 1); +#endif + + BOOLEAN IsRethrow = FALSE; + + // Get the current state (machine-dependent) + __ehstate_t curState = EH_EMPTY_STATE; +#if _EH_RELATIVE_FUNCINFO + curState = T::GetHandlerSearchState(pRN, pDC, pFuncInfo); +#else + curState = T::GetCurrentState(pRN, pDC, pFuncInfo); +#endif + _VCRT_VERIFY(curState >= EH_EMPTY_STATE && curState < T::GetMaxState(pDC, pFuncInfo)); + + // Check if it's a re-throw. Use the exception we stashed away if it is. + if (PER_IS_MSVC_EH(pExcept) && PER_PTHROW(pExcept) == nullptr) { + + if (_pCurrentException == nullptr) { + // Oops! User re-threw a non-existent exception! Let it propagate. + return; + } + + pExcept = _pCurrentException; + pContext = _pCurrentExContext; + IsRethrow = TRUE; +#if _EH_RELATIVE_TYPEINFO + _SetThrowImageBase((ptrdiff_t)pExcept->params.pThrowImageBase); +#endif + + _VCRT_VERIFY(pExcept && (!PER_IS_MSVC_EH(pExcept) || PER_PTHROW(pExcept))); + + // + // We know it is a rethrow -- did we come here as a result of an + // exception re-thrown from CallUnexpected() ? + // + if (_pCurrentFuncInfo) + { + ESTypeList* pCurrentFuncInfo = _pCurrentFuncInfo; // remember it in a local variable + _pCurrentFuncInfo = nullptr; // and reset it immediately -- so we don't forget to do it later + + // Does the exception thrown by CallUnexpected belong to the exception specification? + + if (IsInExceptionSpec(pExcept, pCurrentFuncInfo)) + { + // Yes it does -- so "continue the search for another handler at the call of the function + // whose exception-specification was violated" + ; + } + else + { + // Nope, it does not. Is std::bad_exception allowed by the spec? + + if (Is_bad_exception_allowed(pCurrentFuncInfo)) + { + // yup -- so according to the standard, we need to replace the thrown + // exception by an implementation-defined object of the type std::bad_exception + // and continue the search for another handler at the call of the function + // whose exception-specification was violated. + + // Just throw bad_exception -- we will then come into FindHandler for the third time -- + // but make sure we will not get here again + + __DestructExceptionObject(pExcept, TRUE); // destroy the original object + + throw std::bad_exception(); + } + else + { + terminate(); + } + } + } + } + +#if _EH_RELATIVE_FUNCINFO + auto tryBlockMap = T::TryBlockMap(pFuncInfo, pDC->ImageBase); +#else + auto tryBlockMap = T::TryBlockMap(pFuncInfo, 0); +#endif + + if (PER_IS_MSVC_EH(pExcept)) { + // Looks like it's ours. Let's see if we have a match: + // + // First, determine range of try blocks to consider: + // Only try blocks which are at the current catch depth are of interest. + + if (tryBlockMap.getNumTryBlocks() > 0) + { + auto startStop = T::GetRangeOfTrysToCheck(tryBlockMap, curState, pDC, pFuncInfo, CatchDepth); + // Scan the try blocks in the function: + for (auto iter = startStop.first; iter < startStop.second; ++iter) { + auto tryBlock = *iter; + +#if _EH_RELATIVE_TYPEINFO + __int32 const *ppCatchable; +#else + CatchableType * const *ppCatchable; +#endif + CatchableType *pCatchable; + + if (tryBlock.tryLow > curState || curState > tryBlock.tryHigh) { + continue; + } + + // Try block was in scope for current state. Scan catches for this + // try: +#if _EH_RELATIVE_FUNCINFO + auto handlerMap = T::HandlerMap(&tryBlock, pDC->ImageBase, pDC->FunctionEntry->BeginAddress); +#else + auto handlerMap = T::HandlerMap(&tryBlock, 0, 0); +#endif + for (auto handler : handlerMap) + { + // Scan all types that thrown object can be converted to: + ppCatchable = THROW_CTLIST(*PER_PTHROW(pExcept)); + for (int catchables = THROW_COUNT(*PER_PTHROW(pExcept)); + catchables > 0; catchables--, ppCatchable++) { + +#if _EH_RELATIVE_TYPEINFO + pCatchable = (CatchableType *)(_GetThrowImageBase() + *ppCatchable); +#else + pCatchable = *ppCatchable; +#endif + + if (!T::TypeMatch(&handler, pCatchable, PER_PTHROW(pExcept))) { + continue; + } + + // OK. We finally found a match. Activate the catch. If + // control gets back here, the catch did a re-throw, so + // keep searching. + CatchIt(pExcept, + pRN, + pContext, + pDC, + pFuncInfo, + &handler, + pCatchable, + &tryBlock, + CatchDepth, + pMarkerRN, + IsRethrow, + recursive + ); + goto NextTryBlock; + + } // Scan possible conversions + } // Scan catch clauses + NextTryBlock: ; + } // Scan try blocks + } // if FUNC_NTRYBLOCKS( pFuncInfo ) > 0 +#if defined(_DEBUG) + else + { + // + // This can only happen if the function has an exception specification + // but no try/catch blocks + // + _VCRT_VERIFY(T::getMagicNum(pFuncInfo) >= EH_MAGIC_NUMBER2 + && (T::isNoExcept(pFuncInfo) || T::getESTypes(pFuncInfo))); + } +#endif + +#if defined(_M_IX86) && !defined(_CHPE_X86_ARM64_EH_) + if (recursive) { + // + // A translation was provided, but this frame didn't catch it. + // Destruct the translated object before returning; if destruction + // raises an exception, terminate. + // + // This is not done for Win64 platforms. On those, the translated + // object is destructed in __CxxCallCatchBlock. + // + __DestructExceptionObject(pExcept, TRUE); + } +#endif + + // We did not find a handler in this function. Or, we found a handler and that + // handler re-threw the exception, so we returned from CatchIt and no other handler + // was found in this function to handle the re-thrown exception. Note: this only + // happens for true re-throw (throw;) and not a nested exception where the catch + // handler throws some entirely new exception. + // + // Since we didn't find a handler here, we will be returning to the caller to + // allow it to search the current function's callers for a handler. Before we leave + // we need to check for a noexcept violation and possibly terminate. + + // FH4 doesn't support Exception Specifications aside from NoExcept + if constexpr (std::is_same_v) + { + if (T::isNoExcept(pFuncInfo) && +#if defined(_M_IX86) && !defined(_CHPE_X86_ARM64_EH_) + CatchDepth == 0 +#else + !T::ExecutionInCatch(pDC, pFuncInfo) +#endif + ) + { + _pCurrentException = pExcept; + _pCurrentExContext = pContext; + terminate(); + } + } + else + { + // + // We haven't found the match -- let's look at the exception spec and see if our try + // matches one of the listed types. + // + // This block also handles noexcept termination if the current function is noexcept and + // we are not handling a nested throw or re-throw. e.g.: + // + // try { + // try { throw 1; } (1) + // catch(int) { throw; /* or throw ; */ } (2) + // } catch(int) {} (3) + // + // During the initial search for a handler when throwing the original exception (1) + // we find and execute catch handler (2). This throws, which re-enters this function + // while in the context of a catch, but which cannot find a handler. We cannot terminate here, + // we're in a recursive context. Just let it go, and we'll return back to the original search + // from (1) and find (3). If we fail to find a handler, e.g. (3) didn't match, we would + // then terminate at this point as we are not in a catch block. + // + // Catch block detection uses CatchDepth on X86, or _ExecutionInCatch on other platforms. On + // these platforms CatchDepth is always 0 - we don't maintain a stack of entered try/catch + // states. + if (FUNC_MAGICNUM(*pFuncInfo) >= EH_MAGIC_HAS_ES && + (T::getESTypes(pFuncInfo) || (T::isNoExcept(pFuncInfo) && +#if defined(_M_IX86) && !defined(_CHPE_X86_ARM64_EH_) + CatchDepth == 0 +#else + !T::ExecutionInCatch(pDC, pFuncInfo) +#endif + ))) + { + // Are we noexcept? + if (T::isNoExcept(pFuncInfo)) + { + _pCurrentException = pExcept; + _pCurrentExContext = pContext; + terminate(); + } + + if (!IsInExceptionSpec(pExcept, T::getESTypes(pFuncInfo))) + { + // Nope, it does not. Call unexpected + + // + // We must unwind the stack before calling unexpected -- this makes it work + // as if it were inside catch(...) clause + // +#if _EH_RELATIVE_FUNCINFO + EHRegistrationNode *pEstablisher = pRN; + EHRegistrationNode EstablisherFramePointers; + pEstablisher = T::GetEstablisherFrame(pRN, pDC, pFuncInfo, &EstablisherFramePointers); + T::UnwindNestedFrames(pRN, + pExcept, + pContext, + pEstablisher, + nullptr, + pFuncInfo, + EH_EMPTY_STATE, + EH_EMPTY_STATE, + nullptr, + pDC, + recursive + ); +#else + + _pCurrentException = pExcept; + _pCurrentExContext = pContext; + + if (pMarkerRN == nullptr) { + RENAME_EH_EXTERN(_UnwindNestedFrames)(pRN, pExcept); + } + else { + RENAME_EH_EXTERN(_UnwindNestedFrames)(pMarkerRN, pExcept); + } + T::FrameUnwindToEmptyState(pRN, pDC, pFuncInfo); + + CallUnexpected(T::getESTypes(pFuncInfo)); + _pCurrentException = pExcept; + _pCurrentExContext = pContext; +#endif + } + } + } + } // It was a C++ EH exception + else + { + // Not ours. But maybe someone told us how to make it ours. + if (tryBlockMap.getNumTryBlocks() > 0) + { + if (recursive) { + // We're recursive, and the exception wasn't a C++ EH! + // Translator threw something unintelligible. + + // Two choices here: we could let the new exception take over, or we could abort. We abort. + abort(); + } + + FindHandlerForForeignException(pExcept, pRN, pContext, pDC, pFuncInfo, curState, CatchDepth, pMarkerRN); + } + } // It wasn't our exception + + _VCRT_VERIFY(_pCurrentFuncInfo == nullptr); // never leave it initialized with something +} + +//////////////////////////////////////////////////////////////////////////////// +// +// FindHandlerForForeignException - We've got an exception which wasn't ours. +// Try to translate it into C++ EH, and also check for match with ellipsis. +// +// Description: +// If an SE-to-EH translator has been installed, call it. The translator +// must throw the appropriate typed exception or return. If the translator +// throws, we invoke FindHandler again as the exception filter. +// +// Returns: +// Returns if exception was not fully handled. +// No return value. +// +// Assumptions: +// Only called if there are handlers in this function. + +template +static void FindHandlerForForeignException( + EHExceptionRecord *pExcept, // Information for this (logical) + // exception + EHRegistrationNode *pRN, // Dynamic information for subject frame + CONTEXT *pContext, // Context info + DispatcherContext *pDC, // Context within subject frame + typename T::FuncInfo *pFuncInfo, // Static information for subject frame + __ehstate_t curState, // Current state + int catchDepth, // Level of nested catch that is being + // checked + EHRegistrationNode *pMarkerRN // Extra marker RN for nested catch + // handling + ) +{ +#if defined(_M_HYBRID_X86_ARM64) && !defined(_CHPE_X86_ARM64_EH_) + _HybridGenerateThunks(FindHandlerForForeignException, 1); +#endif + + // We don't want to touch BreakPoint generated Exception. + if (PER_CODE(pExcept) == STATUS_BREAKPOINT) { + return; + } + + if (__pSETranslator && __pSETranslator != __vcrt_EncodePointer(nullptr) && + pExcept->ExceptionCode != MANAGED_EXCEPTION_CODE && + pExcept->ExceptionCode != MANAGED_EXCEPTION_CODE_V4) { + + // Call the translator. If the translator knows what to + // make of it, it will throw an appropriate C++ exception. + // We intercept it and use it (recursively) for this + // frame. Don't recurse more than once. + +#if _EH_RELATIVE_FUNCINFO + if (_CallSETranslator(pExcept, pRN, pContext, pDC, pFuncInfo, + catchDepth, pMarkerRN, curState)) { +#else + if (_CallSETranslator(pExcept, pRN, pContext, pDC, pFuncInfo, + catchDepth, pMarkerRN)) { +#endif + return; + } + } + +#if _EH_RELATIVE_FUNCINFO + auto tryBlockMap = T::TryBlockMap(pFuncInfo, pDC->ImageBase); +#else + auto tryBlockMap = T::TryBlockMap(pFuncInfo, 0); +#endif + + _VCRT_VERIFY(tryBlockMap.getNumTryBlocks() > 0); + + if (tryBlockMap.getNumTryBlocks() > 0) + { + // Didn't have a translator, or the translator returned normally (i.e. + // didn't translate it). Still need to check for match with ellipsis: + auto startStop = T::GetRangeOfTrysToCheck(tryBlockMap, curState, pDC, pFuncInfo, catchDepth); + + // Scan the try blocks in the function: + for (auto iter = startStop.first; iter < startStop.second; ++iter) + { + auto tryBlock = *iter; + + // If the try-block was in scope... + if (tryBlock.tryLow > curState || curState > tryBlock.tryHigh) { + continue; + } + + // *and* the last catch in that try is an ellipsis (no other can be) +#if _EH_RELATIVE_FUNCINFO + auto handlerMap = T::HandlerMap(&tryBlock, pDC->ImageBase, pDC->FunctionEntry->BeginAddress); +#else + auto handlerMap = T::HandlerMap(&tryBlock, 0, 0); +#endif + auto handler = handlerMap.getLastEntry(); + if (!(HT_IS_TYPE_ELLIPSIS(*handler) && !HT_IS_STD_DOTDOT(*handler))) { + continue; + } + + // Found an ellipsis. Handle exception. + CatchIt(pExcept, + pRN, + pContext, + pDC, + pFuncInfo, + handler, + nullptr, + &tryBlock, + catchDepth, + pMarkerRN, + TRUE, + FALSE + ); + } + + // If it returns, handler re-threw. Keep searching. + + } // Search for try + + // If we got here, that means we didn't have anything to do with the + // exception. Continue search. +} + +template +int TypeMatchHelper( + typename T::HandlerType *pCatch, // Type of the 'catch' clause + CatchableType *pCatchable, // Type conversion under consideration + ThrowInfo *pThrow // General information about the thrown + // type. +) { + // First, check for match with ellipsis: + if (HT_IS_TYPE_ELLIPSIS(*pCatch)) { + return TRUE; + } + + if (HT_ISBADALLOCCOMPAT(*pCatch) && CT_ISSTDBADALLOC(*pCatchable)) + { + return true; + } + + // Not ellipsis; the basic types match if it's the same record *or* the + // names are identical. + if (HT_PTD(*pCatch) != CT_PTD(*pCatchable) + && strcmp(HT_NAME(*pCatch), CT_NAME(*pCatchable)) != 0) { + return FALSE; + } + + // Basic types match. The actual conversion is valid if: + // caught by ref if ref required *and* + // the qualifiers are compatible *and* + // the alignments match *and* + // the volatility matches + + return (!CT_BYREFONLY(*pCatchable) || HT_ISREFERENCE(*pCatch)) + && (!THROW_ISCONST(*pThrow) || HT_ISCONST(*pCatch)) +#if _EH_RELATIVE_FUNCINFO + && (!THROW_ISUNALIGNED(*pThrow) || HT_ISUNALIGNED(*pCatch)) +#endif + && (!THROW_ISVOLATILE(*pThrow) || HT_ISVOLATILE(*pCatch)); +} + +//////////////////////////////////////////////////////////////////////////////// +// +// __TypeMatch - Check if the catch type matches the given throw conversion. +// +// Returns: +// TRUE if the catch can catch using this throw conversion, FALSE otherwise. +#if _VCRT_BUILD_FH4 +int RENAME_EH_EXTERN(__FrameHandler4)::TypeMatch( + HandlerType *pCatch, + CatchableType *pCatchable, + ThrowInfo *pThrow +) +{ + return TypeMatchHelper(pCatch, pCatchable, pThrow); +}; +#endif // _VCRT_BUILD_FH4 + +//////////////////////////////////////////////////////////////////////////////// +// +// FrameUnwindToState - Unwind this frame until specified state is reached. +// +// Returns: +// No return value. +// +// Side Effects: +// All objects on frame which go out of scope as a result of the unwind are +// destructed. +// Registration node is updated to reflect new state. +// +// Usage: +// This function is called both to do full-frame unwind during the unwind +// phase (targetState = -1), and to do partial unwinding when the current +// frame has an appropriate catch. + +#if _VCRT_BUILD_FH4 +void RENAME_EH_EXTERN(__FrameHandler4)::FrameUnwindToState( + EHRegistrationNode *pRN, // Registration node for subject + // function + DispatcherContext *pDC, // Context within subject frame + FuncInfo *pFuncInfo, // Static information for subject + // function + __ehstate_t targetState // State to unwind to + ) +{ + UNREFERENCED_PARAMETER(pDC); // This parameter is not used in some compilations +#if _EH_RELATIVE_FUNCINFO + ptrdiff_t unwindImageBase = _GetImageBase(); + + __ehstate_t curState = GetHandlerSearchState(pRN, pDC, pFuncInfo); +#else // ^^^ _EH_RELATIVE_FUNCINFO // !_EH_RELATIVE_FUNCINFO vvv + #error Not yet implemented. +#endif // _EH_RELATIVE_FUNCINFO + __ProcessingThrow++; + + // Find starting and ending indexes in the decompressed map + auto unwindMap = UWMap(pFuncInfo, pDC->ImageBase); + + UWMap::iterator start = unwindMap.begin(); + UWMap::iterator end = unwindMap.begin(); + + _VCRT_VERIFY(start >= end); + unwindMap.getStartStop(curState, targetState, start, end); + + __try + { + while (start >= unwindMap.begin() && start > end) + { + UnwindMapEntry4 UWEntry = *start; + auto prevIter = start; + + start.WalkBack(); + + __ehstate_t prevState = curState; + curState = UWMap::getStateFromIterators(end, targetState, prevIter, prevState, start); + + // default values taken if UnwindMapEntry4::Type::NoUW + unsigned dispAction = 0; + + if (UWEntry.type != UnwindMapEntry4::Type::NoUW) + { + dispAction = UWEntry.action; + } + + if (dispAction != 0) { + // Before calling unwind action, adjust state as if it were + // already completed: +#if _EH_RELATIVE_FUNCINFO + pDC->ScopeIndex = (DWORD)(curState + SCOPE_INDEX_SHIFT_VALUE); +#else // ^^^ _EH_RELATIVE_FUNCINFO // !_EH_RELATIVE_FUNCINFO vvv + #error Not yet implemented. + //SetState(pRN, pDC, pFuncInfo, start - unwindMap.begin()); +#endif // _EH_RELATIVE_FUNCINFO + + EHTRACE_FMT2("Unwind from state %d to state %d\n", prevState, curState); + __try { + // Call the unwind action (if one exists): + if ((UWEntry.type == UnwindMapEntry4::Type::DtorWithObj) || (UWEntry.type == UnwindMapEntry4::Type::DtorWithPtrToObj)) + { + VOID * objectAddr; + if (UWEntry.type == UnwindMapEntry4::Type::DtorWithPtrToObj) { + objectAddr = (void*)(*(uintptr_t *)OffsetToAddress(UWEntry.object, *pRN)); + } + else { + objectAddr = OffsetToAddress(UWEntry.object, *pRN); + } + + RENAME_EH_EXTERN(_CallSettingFrameEncoded)((void*)__RVAtoRealOffset(pDC, dispAction), + *pRN, + objectAddr, +#if defined(_M_ARM_NT) || defined(_M_ARM64) || defined(_CHPE_X86_ARM64_EH_) + (PULONG)pDC->NonVolatileRegisters, +#endif // defined(_M_ARM_NT) || defined(_M_ARM64) || defined(_CHPE_X86_ARM64_EH_) + 0x103); + } + else + { // TODO: this is currently hardcoded for non-x86, as x86 seems to encode + // its RVAs as non-image relative, will require fix for that + RENAME_EH_EXTERN(_CallSettingFrame)((void*)__RVAtoRealOffset(pDC, dispAction), pRN, +#if defined(_M_ARM_NT) || defined(_M_ARM64) || defined(_CHPE_X86_ARM64_EH_) + (PULONG)pDC->NonVolatileRegisters, +#endif // defined(_M_ARM_NT) || defined(_M_ARM64) || defined(_CHPE_X86_ARM64_EH_) + 0x103); + } + +#if _EH_RELATIVE_FUNCINFO + _SetImageBase(unwindImageBase); +#endif // _EH_RELATIVE_FUNCINFO + + } + __except (__FrameUnwindFilter(exception_info())) { + ; // Deliberately do nothing + } + } + } + } + __finally { + if (__ProcessingThrow > 0) { + __ProcessingThrow--; + } + } + + EHTRACE_FMT2("Moved from state %d to state %d", curState, targetState); +} +#endif // _VCRT_BUILD_FH4 + +#if 0 +void RENAME_EH_EXTERN(__FrameHandler3)::FrameUnwindToState( + EHRegistrationNode *pRN, // Registration node for subject + // function + DispatcherContext *pDC, // Context within subject frame + FuncInfo *pFuncInfo, // Static information for subject + // function + __ehstate_t targetState // State to unwind to + ) +{ + UNREFERENCED_PARAMETER(pDC); // This parameter is not used in some compilations + +#if _EH_RELATIVE_FUNCINFO + ptrdiff_t unwindImageBase = _GetImageBase(); +#endif + + __ehstate_t curState = GetCurrentState(pRN, pDC, pFuncInfo); + __ProcessingThrow++; + __try { +#if _EH_RELATIVE_FUNCINFO + while (curState != EH_EMPTY_STATE && curState > targetState) +#else + while (curState != targetState) +#endif + { + _VCRT_VERIFY(curState > EH_EMPTY_STATE && curState < FUNC_MAXSTATE(*pFuncInfo)); + + // Get state after next unwind action + __ehstate_t nxtState = UWE_TOSTATE(FUNC_UNWIND(*pFuncInfo, curState)); + + __try { + // Call the unwind action (if one exists): + + if (UWE_ACTION(FUNC_UNWIND(*pFuncInfo, curState))) { + + // Before calling unwind action, adjust state as if it were + // already completed: + SetState(pRN, pFuncInfo, nxtState); + + EHTRACE_FMT2("Unwind from state %d to state %d", curState, nxtState); + +#if defined(_M_ARM64EC) + if (RtlIsEcCode((ULONG64)UWE_ACTION(FUNC_UNWIND(*pFuncInfo, curState)))) { + RENAME_EH_EXTERN(_CallSettingFrameArm64Ec)(UWE_ACTION(FUNC_UNWIND(*pFuncInfo, curState)), + pRN, + (PULONG)(((PDISPATCHER_CONTEXT_ARM64EC)pDC)->NonVolatileRegisters), + 0x103); + } else { + RENAME_EH_EXTERN(_CallSettingFrame)(UWE_ACTION(FUNC_UNWIND(*pFuncInfo, curState)), pRN, + 0x103); + } +#else + + RENAME_EH_EXTERN(_CallSettingFrame)(UWE_ACTION(FUNC_UNWIND(*pFuncInfo, curState)), pRN, +#if defined(_M_ARM_NT) || defined(_M_ARM64) || defined(_CHPE_X86_ARM64_EH_) + (PULONG)pDC->NonVolatileRegisters, +#endif + 0x103); + +#endif + +#if _EH_RELATIVE_FUNCINFO + _SetImageBase(unwindImageBase); +#endif + } + + } __except(__FrameUnwindFilter(exception_info())) { + ; // Deliberately do nothing + } + + curState = nxtState; + } + } __finally { + if (__ProcessingThrow > 0) { + __ProcessingThrow--; + } + } + + + // Now that we're done, set the frame to reflect the final state. + +#if _EH_RELATIVE_FUNCINFO + _VCRT_VERIFY(curState == EH_EMPTY_STATE || curState <= targetState); +#else + _VCRT_VERIFY(curState == targetState); +#endif + + EHTRACE_FMT2("Move from state %d to state %d", GetCurrentState(pRN, pDC, pFuncInfo), curState); + + SetState(pRN, pFuncInfo, curState); +} +#endif + +//////////////////////////////////////////////////////////////////////////////// +// +// CatchIt - A handler has been found for the thrown type. Do the work to +// transfer control. +// +// Description: +// Builds the catch object +// Unwinds the stack to the point of the try +// Calls the address of the handler (funclet) with the frame set up for that +// function but without resetting the stack. +// Handler funclet returns address to continue execution, or nullptr if the +// handler re-threw ("throw;" lexically in handler) +// If the handler throws an EH exception whose exception info is nullptr, then +// it's a re-throw from a dynamically enclosed scope. +// +// It is an open question whether the catch object is built before or after the local unwind. +// +// Returns: +// No return value. Returns iff handler re-throws. +template +static void CatchIt( + EHExceptionRecord *pExcept, // The exception thrown + EHRegistrationNode *pRN, // Dynamic info of function with catch + CONTEXT *pContext, // Context info + DispatcherContext *pDC, // Context within subject frame + typename T::FuncInfo *pFuncInfo, // Static info of function with catch + typename T::HandlerType *pCatch, // The catch clause selected + CatchableType *pConv, // The rules for making the conversion + typename T::TryBlockMapEntry *pEntry, // Description of the try block + int CatchDepth, // How many catches are we nested in? + EHRegistrationNode *pMarkerRN, // Special node if nested in catch + BOOLEAN IsRethrow, // Is this a rethrow ? + BOOLEAN recursive // Is this from a translated exception ? +) { + + // These parameters are not used in some compilations + UNREFERENCED_PARAMETER(CatchDepth); + UNREFERENCED_PARAMETER(pMarkerRN); + UNREFERENCED_PARAMETER(IsRethrow); + UNREFERENCED_PARAMETER(recursive); + + EHTRACE_FMT1("Catching object @ 0x%p", PER_PEXCEPTOBJ(pExcept)); + + EHRegistrationNode *pEstablisher = pRN; + +#if _EH_RELATIVE_FUNCINFO + EHRegistrationNode EstablisherFramePointers; + pEstablisher = T::GetEstablisherFrame(pRN, pDC, pFuncInfo, &EstablisherFramePointers); +#else + void *continuationAddress; +#endif // defined(_POWERPC) + + // Copy the thrown object into a buffer in the handler's stack frame, + // unless the catch was by elipsis (no conversion) OR the catch was by + // type without an actual 'catch object'. + + if (pConv) { + T::BuildCatchObject(pExcept, pEstablisher, pCatch, pConv); + } + + // Unwind stack objects to the entry of the try that caught this exception. + +#if _EH_RELATIVE_FUNCINFO + // This call will never return. This call will end up calling CxxCallCatchBlock + // through RtlUnwind (STATUS_CONSOLIDATE_FRAMES) mechanism. + T::UnwindNestedFrames( + pRN, + pExcept, + pContext, + pEstablisher, + HT_HANDLER(*pCatch), + pFuncInfo, + pEntry->tryLow, + pEntry->catchHigh, + pCatch, + pDC, + recursive + ); + +#else + + static_assert(!std::is_same_v, "Not yet implemented."); + if (pMarkerRN == nullptr) { + RENAME_EH_EXTERN(_UnwindNestedFrames)(pRN, pExcept); + } + else { + RENAME_EH_EXTERN(_UnwindNestedFrames)(pMarkerRN, pExcept); + } + + + T::FrameUnwindToState(pEstablisher, pDC, pFuncInfo, TBME_LOW(*pEntry)); + + // Call the catch. Separated out because it introduces a new registration + // node. + EHTRACE_FMT2("Move from state %d to state %d", T::GetCurrentState(pRN, pDC, pFuncInfo), TBME_HIGH(*pEntry) + 1); + T::SetState(pRN, pFuncInfo, TBME_HIGH(*pEntry) + 1); + + continuationAddress = CallCatchBlock(pExcept, + pEstablisher, + pContext, + pFuncInfo, + HT_HANDLER(*pCatch), + CatchDepth, + 0x100); + + // Transfer control to the continuation address. If no continuation then + // it's a re-throw, so return. + + if (continuationAddress) { + _JumpToContinuation(continuationAddress, pRN); + // No return. + } +#endif +} + +#if _EH_RELATIVE_FUNCINFO /* { { */ + +static void __RethrowException(EHExceptionRecord *pThisException) +{ + RaiseException( pThisException->ExceptionCode, + pThisException->ExceptionFlags, + pThisException->NumberParameters, + (PULONG_PTR)&(pThisException->params) ); +} + +#if _VCRT_BUILD_FH4 +void * RENAME_EH_EXTERN(__FrameHandler4)::CxxCallCatchBlock( + EXCEPTION_RECORD *pExcept + ) +{ + int rethrow = 0, TranslatedCatch = 0; + void *handlerAddress; + void *continuationAddress = nullptr; + FRAMEINFO FrameInfo; + CONTEXT *pContext, *pSaveContext; + EHRegistrationNode *pEstablisherFrame; + EHExceptionRecord *pThisException, *pSaveException, *pForeignException = nullptr; + void *continuationAddresses[MAX_CONT_ADDRESSES]; + memset(continuationAddresses, 0, sizeof(continuationAddresses)); + FuncInfo FuncInfo; + + pSaveContext = _pCurrentExContext; + pSaveException = _pCurrentException; + + // Copy Necessary Information which is passed from UnwindNestedFrames. + pThisException = (EHExceptionRecord *)pExcept->ExceptionInformation[6]; + pContext = (CONTEXT *)pExcept->ExceptionInformation[4]; + handlerAddress = (void *)pExcept->ExceptionInformation[2]; + pEstablisherFrame = (EHRegistrationNode *)pExcept->ExceptionInformation[1]; + + continuationAddresses[0] = (PBYTE)pExcept->ExceptionInformation[5]; + continuationAddresses[1] = (PBYTE)pExcept->ExceptionInformation[9]; + + // State used if an exception inside the called catch needs to be handled in the parent + __ehstate_t HandlerSearchState = (__ehstate_t) pExcept->ExceptionInformation[11]; + // State used during unwinding to bypass already unwound states in the parent + __ehstate_t UnwindTryState = (__ehstate_t)pExcept->ExceptionInformation[3]; + + __except_validate_context_record(pContext); + + _pCurrentException = pThisException; + _pCurrentExContext = pContext; + FRAMEINFO *pFrameInfo = RENAME_EH_EXTERN(_CreateFrameInfo)(&FrameInfo, + (void *)PER_PEXCEPTOBJ(_pCurrentException)); + + if (pExcept->ExceptionInformation[7]) { + // Stuff for SehTranslation book keeping + // This Exception Object is Translation of Foreign Exception And should + // be destroyed in any case. If there is rethrow, throw ForeignException. + // IMPORTANT: No one else can rethrow this Exception Object. + TranslatedCatch = 1; + pForeignException = _pForeignExcept; + // End Translation Stuff + } + + __try { + __try { +#if defined(_M_X64) + continuationAddress = RENAME_EH_EXTERN(_CallSettingFrame_LookupContinuationIndex)( +#else + #error Not yet implemented. + // continuationAddress = RENAME_EH_EXTERN(_CallSettingFrame)( +#endif + handlerAddress, + pEstablisherFrame, +#if defined(_M_ARM_NT) || defined(_M_ARM64) || defined(_CHPE_X86_ARM64_EH_) + (PULONG)pExcept->ExceptionInformation[10], +#endif + 0x100); + + intptr_t continuationIndex = reinterpret_cast(continuationAddress); + if (continuationIndex < MAX_CONT_ADDRESSES) + { + _VCRT_VERIFY(continuationAddresses[continuationIndex] != 0); + continuationAddress = continuationAddresses[continuationIndex]; + } +#if defined(_M_X64) + RENAME_EH_EXTERN(_CallSettingFrame_NotifyContinuationAddr)(continuationAddress, pEstablisherFrame); +#else + #error Not yet implemented. + // FH4 is only implemented for amd64 +#endif + } + // Filter will be invoked in pass 1 looking for an exception, this lets us set up the correct _CatchStateInParent that should + // be used when looking for a handler in the parent of a catch funclet inside ExFilterRethrowFH4. + // Note: in case of rethrow we unwind through the catch handler back to this filter in order to rethrow. + // In that case, the _CatchStateInParent should not be set until we get into the except. + __except (ExFilterRethrowFH4(exception_info(), pThisException, HandlerSearchState, &rethrow)) + { + rethrow = 1; + cxxReThrow = false; + CatchStateInParent = HandlerSearchState; + if (TranslatedCatch) { + // Note in case of rethrow, no one else can convert rethrow to + // pThisException. This means only this except will deal with conversion + // of rethrow to pThisException. Instead of pThisException, we + // will throw original Foreign Exception. Also we will need to + // destroy Exception Object before Raising Foreign Exception. + __DestructExceptionObject(pThisException, TRUE); + __RethrowException(pForeignException); + } + else + { + __RethrowException(pThisException); + } + } + } + __finally { + RENAME_EH_EXTERN(_FindAndUnlinkFrame)(pFrameInfo); + if (!rethrow && + PER_IS_MSVC_EH(pThisException) && + _IsExceptionObjectToBeDestroyed(PER_PEXCEPTOBJ(pThisException))) + { + __DestructExceptionObject(pThisException, TRUE); + } + _pCurrentException = pSaveException; + _pCurrentExContext = pSaveContext; + + // Finally is invoked in pass 2, letting us set the correct state to unwind from when back in the parent frame + CatchStateInParent = UnwindTryState; + } +#if _EH_RELATIVE_FUNCINFO + // exception caught successfully, reset this value + CatchStateInParent = INVALID_CATCH_SPECIFIC_STATE; +#endif + return continuationAddress; +} +#endif // _VCRT_BUILD_FH4 + +#if 0 +void * RENAME_EH_EXTERN(__FrameHandler3)::CxxCallCatchBlock( + EXCEPTION_RECORD *pExcept + ) +{ + int rethrow = 0, TranslatedCatch = 0; + void *handlerAddress; + void *continuationAddress = nullptr; + FuncInfo *pFuncInfo; + FRAMEINFO FrameInfo; + CONTEXT *pContext, *pSaveContext; + EHRegistrationNode *pEstablisherFrame; + EHExceptionRecord *pThisException, *pSaveException, *pForeignException = nullptr; + + pSaveContext = _pCurrentExContext; + pSaveException = _pCurrentException; + + // Copy Necessary Information which is passed from UnwindNestedFrames. + pThisException = (EHExceptionRecord *) pExcept->ExceptionInformation[6]; + pFuncInfo = (FuncInfo *) pExcept->ExceptionInformation[5]; + pContext = (CONTEXT *) pExcept->ExceptionInformation[4]; + handlerAddress = (void *) pExcept->ExceptionInformation[2]; + pEstablisherFrame = (EHRegistrationNode *)pExcept->ExceptionInformation[1]; + + __except_validate_context_record(pContext); + + _pCurrentException = pThisException; + _pCurrentExContext = pContext; + FRAMEINFO *pFrameInfo = RENAME_EH_EXTERN(_CreateFrameInfo)(&FrameInfo, + (void *)PER_PEXCEPTOBJ(_pCurrentException)); + + if (pExcept->ExceptionInformation[7]) { + // Stuff for SehTranslation book keeping + // This Exception Object is Translation of Foreign Exception And should + // be destroyed in any case. If there is rethrow, throw ForeignException. + // IMPORTANT: No one else can rethrow this Exception Object. + TranslatedCatch = 1; + pForeignException = _pForeignExcept; + // End Translation Stuff + } + + __try { + __try{ +#if defined(_M_ARM64EC) + + if (RtlIsEcCode((ULONG64)handlerAddress)) { + continuationAddress = RENAME_EH_EXTERN(_CallSettingFrameArm64Ec) (handlerAddress, + pEstablisherFrame, + (PULONG)pExcept->ExceptionInformation[10], + 0x100); + + } else { + continuationAddress = RENAME_EH_EXTERN(_CallSettingFrame) (handlerAddress, + pEstablisherFrame, + 0x100); + } + +#else + continuationAddress = RENAME_EH_EXTERN(_CallSettingFrame)(handlerAddress, + pEstablisherFrame, +#if defined(_M_ARM_NT) || defined(_M_ARM64) || defined(_CHPE_X86_ARM64_EH_) + (PULONG)pExcept->ExceptionInformation[10], +#endif + 0x100); +#endif + } __except(ExFilterRethrow(exception_info(), + pThisException, + &rethrow)) { + rethrow = 1; + cxxReThrow = false; + if (TranslatedCatch) { + // Note in case of rethrow, no one else can convert rethrow to + // pThisException. This means only this except will deal with conversion + // of rethrow to pThisException. Instead of pThisException, we + // will throw original Foreign Exception. Also we will need to + // destroy Exception Object before Raising Foreign Exception. + __DestructExceptionObject(pThisException, TRUE); + __RethrowException(pForeignException); + } else { + __RethrowException(pThisException); + } + } + } __finally { + RENAME_EH_EXTERN(_FindAndUnlinkFrame)(pFrameInfo); + if ( !rethrow && + PER_IS_MSVC_EH(pThisException) && + _IsExceptionObjectToBeDestroyed(PER_PEXCEPTOBJ(pThisException))) + { + __DestructExceptionObject(pThisException, TRUE); + } + _pCurrentException = pSaveException; + _pCurrentExContext = pSaveContext; + } +#if _EH_RELATIVE_FUNCINFO + UNWINDHELP(*pEstablisherFrame, FUNC_DISPUNWINDHELP(*pFuncInfo)) = -2; +#endif + return continuationAddress; +} +#endif + +//////////////////////////////////////////////////////////////////////////////// +// +// ExFilterRethrow - Exception filter for re-throw exceptions. +// +// Returns: +// EXCEPTION_EXECUTE_HANDLER - exception was a re-throw +// EXCEPTION_CONTINUE_SEARCH - anything else +// +// Side-effects: sets rethrow = TRUE if exception objects of the two Exception matches + +static __declspec(guard(ignore)) int ExFilterRethrow( + EXCEPTION_POINTERS *pExPtrs, + EHExceptionRecord *pOldExcept, + int *rethrow +) { + // Get the exception record thrown (don't care about other info) + EHExceptionRecord *pExcept = (EHExceptionRecord *)pExPtrs->ExceptionRecord; + *rethrow = 0; + if (PER_IS_MSVC_EH(pExcept) && PER_PEXCEPTOBJ(pExcept) == PER_PEXCEPTOBJ(pOldExcept)) + *rethrow = 1; + // Check if it's ours and it's has no exception information. + if (PER_IS_MSVC_EH(pExcept) && PER_PTHROW(pExcept) == nullptr) { + // In a rethrow, ExceptionCode isn't set to EH_EXCEPTION_NUMBER even for a + // C++ Exception. Hence we use cxxReThrow in __InternalCxxFrameHandler + // to check for a C++ Exception + cxxReThrow = true; + *rethrow = 1; + return EXCEPTION_EXECUTE_HANDLER; + } + return EXCEPTION_CONTINUE_SEARCH; +} + +#if _VCRT_BUILD_FH4 +// Wraps around ExFilterRethrow to set _CatchStateInParent if this isn't a rethrow. +static __declspec(guard(ignore)) int ExFilterRethrowFH4( + EXCEPTION_POINTERS *pExPtrs, + EHExceptionRecord *pOldExcept, + __ehstate_t HandlerSearchState, + int *rethrow +) +{ + int exceptionCode = ExFilterRethrow(pExPtrs, pOldExcept, rethrow); + if (exceptionCode == EXCEPTION_CONTINUE_SEARCH) + { + // Set correct parent state to be used + CatchStateInParent = HandlerSearchState; + } + + return exceptionCode; +} +#endif + +#elif defined(_M_IX86) + +//////////////////////////////////////////////////////////////////////////////// +// +// CallCatchBlock - continuation of CatchIt. +// +// This is separated from CatchIt because it needs to introduce an SEH/EH frame +// in case the catch block throws. This frame cannot be added until unwind of +// nested frames has been completed (otherwise this frame would be the first +// to go). + +static __declspec(guard(ignore)) void *CallCatchBlock( + EHExceptionRecord *pExcept, // The exception thrown + EHRegistrationNode *pRN, // Dynamic info of function with catch + CONTEXT *pContext, // Context info + FuncInfo *pFuncInfo, // Static info of function with catch + void *handlerAddress, // Code address of handler + int CatchDepth, // How deeply nested in catch blocks + // are we? + unsigned long NLGCode // NLG destination code +) { + // Address where execution resumes after exception handling completed. + // Initialized to non-nullptr (value doesn't matter) to distinguish from + // re-throw in __finally. + void *continuationAddress = handlerAddress; + + BOOL ExceptionObjectDestroyed = FALSE; + + // The stack pointer at entry to the try must be saved, in case there is + // another try inside this catch. We'll restore it on our way out. + void *saveESP = PRN_STACK(pRN); + + // Push this catch block's frame info on a linked list + FRAMEINFO FrameInfo; + FRAMEINFO *pFrameInfo = RENAME_EH_EXTERN(_CreateFrameInfo)(&FrameInfo, PER_PEXCEPTOBJ(pExcept)); + + // Save the current exception in case of a rethrow. Save the previous value + // on the stack, to be restored when the catch exits. + EHExceptionRecord *pSaveException = _pCurrentException; + CONTEXT *pSaveExContext = _pCurrentExContext; + + _pCurrentException = pExcept; + _pCurrentExContext = pContext; + + __try { + __try { + // Execute the handler as a funclet, whose return value is the + // address to resume execution. + continuationAddress = _CallCatchBlock2(pRN, pFuncInfo, + handlerAddress, CatchDepth, NLGCode); + } __except(ExFilterRethrow(exception_info())) { + cxxReThrow=false; + // Here we are exiting the catch block on rethrow out of this + // catch block. To keep the order of destruction and construction + // same when the the rethrow was from function or was inline, here + // we unwind to the parent state for this catch. + UnwindMapEntry *pUnwindMap = pFuncInfo->pUnwindMap; + int cState = RENAME_EH_EXTERN(__FrameHandler3)::GetCurrentState(pRN, handlerAddress, pFuncInfo); + TryBlockMapEntry *pTryBlockMap = pFuncInfo->pTryBlockMap; + unsigned int i; + for (i = 0; i < pFuncInfo->nTryBlocks; i++) { + if (cState > pTryBlockMap[i].tryHigh && + cState <= pTryBlockMap[i].catchHigh) { + cState = pTryBlockMap[i].tryHigh +1; + cState = pUnwindMap[cState].toState; + break; + } + } + RENAME_EH_EXTERN(__FrameHandler3)::FrameUnwindToState(pRN, nullptr, pFuncInfo, cState); + // If the handler threw a typed exception without exception info or + // exception object, then it's a re-throw, so return. Otherwise + // it's a new exception, which takes precedence over this one. + continuationAddress = nullptr; + } + } __finally { + EHTRACE_FMT1("Executing __finally, %snormal termination", _abnormal_termination() ? "ab" : ""); + // Restore the saved stack pointer, so the stack can be reset when + // we're done. + PRN_STACK(pRN) = saveESP; + + // Pop this catch block's frame info + RENAME_EH_EXTERN(_FindAndUnlinkFrame)(pFrameInfo); + + // Restore the 'current exception' for a possibly enclosing catch + _pCurrentException = pSaveException; + _pCurrentExContext = pSaveExContext; + + // Destroy the original exception object if we're not exiting on a + // re-throw and the object isn't also in use by a more deeply nested + // catch. Note that the catch handles destruction of its parameter. + + if (PER_IS_MSVC_EH(pExcept) && !ExceptionObjectDestroyed + && continuationAddress + && _IsExceptionObjectToBeDestroyed(PER_PEXCEPTOBJ(pExcept))) + { + __DestructExceptionObject(pExcept, abnormal_termination() != FALSE); + } + } + + return continuationAddress; +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// ExFilterRethrow - Exception filter for re-throw exceptions. +// +// Returns: +// EXCEPTION_EXECUTE_HANDLER - exception was a re-throw +// EXCEPTION_CONTINUE_SEARCH - anything else +// +// Side-effects: NONE. + +static int ExFilterRethrow( + EXCEPTION_POINTERS *pExPtrs +) { + // Get the exception record thrown (don't care about other info) + EHExceptionRecord *pExcept = (EHExceptionRecord *)pExPtrs->ExceptionRecord; + + // Check if it's ours and it's has no exception information. + if (PER_IS_MSVC_EH(pExcept) && PER_PTHROW(pExcept) == nullptr) { + // In a rethrow, ExceptionCode isn't set to EH_EXCEPTION_NUMBER even for a + // C++ Exception. Hence we use cxxReThrow in __InternalCxxFrameHandler + // to check for a C++ Exception + cxxReThrow = true; + return EXCEPTION_EXECUTE_HANDLER; + } else { + return EXCEPTION_CONTINUE_SEARCH; + } +} + +#endif /* } } */ + +//////////////////////////////////////////////////////////////////////////////// +// +// BuildCatchObjectHelper - Copy or construct the catch object from the object thrown. +// +// Returns: +// 0 if nothing to be done for constructing object from caller side +// 1 if single parameter constructor is to be called. +// 2 if two parameter constructor is to be called. +// +// Side-effects: +// A buffer in the subject function's frame is initialized. +// +// Open issues: +// What happens if the constructor throws? (or faults?) + +#pragma warning(push) +#pragma warning(disable:4191) + +template +static int BuildCatchObjectHelperInternal( + EHExceptionRecord *pExcept, // Original exception thrown + void *pRN, // This is a pointer to the object + // that we want to build while doing + // COM+ eh. If we are in our own eh, + // then this is a Registration node of + // catching function + typename T::HandlerType *pCatch, // The catch clause that got it + CatchableType *pConv // The conversion to use + ) +{ + int retval = 0; + + // If the catch is by ellipsis, then there is no object to construct. + // If the catch is by type(No Catch Object), then leave too! + if (HT_IS_TYPE_ELLIPSIS(*pCatch) || + (!HT_DISPCATCH(*pCatch) && !HT_ISCOMPLUSEH(*pCatch))) { + return 0; + } + + void **pCatchBuffer; + if (HT_ISCOMPLUSEH(*pCatch)) + { + pCatchBuffer = (void **)pRN; + } + else + { +#if _EH_RELATIVE_FUNCINFO + pCatchBuffer = (void **)OffsetToAddress( + HT_DISPCATCH(*pCatch), + *((EHRegistrationNode *)pRN) + ); +#else // ^^^ _EH_RELATIVE_FUNCINFO // !_EH_RELATIVE_FUNCINFO vvv + pCatchBuffer = (void **)OffsetToAddress( + HT_DISPCATCH(*pCatch), + (EHRegistrationNode *)pRN + ); +#endif // _EH_RELATIVE_FUNCINFO + } + __try { + if (HT_ISBADALLOCCOMPAT(*pCatch) && CT_ISSTDBADALLOC(*pConv) && __WinRTOutOfMemoryExceptionCallback) + { + void* pException = __WinRTOutOfMemoryExceptionCallback(); + + _VCRT_VERIFY(pException && pCatchBuffer); + *pCatchBuffer = pException; + *pCatchBuffer = __AdjustPointer(*pCatchBuffer, CT_THISDISP(*pConv)); + } + else if (HT_ISREFERENCE(*pCatch)) { + + // The catch is of form 'reference to T'. At the throw point we + // treat both 'T' and 'reference to T' the same, i.e. + // pExceptionObject is a (machine) pointer to T. Adjust as + // required. + _VCRT_VERIFY(PER_PEXCEPTOBJ(pExcept) && pCatchBuffer); + *pCatchBuffer = PER_PEXCEPTOBJ(pExcept); + *pCatchBuffer = __AdjustPointer(*pCatchBuffer, CT_THISDISP(*pConv)); + } + else if (CT_ISSIMPLETYPE(*pConv)) { + + // Object thrown is of simple type (this including pointers) copy + // specified number of bytes. Adjust the pointer as required. If + // the thing is not a pointer, then this should be safe since all + // the entries in the THISDISP are 0. + _VCRT_VERIFY(PER_PEXCEPTOBJ(pExcept) && pCatchBuffer); + memmove(pCatchBuffer, PER_PEXCEPTOBJ(pExcept), CT_SIZE(*pConv)); + if (CT_SIZE(*pConv) == sizeof(void*) && *pCatchBuffer) { + *pCatchBuffer = __AdjustPointer(*pCatchBuffer, CT_THISDISP(*pConv)); + } + } + else { + // Object thrown is UDT. + if (CT_COPYFUNC(*pConv) == nullptr) { + // The UDT had a simple ctor. Adjust in the thrown object, + // then copy n bytes. + _VCRT_VERIFY(PER_PEXCEPTOBJ(pExcept) && pCatchBuffer); + memmove(pCatchBuffer, __AdjustPointer(PER_PEXCEPTOBJ(pExcept), CT_THISDISP(*pConv)), CT_SIZE(*pConv)); + } + else { + // It's a UDT: make a copy using copy ctor + _VCRT_VERIFY(PER_PEXCEPTOBJ(pExcept) && pCatchBuffer && CT_COPYFUNC(*pConv)); + if (CT_HASVB(*pConv)) { + retval = 2; + } else { + retval = 1; + } + } + } + } __except(EXCEPTION_EXECUTE_HANDLER) { + // Something went wrong when building the catch object. + abort(); + } + + return retval; +} + +#pragma warning(pop) + +#if 0 +extern "C" _VCRTIMP int __cdecl RENAME_EH_EXTERN(__BuildCatchObjectHelper)( + EHExceptionRecord *pExcept, // Original exception thrown + void *pRN, // This is a pointer to the object + // that we want to build while doing + // COM+ eh. If we are in our own eh, + // then this is a Registration node of + // catching function + HandlerType *pCatch, // The catch clause that got it + CatchableType *pConv // The conversion to use + ) +{ + return BuildCatchObjectHelperInternal(pExcept, pRN, pCatch, pConv); +} + +int RENAME_EH_EXTERN(__FrameHandler3)::BuildCatchObjectHelper( + EHExceptionRecord *pExcept, + void *pRN, + HandlerType *pCatch, + CatchableType *pConv + ) +{ + return BuildCatchObjectHelperInternal(pExcept, pRN, pCatch, pConv); +} +#endif + +#if _VCRT_BUILD_FH4 +int RENAME_EH_EXTERN(__FrameHandler4)::BuildCatchObjectHelper( + EHExceptionRecord *pExcept, + void *pRN, + HandlerType *pCatch, + CatchableType *pConv + ) +{ + return BuildCatchObjectHelperInternal(pExcept, pRN, pCatch, pConv); +} +#endif // _VCRT_BUILD_FH4 + +//////////////////////////////////////////////////////////////////////////////// +// +// BuildCatchObjectInternal - Copy or construct the catch object from the object thrown. +// +// Returns: +// nothing. +// +// Side-effects: +// A buffer in the subject function's frame is initialized. +// +// Open issues: +// What happens if the constructor throws? (or faults?) + +template +static void BuildCatchObjectInternal( + EHExceptionRecord *pExcept, // Original exception thrown + void *pRN, // This is a pointer to the object + // that we want to build while doing + // COM+ eh. If we are in our own eh, + // then this is a Registration node of + // catching function + typename T::HandlerType *pCatch, // The catch clause that got it + CatchableType *pConv // The conversion to use + ) +{ + void **pCatchBuffer; + if ( HT_ISCOMPLUSEH(*pCatch)) + { + pCatchBuffer = (void **)pRN; + } + else + { +#if _EH_RELATIVE_FUNCINFO + pCatchBuffer = (void **)OffsetToAddress( + HT_DISPCATCH(*pCatch), + *((EHRegistrationNode *)pRN) + ); +#else + pCatchBuffer = (void **)OffsetToAddress( + HT_DISPCATCH(*pCatch), + (EHRegistrationNode *)pRN + ); +#endif + } + + __try { + switch(BuildCatchObjectHelperInternal(pExcept, pRN, pCatch, pConv)) + { + case 1: + _CallMemberFunction1((char *)pCatchBuffer, + CT_COPYFUNC(*pConv), + __AdjustPointer(PER_PEXCEPTOBJ(pExcept), + CT_THISDISP(*pConv))); + break; + case 2: + _CallMemberFunction2((char *)pCatchBuffer, + CT_COPYFUNC(*pConv), + __AdjustPointer(PER_PEXCEPTOBJ(pExcept), + CT_THISDISP(*pConv)), 1); + break; + case 0: + break; + default: + break; + } + } __except(EXCEPTION_EXECUTE_HANDLER) { + // Something went wrong when building the catch object. + abort(); + } +} + +#if 0 +extern "C" _VCRTIMP void __cdecl RENAME_EH_EXTERN(__BuildCatchObject)( + EHExceptionRecord *pExcept, // Original exception thrown + void *pRN, // This is a pointer to the object + // that we want to build while doing + // COM+ eh. If we are in our own eh, + // then this is a Registration node of + // catching function + HandlerType *pCatch, // The catch clause that got it + CatchableType *pConv // The conversion to use + ) +{ + BuildCatchObjectInternal(pExcept, pRN, pCatch, pConv); +} + +void RENAME_EH_EXTERN(__FrameHandler3)::BuildCatchObject( + EHExceptionRecord *pExcept, + void *pRN, + HandlerType *pCatch, + CatchableType *pConv + ) +{ + BuildCatchObjectInternal(pExcept, pRN, pCatch, pConv); +} +#endif + +#if _VCRT_BUILD_FH4 +void RENAME_EH_EXTERN(__FrameHandler4)::BuildCatchObject( + EHExceptionRecord *pExcept, + void *pRN, + HandlerType *pCatch, + CatchableType *pConv + ) +{ + BuildCatchObjectInternal(pExcept, pRN, pCatch, pConv); +} +#endif // _VCRT_BUILD_FH4 + +////////////////////////////////////////////////////////////////////////////////// +// IsInExceptionSpec - Checks if the exception matches the exception specification +// list. Returns TRUE if it does, otherwise FALSE +// +static BOOLEAN IsInExceptionSpec( + EHExceptionRecord *pExcept, // Information for this (logical) exception + ESTypeList *pESTypeList // Static information for subject frame +) +{ + _VCRT_VERIFY(pESTypeList); + BOOLEAN bFoundMatchingTypeInES = FALSE; + +#if _EH_RELATIVE_TYPEINFO + __int32 const *ppCatchable; +#elif defined(_WIN64) + CatchableType * UNALIGNED const *ppCatchable; +#else + CatchableType * const *ppCatchable; +#endif + CatchableType *pCatchable; + int catchables; + + // for every type in the exception spec... + for (int i=0; i 0; catchables--, ppCatchable++) { + +#if _EH_RELATIVE_TYPEINFO + pCatchable = (CatchableType *)(_GetThrowImageBase() + *ppCatchable); +#else + pCatchable = *ppCatchable; +#endif + if (RENAME_EH_EXTERN(__TypeMatch)(EST_ARRAY(pESTypeList,i), pCatchable, PER_PTHROW(pExcept))) + { + bFoundMatchingTypeInES = TRUE; + break; + } + } + } + + return bFoundMatchingTypeInES; +} + +////////////////////////////////////////////////////////////////////////////////// +// CallUnexpected - Calls unexpected and handles all exceptions +// thrown by it +// +// The unexpected() function shall not return, but it can throw (or re-throw) an +// exception. +// +// If it throws a new exception which is allowed by the exception +// specification which previously was violated, then +// { +// the search for another handler will continue at the call of the function +// whose exception specification was violated. +// } +// else /* If it throws or rethrows an exception that the exception-specification does not +// allow */ then the following happens: +// { +// If the exception-specification does not include the class std::bad_exception +// (lib.bad.exception) then +// { +// the function terminate() is called, +// } +// otherwise +// { +// the thrown exception is replaced by an implementation-defined +// object of the type std::bad_exception and the search for another handler +// will continue at the call of the function whose exception-specification +// was violated. +// } +// } +// +// Simple, isn't it? +// +static void CallUnexpected( ESTypeList* pESTypeList ) +{ + _VCRT_VERIFY(_pCurrentFuncInfo == nullptr); + + try + { + unexpected(); + } + catch(...) + { + _pCurrentFuncInfo = pESTypeList; + + throw; // rethrow -- we will catch it in the FrameHandler + } + terminate(); +} + +////////////////////////////////////////////////////////////////////////////////// +// Is_bad_exception_allowed - checks if std::bad_exception belongs to the list +// +static BOOLEAN Is_bad_exception_allowed(ESTypeList *pESTypeList) +{ + for (int i=0; i + +#define WIN32_LEAN_AND_MEAN // 从 Windows 头文件中排除极少使用的内容 + +#if defined _M_IX86 +#if defined _M_HYBRID +#define _LCRT_DECLARE_ALTERNATE_NAME_PREFIX "#" +#else +#define _LCRT_DECLARE_ALTERNATE_NAME_PREFIX "_" +#endif +#define _LCRT_DECLARE_ALTERNATE_NAME_PREFIX_DATA "_" +#elif defined _M_X64 || defined _M_ARM || defined _M_ARM64 +#define _LCRT_DECLARE_ALTERNATE_NAME_PREFIX "" +#define _LCRT_DECLARE_ALTERNATE_NAME_PREFIX_DATA "" +#else +#error Unsupported architecture +#endif + +// The _VCRT_DEFINE_IAT_SYMBOL macro provides an architecture-neutral way of +// defining IAT symbols (__imp_- or _imp__-prefixed symbols). +#ifdef _M_IX86 +#define _LCRT_DEFINE_IAT_SYMBOL_MAKE_NAME(f) _CRT_CONCATENATE(_imp__, f) +#else +#define _LCRT_DEFINE_IAT_SYMBOL_MAKE_NAME(f) _CRT_CONCATENATE(__imp_, f) +#endif + +#ifdef __cplusplus +#define __IAT_EXTERN_C extern "C" +#define __IAT_reinterpret_cast(f) reinterpret_cast(f) +#else +#define __IAT_EXTERN_C +#define __IAT_reinterpret_cast(f) f +#endif + +#ifdef _DLL + +#define _LCRT_DEFINE_IAT_SYMBOL(f) \ + __IAT_EXTERN_C __declspec(selectany) void const* const _LCRT_DEFINE_IAT_SYMBOL_MAKE_NAME(f) \ + = __IAT_reinterpret_cast(f) +#else + +//说明静态依赖,所以我们不需要定义 IAT_SYMBOL符号 +#define _LCRT_DEFINE_IAT_SYMBOL(f) + +#endif + + +#define __MakeVersion(Major, Minor, Build) ((Major << 12) + (Minor << 8) + Build) \ No newline at end of file diff --git a/vcruntime.src/Shared/internal_shared.h b/vcruntime.src/Shared/internal_shared.h new file mode 100644 index 0000000..c400050 --- /dev/null +++ b/vcruntime.src/Shared/internal_shared.h @@ -0,0 +1,771 @@ +// +// internal_shared.h +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Header-only utilities used by both the VCRuntime and the CoreCRT. +// +#pragma once + +#include +#include +#include +#include +#include +#include + +_CRT_BEGIN_C_HEADER + + + +extern IMAGE_DOS_HEADER __ImageBase; + + + +//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +// Preprocessor Utilities and Awesome Macros +// +//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// Attributes for managed declarations in the CRT +#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 + + + +// The pointer-width interlocked exchange and compare-exchange operations are +// not defined for x86. We declare them ourselves so that we can use the same +// macros consistently across all architectures: +#ifdef _M_IX86 + + #undef _InterlockedExchangePointer + #undef _InterlockedCompareExchangePointer + + #define _InterlockedExchangePointer(target, value) \ + ((void*)_InterlockedExchange((long volatile*)(target), (long)(value))) + + #define _InterlockedCompareExchangePointer(target, exchange, comparand) \ + ((void*)_InterlockedCompareExchange((long volatile*)(target), (long)(exchange), (long)(comparand))) + +#endif + + + +#define _BEGIN_SECURE_CRT_DEPRECATION_DISABLE \ + __pragma(warning(push)) \ + __pragma(warning(disable:4996)) \ + __pragma(warning(disable:25025)) \ + __pragma(warning(disable:28719)) + +#define _END_SECURE_CRT_DEPRECATION_DISABLE \ + __pragma(warning(pop)) + + + +#define CRT_WARNING_DISABLE_PUSH(x,y) \ + __pragma(warning(push)) \ + __pragma(warning(disable: x)) + +#define CRT_WARNING_POP \ + __pragma(warning(pop)) + + + +//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +// Section Attributes +// +//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +#pragma section(".CRT$XCA", long, read) // First C++ Initializer +#pragma section(".CRT$XCAA", long, read) // Startup C++ Initializer +#pragma section(".CRT$XCZ", long, read) // Last C++ Initializer + +#pragma section(".CRT$XDA", long, read) // First Dynamic TLS Initializer +#pragma section(".CRT$XDZ", long, read) // Last Dynamic TLS Initializer + +#pragma section(".CRT$XIA", long, read) // First C Initializer +#pragma section(".CRT$XIAA", long, read) // Startup C Initializer +#pragma section(".CRT$XIAB", long, read) // PGO C Initializer +#pragma section(".CRT$XIAC", long, read) // Post-PGO C Initializer +#pragma section(".CRT$XIC", long, read) // CRT C Initializers +#pragma section(".CRT$XIYA", long, read) // VCCorLib Threading Model Initializer +#pragma section(".CRT$XIYAA", long, read) // XAML Designer Threading Model Override Initializer +#pragma section(".CRT$XIYB", long, read) // VCCorLib Main Initializer +#pragma section(".CRT$XIZ", long, read) // Last C Initializer + +#pragma section(".CRT$XLA", long, read) // First Loader TLS Callback +#pragma section(".CRT$XLC", long, read) // CRT TLS Constructor +#pragma section(".CRT$XLD", long, read) // CRT TLS Terminator +#pragma section(".CRT$XLZ", long, read) // Last Loader TLS Callback + +#pragma section(".CRT$XPA", long, read) // First Pre-Terminator +#pragma section(".CRT$XPB", long, read) // CRT ConcRT Pre-Terminator +#pragma section(".CRT$XPX", long, read) // CRT Pre-Terminators +#pragma section(".CRT$XPXA", long, read) // CRT stdio Pre-Terminator +#pragma section(".CRT$XPZ", long, read) // Last Pre-Terminator + +#pragma section(".CRT$XTA", long, read) // First Terminator +#pragma section(".CRT$XTZ", long, read) // Last Terminator + +#pragma section(".CRTMA$XCA", long, read) // First Managed C++ Initializer +#pragma section(".CRTMA$XCZ", long, read) // Last Managed C++ Initializer + +#pragma section(".CRTVT$XCA", long, read) // First Managed VTable Initializer +#pragma section(".CRTVT$XCZ", long, read) // Last Managed VTable Initializer + +#pragma section(".rdata$T", long, read) + +#pragma section(".rtc$IAA", long, read) // First RTC Initializer +#pragma section(".rtc$IZZ", long, read) // Last RTC Initializer + +#pragma section(".rtc$TAA", long, read) // First RTC Terminator +#pragma section(".rtc$TZZ", long, read) // Last RTC Terminator + +#define _CRTALLOC(x) __declspec(allocate(x)) + + + +//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +// "Special" Data +// +//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +#ifndef _M_CEE + typedef void (__cdecl* _PVFV)(void); + typedef int (__cdecl* _PIFV)(void); + + extern _CRTALLOC(".CRT$XIA") _PIFV __xi_a[]; // First C Initializer + extern _CRTALLOC(".CRT$XIZ") _PIFV __xi_z[]; // Last C Initializer + extern _CRTALLOC(".CRT$XCA") _PVFV __xc_a[]; // First C++ Initializer + extern _CRTALLOC(".CRT$XCZ") _PVFV __xc_z[]; // Last C++ Initializer + extern _CRTALLOC(".CRT$XPA") _PVFV __xp_a[]; // First Pre-Terminator + extern _CRTALLOC(".CRT$XPZ") _PVFV __xp_z[]; // Last Pre-Terminator + extern _CRTALLOC(".CRT$XTA") _PVFV __xt_a[]; // First Terminator + extern _CRTALLOC(".CRT$XTZ") _PVFV __xt_z[]; // Last Terminator +#endif + + + +//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +// SEH Encapsulation +// +//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// Whenever we acquire locks in the CRT, we use SEH __try/__finally blocks to +// ensure that we release the lock under all circumstances, even if an unwind +// operation unwinds through the CRT frames. (Unexpected unwinding through the +// CRT is not a supported scenario, but we protect ourselves against this +// possibility anyway as a matter of policy.) +// +// These wrappers make it easier to mix SEH handling with RAII types in the CRT. +// The 'action' is called under a __try, and the 'cleanup' executes in the +// __finally block. Note that we expect the return type of the 'action callable +// to be either 'void' or some trivial type. At a minimum, the type must be +// value initializable. +#ifdef __cplusplus +extern "C++" +{ + template + struct __crt_seh_guarded_call + { + template + auto operator()(Setup&& setup, Action&& action, Cleanup&& cleanup) + -> decltype(action()) + { + decltype(action()) result{}; + + setup(); + __try + { + result = action(); + } + __finally + { + cleanup(); + } + + return result; + } + }; + + template <> + struct __crt_seh_guarded_call + { + template + void operator()(Setup&& setup, Action&& action, Cleanup&& cleanup) + { + setup(); + __try + { + action(); + } + __finally + { + cleanup(); + } + } + }; + + template + auto __crt_call_and_cleanup(Action&& action, Cleanup&& cleanup) + -> decltype(action()) + { + return __crt_seh_guarded_call()([](){}, action, cleanup); + } +} +#endif // __cplusplus + + + +//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +// CRT Memory Allocation and Management +// +//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +#ifdef _DEBUG + + // These must match the definitions in the CoreCRT's debug header. They + // are defined separately here to avoid unwanted CRT header dependencies. + #define _NORMAL_BLOCK 1 + #define _CRT_BLOCK 2 + + #define _calloc_crt(c, s) (_calloc_dbg ( c, s, _CRT_BLOCK, __FILE__, __LINE__)) + #define _free_crt(p) (_free_dbg (p, _CRT_BLOCK )) + #define _malloc_crt(s) (_malloc_dbg ( s, _CRT_BLOCK, __FILE__, __LINE__)) + #define _msize_crt(p) (_msize_dbg (p, _CRT_BLOCK )) + #define _recalloc_crt(p, c, s) (_recalloc_dbg(p, c, s, _CRT_BLOCK, __FILE__, __LINE__)) + #define _realloc_crt(p, s) (_realloc_dbg (p, s, _CRT_BLOCK, __FILE__, __LINE__)) + + #define _malloca_crt(size) \ + __pragma(warning(suppress: 6255)) \ + (_MallocaComputeSize(size) != 0 \ + ? _MarkAllocaS(_malloc_crt(_MallocaComputeSize(size)), _ALLOCA_S_HEAP_MARKER) \ + : NULL) + +#else // ^^^ _DEBUG ^^^ // vvv !_DEBUG vvv + + // The *_crt macros call the allocation function that vcruntime should use for + // internal allocations. It changes based off of where it is being built. + + #ifdef _CRT_WINDOWS + // When building for the UCRT, we want to use the internal allocation functions. + // We need to ensure that users hooking the public allocation functions do not + // interfere with the UCRT's allocations. + #define _calloc_crt _calloc_base + #define _free_crt _free_base + #define _malloc_crt _malloc_base + #define _realloc_crt _realloc_base + #define _msize_crt _msize_base + #define _recalloc_crt _recalloc_base + #else + // When building for vcruntime*.dll, we are not a part of the UCRT or OS so we + // should use the public allocation functions exported by the UCRT. + #define _calloc_crt calloc + #define _free_crt free + #define _malloc_crt malloc + #define _realloc_crt realloc + #define _msize_crt _msize + #define _recalloc_crt _recalloc + #endif + + #define _malloca_crt(size) \ + __pragma(warning(suppress: 6255)) \ + (_MallocaComputeSize(size) != 0 \ + ? ((_MallocaComputeSize(size) <= _ALLOCA_S_THRESHOLD) \ + ? _MarkAllocaS(_alloca(_MallocaComputeSize(size)), _ALLOCA_S_STACK_MARKER) \ + : _MarkAllocaS(_malloc_crt(_MallocaComputeSize(size)), _ALLOCA_S_HEAP_MARKER)) \ + : NULL) + +#endif // !_DEBUG + +#pragma warning(push) +#pragma warning(disable: 6014) +__inline void __CRTDECL _freea_crt(_Pre_maybenull_ _Post_invalid_ void* memory) +{ + if (memory) + { + unsigned int marker; + + memory = (char*)memory - _ALLOCA_S_MARKER_SIZE; + marker = *(unsigned int*)memory; + if (marker == _ALLOCA_S_HEAP_MARKER) + { + _free_crt(memory); + } + else if (marker != _ALLOCA_S_STACK_MARKER) + { + _ASSERTE(("Corrupted pointer passed to _freea", 0)); + } + } +} +#pragma warning(pop) + +#ifdef __cplusplus +extern "C++" { + + struct __crt_internal_free_policy + { + template + void operator()(T const* const p) const noexcept + { + _free_crt(const_cast(p)); + } + }; + + struct __crt_public_free_policy + { + template + void operator()(T const* const p) const noexcept + { + free(const_cast(p)); + } + }; + + template + class __crt_unique_heap_ptr + { + public: + + explicit __crt_unique_heap_ptr(T* const p = nullptr) noexcept + : _p(p) + { + } + + __crt_unique_heap_ptr(__crt_unique_heap_ptr const&) = delete; + __crt_unique_heap_ptr& operator=(__crt_unique_heap_ptr const&) = delete; + + __crt_unique_heap_ptr(__crt_unique_heap_ptr&& other) noexcept + : _p(other._p) + { + other._p = nullptr; + } + + ~__crt_unique_heap_ptr() noexcept + { + release(); + } + + __crt_unique_heap_ptr& operator=(__crt_unique_heap_ptr&& other) noexcept + { + release(); + _p = other._p; + other._p = nullptr; + return *this; + } + + T* detach() noexcept + { + T* const local_p{_p}; + _p = nullptr; + return local_p; + } + + void attach(T* const p) noexcept + { + release(); + _p = p; + } + + void release() noexcept + { + Free()(_p); + _p = nullptr; + } + + bool is_valid() const noexcept + { + return _p != nullptr; + } + + explicit operator bool() const noexcept + { + return is_valid(); + } + + T* get() const noexcept + { + return _p; + } + + T** get_address_of() noexcept + { + return &_p; + } + + T** release_and_get_address_of() noexcept + { + release(); + return &_p; + } + + private: + T* _p; + }; + + // An internal-use scoped smart pointer for memory allocated by _malloca_crt. + template + struct __crt_scoped_stack_ptr_tag + { + __crt_scoped_stack_ptr_tag(T* const p) noexcept + : _p(p) + { + } + + T* _p; + }; + + template + class __crt_scoped_stack_ptr + { + public: + + explicit __crt_scoped_stack_ptr(__crt_scoped_stack_ptr_tag const p) noexcept + : _p(p._p) + { + } + + __crt_scoped_stack_ptr(__crt_scoped_stack_ptr const&) = delete; + __crt_scoped_stack_ptr& operator=(__crt_scoped_stack_ptr const&) = delete; + + ~__crt_scoped_stack_ptr() noexcept + { + _freea_crt(_p); + } + + T* get() const noexcept { return _p; } + + // Note that we do not provide a release() because one would not be + // useful: a stack allocation is only useful in the scope in which it + // was allocated. + + explicit operator bool() const noexcept + { + return _p != nullptr; + } + + private: + T* const _p; + }; + + // Note that no overflow checks are necessary for the multiplications here, + // because each multiplication operation is an argument to a parameter that + // is decorated __declspec(guard(overflow)). + #define _calloc_crt_t(t, n) (__crt_unique_heap_ptr (static_cast(_calloc_crt ( (n), sizeof(t))))) + #define _malloc_crt_t(t, n) (__crt_unique_heap_ptr (static_cast(_malloc_crt ( (n) * sizeof(t))))) + #define _recalloc_crt_t(t, p, n) (__crt_unique_heap_ptr (static_cast(_recalloc_crt((p), (n), sizeof(t))))) + #define _malloca_crt_t(t, n) (__crt_scoped_stack_ptr_tag(static_cast(_malloca_crt ( (n) * sizeof(t))))) + + + + enum : int + { + __crt_maximum_pointer_shift = sizeof(uintptr_t) * 8 + }; + + inline unsigned int __crt_rotate_pointer_value(unsigned int const value, + int const shift) noexcept + { + return RotateRight32(value, shift); + } + + inline unsigned __int64 __crt_rotate_pointer_value(unsigned __int64 const value, + int const shift) noexcept + { + return RotateRight64(value, shift); + } + + // Fast alternatives to the encode/decode pointer functions that do not use + // the EncodePointer and DecodePointer functions. + template + T __crt_fast_decode_pointer(T const p) noexcept + { + return reinterpret_cast( + __crt_rotate_pointer_value( + reinterpret_cast(p) ^ __security_cookie, + __security_cookie % __crt_maximum_pointer_shift + ) + ); + } + + template + T __crt_fast_encode_pointer(T const p) noexcept + { + return reinterpret_cast( + __crt_rotate_pointer_value( + reinterpret_cast(p), + __crt_maximum_pointer_shift - (__security_cookie % __crt_maximum_pointer_shift) + ) ^ __security_cookie + ); + } + + // The primary __crt_fast_encode_pointer template does not work properly + // when it is called with the argument 'nullptr' because the encoded void* + // pointer is casted back to nullptr_t, and nullptr_t can only represent a + // single value: the real, unencoded null pointer. Therefore, we overload + // the function for nullptr_t, and defer the cast until we know the actual + // type that we need. + struct __crt_fast_encoded_nullptr_t + { + template + operator T*() const noexcept + { + return __crt_fast_encode_pointer(static_cast(nullptr)); + } + }; + + inline __crt_fast_encoded_nullptr_t __crt_fast_encode_pointer(decltype(nullptr)) noexcept + { + 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 + { + // This is required to silence a spurious unreferenced formal parameter + // warning. + UNREFERENCED_PARAMETER(value); + + return reinterpret_cast(_InterlockedExchangePointer((void**)target, (void*)value)); + } + + template + T __crt_interlocked_compare_exchange(T* const target, E const exchange, + C const comparand) noexcept + { + UNREFERENCED_PARAMETER(exchange); // These are required to silence spurious + 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( + reinterpret_cast(target), (LONG)exchange, (LONG)comparand)); + } + + template + T* __crt_interlocked_compare_exchange_pointer(T* const volatile* target, E const exchange, + C const comparand) noexcept + { + UNREFERENCED_PARAMETER(exchange); // These are required to silence spurious + UNREFERENCED_PARAMETER(comparand); // unreferenced formal parameter warnings. + + return reinterpret_cast(_InterlockedCompareExchangePointer( + (void**)target, (void*)exchange, (void*)comparand)); + } + + #ifndef _M_CEE_PURE + + #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 + + 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 + #endif + } + + #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(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 + + + +#define _CRT_DEBUGGER_IGNORE -1 +#define _CRT_DEBUGGER_GSFAILURE 1 +#define _CRT_DEBUGGER_INVALIDPARAMETER 2 +#define _CRT_DEBUGGER_ABORT 3 + +// Note: These names are well-known to the debugger +#ifdef _M_IX86 + void __cdecl _crt_debugger_hook(int); + #define _CRT_DEBUGGER_HOOK _crt_debugger_hook +#else + void __cdecl __crt_debugger_hook(int); + #define _CRT_DEBUGGER_HOOK __crt_debugger_hook +#endif + + + +//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +// Precondition Validation Macros +// +//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +#ifdef _DEBUG + #define _INVALID_PARAMETER(expr) _invalid_parameter(expr, __FUNCTIONW__, __FILEW__, __LINE__, 0) +#else + #define _INVALID_PARAMETER(expr) _invalid_parameter_noinfo() +#endif + +#define _VALIDATE_CLEAR_OSSERR_RETURN(expr, errorcode, retexpr) \ + { \ + int _Expr_val=!!(expr); \ + _ASSERT_EXPR((_Expr_val), _CRT_WIDE(#expr)); \ + if (!(_Expr_val)) \ + { \ + _doserrno = 0L; \ + errno = errorcode; \ + _INVALID_PARAMETER(_CRT_WIDE(#expr)); \ + return retexpr; \ + } \ + } + +#define _VALIDATE_CLEAR_OSSERR_RETURN_ERRCODE(expr, errorcode) \ + { \ + int _Expr_val=!!(expr); \ + _ASSERT_EXPR((_Expr_val), _CRT_WIDE(#expr)); \ + if (!(_Expr_val)) \ + { \ + _doserrno = 0L; \ + errno = errorcode; \ + _INVALID_PARAMETER(_CRT_WIDE(#expr)); \ + return errorcode; \ + } \ + } + +#define _VALIDATE_RETURN(expr, errorcode, retexpr) \ + { \ + int _Expr_val=!!(expr); \ + _ASSERT_EXPR((_Expr_val), _CRT_WIDE(#expr)); \ + if (!(_Expr_val)) \ + { \ + errno = errorcode; \ + _INVALID_PARAMETER(_CRT_WIDE(#expr)); \ + return retexpr; \ + } \ + } + +#define _VALIDATE_RETURN_ERRCODE(expr, errorcode) \ + { \ + int _Expr_val=!!(expr); \ + _ASSERT_EXPR((_Expr_val), _CRT_WIDE(#expr)); \ + if (!(_Expr_val)) \ + { \ + errno = errorcode; \ + _INVALID_PARAMETER(_CRT_WIDE(#expr)); \ + return errorcode; \ + } \ + } + +#define _VALIDATE_RETURN_ERRCODE_NOEXC(expr, errorcode) \ + { \ + if (!(expr)) \ + { \ + errno = errorcode; \ + return errorcode; \ + } \ + } + +#define _VALIDATE_RETURN_NOERRNO(expr, retexpr) \ + { \ + int _Expr_val=!!(expr); \ + _ASSERT_EXPR((_Expr_val), _CRT_WIDE(#expr)); \ + if (!(_Expr_val)) \ + { \ + _INVALID_PARAMETER(_CRT_WIDE(#expr)); \ + return retexpr; \ + } \ + } + +#define _VALIDATE_RETURN_NOEXC(expr, errorcode, retexpr) \ + { \ + if (!(expr)) \ + { \ + errno = errorcode; \ + return retexpr; \ + } \ + } + +#define _VALIDATE_RETURN_VOID(expr, errorcode) \ + { \ + int _Expr_val=!!(expr); \ + _ASSERT_EXPR((_Expr_val), _CRT_WIDE(#expr)); \ + if (!(_Expr_val)) \ + { \ + errno = errorcode; \ + _INVALID_PARAMETER(_CRT_WIDE(#expr)); \ + return; \ + } \ + } + + + +_CRT_END_C_HEADER diff --git a/vcruntime.src/Shared/risctrnsctrl.cpp b/vcruntime.src/Shared/risctrnsctrl.cpp new file mode 100644 index 0000000..52a8584 --- /dev/null +++ b/vcruntime.src/Shared/risctrnsctrl.cpp @@ -0,0 +1,546 @@ +/*** +*risctrnsctrl.cpp - +* +* Copyright (c) Microsoft Corporation. All rights reserved. +* +*Purpose: +* Common control transfer helpers required for RISC and AMD64 architecture +* EH. +****/ + +//#include +#include +#include +#include +#include +#include +#include +#include "ehhelpers.h" +#include + +#include "framework.h" + +#if !defined(RENAME_EH_EXTERN_HYBRID) +#define RENAME_EH_EXTERN_HYBRID(x) x +#endif + +#if _EH_RELATIVE_FUNCINFO + +#define _ImageBase (RENAME_BASE_PTD(__vcrt_getptd)()->_ImageBase) + +extern "C" uintptr_t __cdecl _GetImageBase() +{ + return _ImageBase; +} + +extern "C" void __cdecl _SetImageBase(uintptr_t ImageBaseToRestore) +{ + _ImageBase = ImageBaseToRestore; +} + +#endif + +#if _EH_RELATIVE_TYPEINFO + +#define _ThrowImageBase (RENAME_BASE_PTD(__vcrt_getptd)()->_ThrowImageBase) + +extern "C" uintptr_t __cdecl _GetThrowImageBase() +{ + return _ThrowImageBase; +} + +extern "C" void __cdecl _SetThrowImageBase(uintptr_t NewThrowImageBase) +{ + _ThrowImageBase = NewThrowImageBase; +} + +#endif + +#if _EH_RELATIVE_FUNCINFO +#if _VCRT_BUILD_FH4 +// +// Returns the establisher frame pointers. For catch handlers it is the parent's frame pointer. +// +EHRegistrationNode * RENAME_EH_EXTERN(__FrameHandler4)::GetEstablisherFrame +( + EHRegistrationNode *pRN, + DispatcherContext *pDC, + FuncInfo *pFuncInfo, + EHRegistrationNode *pEstablisher + ) +{ + + *pEstablisher = *pRN; + + if (RENAME_EH_EXTERN(__FrameHandler4)::ExecutionInCatch(pDC, pFuncInfo)) + { + +#if defined(_M_ARM64EC) + + if (RtlIsEcCode(pDC->ControlPc)) { + *pEstablisher = *(EHRegistrationNode *)*pEstablisher; + } else { + *pEstablisher = *(EHRegistrationNode *)OffsetToAddress(pFuncInfo->dispFrame, *pRN); + } + +#elif defined(_M_X64) + + *pEstablisher = *(EHRegistrationNode *)OffsetToAddress(pFuncInfo->dispFrame, *pRN); + +#elif defined(_M_ARM_NT) || defined(_M_ARM64) || defined(_CHPE_X86_ARM64_EH_) + + *pEstablisher = *(EHRegistrationNode *)*pEstablisher; + +#else // architecture + +#error Unknown processor architecture. + +#endif // architecture + } + + return pEstablisher; +} +#endif // _VCRT_BUILD_FH4 + +// +// Returns the establisher frame pointers. For catch handlers it is the parent's frame pointer. +// +#if 0 +EHRegistrationNode * RENAME_EH_EXTERN(__FrameHandler3)::GetEstablisherFrame( + EHRegistrationNode *pRN, + DispatcherContext *pDC, + FuncInfo *pFuncInfo, + EHRegistrationNode *pEstablisher + ) +{ + TryBlockMapEntry *pEntry; + HandlerType *pHandler; + ULONG_PTR HandlerAdd, ImageBase; + unsigned num_of_try_blocks = FUNC_NTRYBLOCKS(*pFuncInfo); + unsigned index, i; + __ehstate_t curState; + + curState = StateFromControlPc(pFuncInfo, pDC); + *pEstablisher = *pRN; + for (index = num_of_try_blocks; index > 0; index--) { + pEntry = FUNC_PTRYBLOCK(*pFuncInfo, index -1, pDC->ImageBase); + if (curState > TBME_HIGH(*pEntry) && curState <= TBME_CATCHHIGH(*pEntry)) { + // Get catch handler address. + HandlerAdd = (*RENAME_EH_EXTERN(RtlLookupFunctionEntry)(pDC->ControlPc, + &ImageBase, + nullptr)).BeginAddress; + pHandler = TBME_PLIST(*pEntry, ImageBase); + for ( i = 0; + i < (unsigned)TBME_NCATCHES(*pEntry) && + static_cast(pHandler[i].dispOfHandler) != HandlerAdd + ; i++); + if ( i < (unsigned)TBME_NCATCHES(*pEntry)) { + +#if defined(_M_ARM64EC) + + if (RtlIsEcCode(pDC->ControlPc)) { + *pEstablisher = *(EHRegistrationNode *)*pEstablisher; + } else { + *pEstablisher = *(EHRegistrationNode *)OffsetToAddress(pHandler[i].dispFrame, *pRN); + } + +#elif defined(_M_X64) + + *pEstablisher = *(EHRegistrationNode *)OffsetToAddress(pHandler[i].dispFrame, *pRN); + +#elif defined(_M_ARM_NT) || defined(_M_ARM64) || defined(_CHPE_X86_ARM64_EH_) + + *pEstablisher = *(EHRegistrationNode *)*pEstablisher; + +#else + +#error Unknown processor architecture. + +#endif + + break; + } + } + } + return pEstablisher; +} +#endif + +// This function returns the try block for the given state if the state is in a +// catch; otherwise, nullptr is returned. + +#if 0 +TryBlockMapEntry * RENAME_EH_EXTERN(__FrameHandler3)::CatchTryBlock( + FuncInfo *pFuncInfo, + __ehstate_t curState +) { + TryBlockMapEntry *pEntry; + unsigned num_of_try_blocks = FUNC_NTRYBLOCKS(*pFuncInfo); + unsigned index; + + for (index = num_of_try_blocks; index > 0; index--) { + pEntry = FUNC_PTRYBLOCK(*pFuncInfo, index -1, _ImageBase); + if (curState > TBME_HIGH(*pEntry) && curState <= TBME_CATCHHIGH(*pEntry)) { + return pEntry; + } + } + + return nullptr; +} +#endif + +// +// This routine returns TRUE if we are executing from within a catch. Otherwise, FALSE is returned. +// +#if _VCRT_BUILD_FH4 +bool RENAME_EH_EXTERN(__FrameHandler4)::ExecutionInCatch( + DispatcherContext* /*pDC*/, + FuncInfo *pFuncInfo + ) +{ + return pFuncInfo->header.isCatch; +} +#endif // _VCRT_BUILD_FH4 + +#if 0 +bool RENAME_EH_EXTERN(__FrameHandler3)::ExecutionInCatch( + DispatcherContext *pDC, + FuncInfo *pFuncInfo + ) +{ + __ehstate_t curState = StateFromControlPc(pFuncInfo, pDC); + return CatchTryBlock(pFuncInfo, curState)? TRUE : FALSE; +} +#endif + +// The name of this function is rather misleading. This function won't really unwind +// to empty state. This function will unwind to lowest possible state for current block. +// Here is an example +// +// try { +// // State = 1; +// } catch (...) { +// // State when we enter catch is 2 +// // State inside catch is 3-5; +// } +// if __FrameUnwindToEmptyState is called for the main function, the target state will +// be -1 but if __FrameUnwindToEmptyState is called for catch block, the target state for +// __FrameUnwindToState will be 2 not -1. This way we are able to unwind the stack block +// by block not the whole function in single call. +#if _VCRT_BUILD_FH4 +void RENAME_EH_EXTERN(__FrameHandler4)::FrameUnwindToEmptyState( + EHRegistrationNode *pRN, + DispatcherContext *pDC, + FuncInfo *pFuncInfo + ) +{ + EHRegistrationNode EstablisherFramePointers, *pEstablisher; + + pEstablisher = GetEstablisherFrame(pRN, pDC, pFuncInfo, &EstablisherFramePointers); + + FrameUnwindToState(pEstablisher, pDC, pFuncInfo, EH_EMPTY_STATE); +} +#endif // _VCRT_BUILD_FH4 + +#if 0 +void RENAME_EH_EXTERN(__FrameHandler3)::FrameUnwindToEmptyState( + EHRegistrationNode *pRN, + DispatcherContext *pDC, + FuncInfo *pFuncInfo + ) +{ + __ehstate_t stateFromControlPC; + TryBlockMapEntry *pEntry; + EHRegistrationNode EstablisherFramePointers, *pEstablisher; + + pEstablisher = GetEstablisherFrame(pRN, + pDC, + pFuncInfo, + &EstablisherFramePointers); + + stateFromControlPC = StateFromControlPc(pFuncInfo, pDC); + pEntry = CatchTryBlock(pFuncInfo, stateFromControlPC); + + FrameUnwindToState(pEstablisher, pDC, pFuncInfo, + pEntry == nullptr ? EH_EMPTY_STATE : TBME_HIGH(*pEntry)); +} +#endif + +#if _VCRT_BUILD_FH4 && WindowsTargetPlatformMinVersion < __MakeVersion(10, 0, 19041) +extern "C" DECLSPEC_GUARD_SUPPRESS EXCEPTION_DISPOSITION __cdecl RENAME_EH_EXTERN_HYBRID(__CxxFrameHandler4)( + EHExceptionRecord *pExcept, // Information for this exception + EHRegistrationNode RN, // Dynamic information for this frame + CONTEXT *pContext, // Context info + DispatcherContext *pDC // More dynamic info for this frame + ) { + FH4::FuncInfo4 FuncInfo; + EXCEPTION_DISPOSITION result; + EHRegistrationNode EstablisherFrame = RN; + + _ImageBase = pDC->ImageBase; +#ifdef _ThrowImageBase + _ThrowImageBase = (uintptr_t)pExcept->params.pThrowImageBase; +#endif + PBYTE buffer = (PBYTE)(_ImageBase + *(PULONG)pDC->HandlerData); + + FH4::DecompFuncInfo(buffer, FuncInfo, pDC->ImageBase, pDC->FunctionEntry->BeginAddress); + + result = __InternalCxxFrameHandler(pExcept, &EstablisherFrame, pContext, pDC, &FuncInfo, 0, nullptr, FALSE); + return result; +} + +_LCRT_DEFINE_IAT_SYMBOL(RENAME_EH_EXTERN_HYBRID(__CxxFrameHandler4)); + +#endif // _VCRT_BUILD_FH4 + +// Call the SEH to EH translator. +template +static int SehTransFilter( + EXCEPTION_POINTERS *ExPtrs, + EHExceptionRecord *pExcept, + EHRegistrationNode *pRN, + CONTEXT *pContext, + DispatcherContext *pDC, + typename T::FuncInfo *pFuncInfo, + __ehstate_t curState, + BOOL *pResult +) { + + UNREFERENCED_PARAMETER(curState); + _pForeignExcept = pExcept; +#ifdef _ThrowImageBase + _ThrowImageBase = (uintptr_t)((EHExceptionRecord *)ExPtrs->ExceptionRecord)->params.pThrowImageBase; +#endif + +#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. + // 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, + pRN, + pContext, + pDC, + pFuncInfo, + 0, + nullptr, + TRUE ); + _pForeignExcept = nullptr; + *pResult = TRUE; + return EXCEPTION_EXECUTE_HANDLER; +} + +template +BOOL _CallSETranslator( + EHExceptionRecord *pExcept, // The exception to be translated + EHRegistrationNode *pRN, // Dynamic info of function with catch + CONTEXT *pContext, // Context info + DispatcherContext *pDC, // More dynamic info of function with catch (ignored) + typename T::FuncInfo *pFuncInfo, // Static info of function with catch + ULONG CatchDepth, // How deeply nested in catch blocks are we? + EHRegistrationNode *pMarkerRN, // Marker for parent context + __ehstate_t curState // Current state + ) +{ + UNREFERENCED_PARAMETER(pMarkerRN); + + BOOL result = FALSE; + pRN; + pDC; + pFuncInfo; + CatchDepth; + + // Call the translator. + + _EXCEPTION_POINTERS excptr = { (PEXCEPTION_RECORD)pExcept, pContext }; + + __try { + _se_translator_function pSETranslator; + pSETranslator = __pSETranslator; + pSETranslator(PER_CODE(pExcept), &excptr); + result = FALSE; + } __except(SehTransFilter(exception_info(), + pExcept, + pRN, + pContext, + pDC, + pFuncInfo, + curState, + &result + )) {} + + // If we got back, then we were unable to translate it. + + return result; +} + +#if _VCRT_BUILD_FH4 +template +BOOL _CallSETranslator( + EHExceptionRecord *pExcept, // The exception to be translated + EHRegistrationNode *pRN, // Dynamic info of function with catch + CONTEXT *pContext, // Context info + DispatcherContext *pDC, // More dynamic info of function with catch (ignored) + RENAME_EH_EXTERN(__FrameHandler4)::FuncInfo *pFuncInfo, // Static info of function with catch + ULONG CatchDepth, // How deeply nested in catch blocks are we? + EHRegistrationNode *pMarkerRN, // Marker for parent context + __ehstate_t curState // Current state + ); +#endif // _VCRT_BUILD_FH4 + + +///////////////////////////////////////////////////////////////////////////// +// +// GetRangeOfTrysToCheck - determine which try blocks are of interest. +// +// The try blocks of interest are the ones in current catch block or function block. +// We will not try to call the catch that are outside the scope of this block. Consider +// the example. +// +// foo() { +// try { // Try block 1 +// try { // Try block 2 +// throw 1; // Throw1 +// } catch (int) { // Catch block 1 +// try { // Try block 3 +// throw 1; // Throw2 +// } catch (int) { // Catch block 2 +// throw; // Throw3 +// } +// } +// } catch (int) { // Catch block 3 +// } +// } +// +// When we have exception from Throw1, our block of concern is function foo. Here the +// try blocks of interest are Try block 2 and Try block 1. +// +// When we have exception for Throw2, we are in Catch block 1 and thus try block of +// concern is Try block 3. We don't really need to care about Try block 1 here as +// we have the main function block still on the stack and exception handler will also +// be called for that block. +// +// Returns: +// Address of first try block of interest is returned +// pStart and pEnd get the indices of the range in question +// +#if _VCRT_BUILD_FH4 +RENAME_EH_EXTERN(__FrameHandler4)::TryBlockMap::IteratorPair RENAME_EH_EXTERN(__FrameHandler4)::GetRangeOfTrysToCheck( + TryBlockMap &tryBlockMap, + __ehstate_t curState, + DispatcherContext * /*pDC*/, + FuncInfo * /*pFuncInfo*/, + int /*CatchDepth*/ +) +{ + auto iterStart = tryBlockMap.begin(); + auto iterEnd = tryBlockMap.begin(); + tryBlockMap.setBuffer(iterStart); + + for (auto iter = tryBlockMap.begin(); iter != tryBlockMap.end(); ++iter) + { + auto tryBlock = *iter; + if (curState >= tryBlock.tryLow && curState <= tryBlock.tryHigh) { + if (iterStart != tryBlockMap.begin()) { + iterStart = iter; + } + iterEnd = iter; + } + } + // change to be (start, end] + iterEnd.incrementToSentinel(); + // Reset so when we start reading it starts at the correct location + tryBlockMap.setBuffer(iterStart); + return TryBlockMap::IteratorPair(iterStart, iterEnd); +} +#endif // _VCRT_BUILD_FH4 + + +#if _VCRT_BUILD_FH4 +void RENAME_EH_EXTERN(__FrameHandler4)::UnwindNestedFrames( + EHRegistrationNode *pFrame, // Unwind up to (but not including) this frame + EHExceptionRecord *pExcept, // The exception that initiated this unwind + CONTEXT *pContext, // Context info for current exception + EHRegistrationNode *pEstablisher, + void *Handler, + FuncInfo* /*pFuncInfo*/, + __ehstate_t TargetUnwindState, + __ehstate_t CatchState, // State outside of current try but inside of any enclosing trys + HandlerType *pCatch, + DispatcherContext *pDC, + BOOLEAN recursive + ) +{ + static const EXCEPTION_RECORD ExceptionTemplate = // A generic exception record + { + STATUS_UNWIND_CONSOLIDATE, // STATUS_UNWIND_CONSOLIDATE + EXCEPTION_NONCONTINUABLE, // Exception flags (we don't do resume) + nullptr, // Additional record (none) + nullptr, // Address of exception (OS fills in) + 15, // Number of parameters + { EH_MAGIC_NUMBER1, // Our version control magic number + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0 + } // pThrowInfo + }; + + EXCEPTION_RECORD ExceptionRecord = ExceptionTemplate; + ExceptionRecord.ExceptionInformation[0] = (ULONG_PTR)CxxCallCatchBlock; + // Address of call back function + ExceptionRecord.ExceptionInformation[1] = (ULONG_PTR)pEstablisher; + // Used by callback function + ExceptionRecord.ExceptionInformation[2] = (ULONG_PTR)Handler; + // Used by callback function to call catch block + ExceptionRecord.ExceptionInformation[3] = (ULONG_PTR)TargetUnwindState; + // Used by CxxFrameHandler to unwind to target_state + ExceptionRecord.ExceptionInformation[4] = (ULONG_PTR)pContext; + // used to set pCurrentExContext in callback function + ExceptionRecord.ExceptionInformation[5] = pCatch->continuationAddress[0] + pDC->ImageBase; + // Used in callback function for continuation address lookup + ExceptionRecord.ExceptionInformation[6] = (ULONG_PTR)pExcept; + // Used for passing current Exception + 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 + // called from _UnwindNestedFrames. + + // TODO: make these contiguous + ExceptionRecord.ExceptionInformation[9] = pCatch->continuationAddress[1] + pDC->ImageBase; + // Used in callback function for continuation address lookup + +#if defined(_M_ARM64EC) + + if (RtlIsEcCode(pDC->ControlPc)) { + ExceptionRecord.ExceptionInformation[10] = static_cast(-1); + } + +#elif defined(_M_ARM_NT) || defined(_M_ARM64) || defined(_CHPE_X86_ARM64_EH_) + + ExceptionRecord.ExceptionInformation[10] = static_cast(-1); + // ARM/ARM64-specific: used to hold a pointer to the non-volatile + // registers + +#elif !defined(_M_X64) + +#error Unknown processor architecture. + +#endif + + // Used to associate Catch Handler state to parent state + ExceptionRecord.ExceptionInformation[11] = CatchState; + + RtlUnwindEx((void *)*pFrame, + (void *)pDC->ControlPc, // Address where control left function + &ExceptionRecord, + nullptr, + pDC->ContextRecord, + (PUNWIND_HISTORY_TABLE)pDC->HistoryTable); +} +#endif // _VCRT_BUILD_FH4 + +#endif // _EH_RELATIVE_FUNCINFO diff --git a/vcruntime.src/Shared/telemetry.cpp b/vcruntime.src/Shared/telemetry.cpp new file mode 100644 index 0000000..14a1d25 --- /dev/null +++ b/vcruntime.src/Shared/telemetry.cpp @@ -0,0 +1,16 @@ + +#include "framework.h" + +typedef void* HINSTANCE; + +extern "C" void __cdecl __telemetry_main_invoke_trigger(HINSTANCE) +{ +} + +_LCRT_DEFINE_IAT_SYMBOL(__telemetry_main_invoke_trigger); + +extern "C" void __cdecl __telemetry_main_return_trigger(HINSTANCE) +{ +} + +_LCRT_DEFINE_IAT_SYMBOL(__telemetry_main_return_trigger); diff --git a/vcruntime.src/Shared/trnsctrl.h b/vcruntime.src/Shared/trnsctrl.h new file mode 100644 index 0000000..a2957fb --- /dev/null +++ b/vcruntime.src/Shared/trnsctrl.h @@ -0,0 +1,270 @@ +// +// trnsctrl.h +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Internal VCRuntime header that defines the functions that perform special +// transfer of control operations and related things. +// +#pragma once + +#include +#include + +#if !defined(RENAME_EH_EXTERN) +#define RENAME_EH_EXTERN(x) x +#endif + +#pragma pack(push, _CRT_PACKING) + +// Link together all existing catch objects to determine when they should +// be destroyed +typedef struct FrameInfo +{ + PVOID pExceptionObject; + +#if defined _M_ARM + + EHRegistrationNode* pRN; + struct _s_FuncInfo* pFuncInfo; + __ehstate_t state; + +#endif + + struct FrameInfo* pNext; +} FRAMEINFO; + +#if defined(_M_ARM64EC) + extern "C" PVOID RENAME_EH_EXTERN(_CallSettingFrameArm64Ec)( + void*, + EHRegistrationNode*, + PULONG, + ULONG + ); +#endif + +#if defined _M_X64 || defined _M_ARM_NT || defined _M_ARM64 || defined _CHPE_X86_ARM64_EH_ + extern "C" PVOID RENAME_EH_EXTERN(_CallSettingFrame)( + void*, + EHRegistrationNode*, +#if defined _M_ARM_NT || defined _M_ARM64 || defined _CHPE_X86_ARM64_EH_ + PULONG, +#endif + ULONG + ); + + extern "C" PVOID RENAME_EH_EXTERN(_CallSettingFrame_LookupContinuationIndex)( + void*, + EHRegistrationNode*, +#if defined _M_ARM_NT || defined _M_ARM64 || defined _CHPE_X86_ARM64_EH_ + PULONG, +#endif + ULONG + ); + + extern "C" PVOID RENAME_EH_EXTERN(_CallSettingFrame_NotifyContinuationAddr)( + void*, + EHRegistrationNode* + ); + + extern "C" PVOID RENAME_EH_EXTERN(_CallSettingFrameEncoded)( + void*, + EHRegistrationNode, + void*, +#if defined _M_ARM_NT || defined _M_ARM64 || defined _CHPE_X86_ARM64_EH_ + PULONG, +#endif + ULONG + ); + + #define OffsetToAddress(offset, fp) (void*)(((char*)(fp)) + (offset)) + + #define UNWINDSTATE(base, offset) *((int*)((char*)base + offset)) + #define UNWINDTRYBLOCK(base, offset) *((int*)((char*)(OffsetToAddress(offset,base)) + 4)) + #define UNWINDHELP(base, offset) *((__int64*)((char*)base + offset)) + + extern "C" uintptr_t __cdecl _GetImageBase(); + + extern "C" void __cdecl _SetImageBase( + uintptr_t ImageBaseToRestore + ); + +#if !defined(_CHPE_X86_ARM64_EH_) + + extern "C" uintptr_t __cdecl _GetThrowImageBase(); + + extern "C" void __cdecl _SetThrowImageBase( + uintptr_t NewThrowImageBase + ); + +#endif + + template + BOOL _CallSETranslator( + EHExceptionRecord *pExcept, + EHRegistrationNode *pRN, + CONTEXT *pContext, + DispatcherContext *pDC, + typename T::FuncInfo *pFuncInfo, + ULONG CatchDepth, + EHRegistrationNode *pMarkerRN, + __ehstate_t curState + ); + +#elif defined _M_IX86 + + extern "C" void* __stdcall _CallSettingFrame( + void*, + EHRegistrationNode*, + unsigned long + ); + + void __stdcall _JumpToContinuation( + void*, + EHRegistrationNode* + ); + + // Translate an ebp-relative offset to a hard address based on address of + // registration node: + #define OffsetToAddress(off, RN) (void*)((char*)(RN) + FRAME_OFFSET + (off)) + + // Call RtlUnwind in a returning fashion + void __stdcall _UnwindNestedFrames( + EHRegistrationNode*, + EHExceptionRecord* + ); + + void* _CallCatchBlock2( + EHRegistrationNode*, + FuncInfo*, + void*, + int, + unsigned long + ); + + BOOL _CallSETranslator( + EHExceptionRecord*, + EHRegistrationNode*, + void*, + DispatcherContext*, + FuncInfo*, + int, + EHRegistrationNode* + ); + +#else + + #error Special transfer of control routines not defined for this platform + +#endif + +#if !defined(_M_CEE_PURE) + +__declspec(guard(ignore)) inline void __stdcall _CallMemberFunction0( + void* const pthis, + void* const pmfn + ) noexcept(false) +{ + auto const OneArgFn = reinterpret_cast(pmfn); + OneArgFn(pthis); +} + +__declspec(guard(ignore)) inline void __stdcall _CallMemberFunction1( + void* const pthis, + void* const pmfn, + void* const pthat + ) noexcept(false) +{ + auto const TwoArgFn = reinterpret_cast(pmfn); + TwoArgFn(pthis, pthat); +} + +__declspec(guard(ignore)) inline void __stdcall _CallMemberFunction2( + void* const pthis, + void* const pmfn, + void* const pthat, + int const val2 + ) noexcept(false) +{ + auto const ThreeArgFn = reinterpret_cast(pmfn); + ThreeArgFn(pthis, pthat, val2); +} + +#endif + +// The following functions are implemented in the common transfer-of-control +// implementation shared by the x64, arm, and arm64 EH implementations. + +extern "C" _VCRTIMP FRAMEINFO* __cdecl RENAME_EH_EXTERN(_CreateFrameInfo)( + FRAMEINFO* fi, + PVOID exception + ); + +extern "C" _VCRTIMP BOOL __cdecl _IsExceptionObjectToBeDestroyed( + PVOID exception + ); + +extern "C" _VCRTIMP void __cdecl RENAME_EH_EXTERN(_FindAndUnlinkFrame)( + FRAMEINFO* fi + ); + +typedef void (__stdcall* PFNPREPARE_FOR_THROW)(void* ExceptionInfo); + +typedef struct WinRTExceptionInfo +{ + void* description; + void* restrictedErrorString; + void* restrictedErrorReference; + void* capabilitySid; + long hr; + void* restrictedInfo; + ThrowInfo* throwInfo; + unsigned int size; + PFNPREPARE_FOR_THROW PrepareThrow; +} WINRTEXCEPTIONINFO; + +extern "C" _VCRTIMP void** __cdecl __current_exception(); +extern "C" _VCRTIMP void** __cdecl __current_exception_context(); +extern "C" _VCRTIMP int* __cdecl __processing_throw(); + +// NOTE: __uncaught_exceptions duplicates __ProcessingThrow. + +#ifndef _VCRT_DIRECT_PTD +#ifdef _VCRT_BUILD +#define _VCRT_DIRECT_PTD 1 +#else // ^^^ _VCRT_BUILD // !_VCRT_BUILD vvv +#define _VCRT_DIRECT_PTD 0 +#endif // _VCRT_BUILD +#endif // _VCRT_DIRECT_PTD + +#if _VCRT_DIRECT_PTD + + #define _pCurrentException (*reinterpret_cast(&RENAME_BASE_PTD(__vcrt_getptd)()->_curexception)) + #define _pCurrentExContext (*reinterpret_cast(&RENAME_BASE_PTD(__vcrt_getptd)()->_curcontext)) + #define __ProcessingThrow (RENAME_BASE_PTD(__vcrt_getptd)()->_ProcessingThrow) + +#else // ^^^ _VCRT_DIRECT_PTD ^^^ // vvv !_VCRT_DIRECT_PTD vvv // + + #define _pCurrentException (*reinterpret_cast(__current_exception())) + #define _pCurrentExContext (*reinterpret_cast(__current_exception_context())) + #define __ProcessingThrow (*__processing_throw()) + +#endif // !_VCRT_DIRECT_PTD + +#ifndef _VCRT_BUILD_FH4 +#ifdef _M_X64 +#define _VCRT_BUILD_FH4 1 +#else // ^^^ _M_X64 // !_M_X64 vvv +#define _VCRT_BUILD_FH4 0 +#endif // _M_X64 +#endif // _VCRT_BUILD_FH4 + +#if _VCRT_BUILD_FH4 +// In the satellite build, __vcrt_getptd uses satellite's PTD +// In the non-DLL build, __vcrt_getptd uses the main PTD which was updated to have this field +extern thread_local int VC_LTL_UCRT_CatchStateInParent; + +#define CatchStateInParent (VC_LTL_UCRT_CatchStateInParent) +#endif + +#pragma pack(pop) diff --git a/vcruntime.src/Shared/uncaught_exceptions.cpp b/vcruntime.src/Shared/uncaught_exceptions.cpp new file mode 100644 index 0000000..1c6be8a --- /dev/null +++ b/vcruntime.src/Shared/uncaught_exceptions.cpp @@ -0,0 +1,16 @@ + +#include "framework.h" +#include "vcruntime_internal.h" + +#if WindowsTargetPlatformMinVersion < __MakeVersion(10, 0, 14393) + +extern "C" int __cdecl __uncaught_exceptions() +{ + auto ptd = __vcrt_getptd_noinit(); + + return ptd ? ptd->_ProcessingThrow : 0; +} + +_LCRT_DEFINE_IAT_SYMBOL(__uncaught_exceptions); + +#endif diff --git a/vcruntime.src/Shared/vcruntime_internal.h b/vcruntime.src/Shared/vcruntime_internal.h new file mode 100644 index 0000000..4891f7b --- /dev/null +++ b/vcruntime.src/Shared/vcruntime_internal.h @@ -0,0 +1,439 @@ +// +// vcruntime_internal.h +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Declarations and definitions of things used internally by the VCRuntime. +// +#pragma once + +#if !defined _VCRT_BUILD && !defined _VCRT_ALLOW_INTERNALS + // This is an internal C Runtime header file. It is used when building the + // C Runtime only. It is not to be used as a public header file. + #error ERROR: Use of C Runtime library internal header file. +#endif + +#define _WIN32_FUSION 0x0100 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +_CRT_BEGIN_C_HEADER + + + +//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +// Optimization macros +// +//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// Note: These macros must match their definitions in the Windows build. +#ifndef BEGIN_PRAGMA_OPTIMIZE_DISABLE + #define BEGIN_PRAGMA_OPTIMIZE_DISABLE(flags, bug, reason) \ + __pragma(optimize(flags, off)) + + #define BEGIN_PRAGMA_OPTIMIZE_ENABLE(flags, bug, reason) \ + __pragma(optimize(flags, on)) + + #define END_PRAGMA_OPTIMIZE() \ + __pragma(optimize("", on)) +#endif + + + +//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +// Internal types +// +//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +typedef int (__cdecl* _PIFV)(void); + + + +//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +// Initialization +// +//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +bool __cdecl __vcrt_initialize_ptd(void); +bool __cdecl __vcrt_uninitialize_ptd(void); + +bool __cdecl __vcrt_initialize_locks(void); +bool __cdecl __vcrt_uninitialize_locks(void); + + + +//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +// ISA Availability +// +//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +extern int __isa_available; + +#if defined _M_IX86 || defined _M_X64 + extern int __isa_enabled; + extern int __favor; +#endif + + + +//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +// Guard +// +//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +#if !defined _M_CEE + typedef void (__fastcall *GUARDCF_CHECK_ROUTINE)(uintptr_t); + extern void* __guard_check_icall_fptr; + + #define _GUARD_CHECK_ICALL(FPTR) \ + (((GUARDCF_CHECK_ROUTINE)(__guard_check_icall_fptr))((uintptr_t)(FPTR))) +#else + #define _GUARD_CHECK_ICALL(FPTR) +#endif + +// This is defined in the Windows 10 SDK but not in the Windows 8.1 SDK. +#if !defined DECLSPEC_GUARD_SUPPRESS + #define DECLSPEC_GUARD_SUPPRESS __declspec(guard(suppress)) +#endif + + + +//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +// Multi-threading +// +//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +typedef enum __vcrt_lock_id +{ + __vcrt_undname_lock, + __vcrt_lock_count +} __vcrt_lock_id; + +#define _VCRT_SPINCOUNT 4000 + +void __cdecl __vcrt_lock(_In_ __vcrt_lock_id _Lock); +void __cdecl __vcrt_unlock(_In_ __vcrt_lock_id _Lock); + +//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +// Telemetry +// +//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +#if !defined _CRT_WINDOWS + + // Telemetry: Invoked when the exe/dll are invoked. There are two different + // implementations in telemetry.cpp and telemetrydefault.cpp. Because GetModuleFileName + // is not available for Store apps, we return an empty string in telemetrydefault.cpp + // when invoked by store apps. For the desktop in telemetry.cpp, it returns the name + // of the module which invokes main/dll. This method is also responsible for firing the + // events associated with Tracelogging. This will help with runtime telemetry for analysis. + void __cdecl __telemetry_main_invoke_trigger(const HINSTANCE instance); + + // Telemetry: Invoked when the exe/dll are shutdown. There are two different + // implementations in telemetry.cpp and telemetrydefault.cpp. This method is + // responsible for firing the events associated with Tracelogging. This will + // help with runtime telemetry for analysis. + void __cdecl __telemetry_main_return_trigger(const HINSTANCE instance); + + void __cdecl __vcrt_initialize_telemetry_provider(void); + + void __cdecl __vcrt_uninitialize_telemetry_provider(void); + +#endif // !defined _CRT_WINDOWS + +//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +// CoreCRT SEH Encapsulation +// +//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +#ifdef __cplusplus +extern "C++" +{ + template + auto __vcrt_lock_and_call(__vcrt_lock_id const lock_id, Action&& action) + -> decltype(action()) + { + return __crt_seh_guarded_call()( + [lock_id]() { __vcrt_lock(lock_id); }, + action, + [lock_id]() { __vcrt_unlock(lock_id); }); + } +} +#endif // __cplusplus + +// When building the satellite, define __vcrt_ptd to be the satellite-specific implementation, rename the base implementation to __vcrt_ptd_base +#if defined _VCRT_SAT_1 +#define RENAME_BASE_PTD(x) x##base +#else +#define RENAME_BASE_PTD(x) x +#endif + +//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +// Per-thread data +// +//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// WARNING WARNING WARNING +// This entire structure is inferred by the satellite DLL from the address of _curexception and +// __ProcessingThrow. Any changes to this structure must continue to allow this to happen +// WARNING WARNING WARNING +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* _translator; // S.E. translator + void* _purecall; // called when pure virtual happens + void* _curexception; // current exception + void* _curcontext; // current exception context + int _ProcessingThrow; // for uncaught_exception + void* _curexcspec; // for handling exceptions thrown from std::unexpected + int _cxxReThrow; // true if it's a rethrown C++ exception + + #if defined _M_X64 || defined _M_ARM || defined _M_ARM64 || defined _M_HYBRID + void* _pExitContext; + void* _pUnwindContext; + void* _pFrameInfoChain; + uintptr_t _ImageBase; + uintptr_t _ThrowImageBase; + void* _pForeignException; + + //2015 没有这个 + //int _CatchStateInParent; // Used to link together the catch funclet with the parent. During dispatch contains state associated + // with catch in the parent. During unwind represents the current unwind state that is resumed to + // during collided unwind and used to look for handlers of the throwing dtor. + #elif defined _M_IX86 + void* _pFrameInfoChain; + #endif + +} RENAME_BASE_PTD(__vcrt_ptd); + +// Represents uninitialized value of _CatchStateInParent +#define INVALID_CATCH_SPECIFIC_STATE -2 + +// Utilize windows scope index to resolve collided unwind, since the uninitialized value is 0 we subtract the value by 2 +// so that a scope index value of 1 maps to a EH state of -1 etc. +#define SCOPE_INDEX_SHIFT_VALUE 2 + +#if defined _VCRT_SAT_1 +typedef struct __vcrt_ptd +{ + int _CatchStateInParent; // Used to link together the catch funclet with the parent. During dispatch contains state associated + // with catch in the parent. During unwind represents the current unwind state that is resumed to + // during collided unwind and used to look for handlers of the throwing dtor. +} __vcrt_ptd; + +RENAME_BASE_PTD(__vcrt_ptd)* __cdecl RENAME_BASE_PTD(__vcrt_getptd)(void); +RENAME_BASE_PTD(__vcrt_ptd)* __cdecl RENAME_BASE_PTD(__vcrt_getptd_noinit)(void); +#endif + +extern "C" _VCRTIMP void** __cdecl __current_exception(); +// These functions are defined differently for satellite DLL compilation to get the PTD +// from the base vcruntime DLL. +__forceinline __vcrt_ptd* __cdecl __vcrt_getptd(void) +{ + //由于 __current_exception 内部可以确保 ptd 必然存在 + + auto ptd = (__vcrt_ptd*)(((char*)__current_exception()) - FIELD_OFFSET(__vcrt_ptd, _curexception)); + + return ptd; +} + +//__vcrt_ptd* __cdecl __vcrt_getptd_noexit(void); +#define __vcrt_getptd_noexit __vcrt_getptd +//__vcrt_ptd* __cdecl __vcrt_getptd_noinit(void); +#define __vcrt_getptd_noinit __vcrt_getptd + +void __cdecl __vcrt_freeptd(_Inout_opt_ __vcrt_ptd* _Ptd); +void WINAPI __vcrt_freefls(_Inout_opt_ void* _Pfd); + +//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +// Windows API wrappers +// +//-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +#if defined _VCRT_ENCLAVE_BUILD + + // When building for Enclave, we directly call the most suitable corresponding API. + __inline DWORD __vcrt_FlsAlloc(PFLS_CALLBACK_FUNCTION const callback) + { + UNREFERENCED_PARAMETER(callback); + return TlsAlloc(); + } + + __inline BOOL __vcrt_FlsFree(DWORD const fls_index) + { + return TlsFree(fls_index); + } + + __inline PVOID __vcrt_FlsGetValue(DWORD const fls_index) + { + return TlsGetValue(fls_index); + } + + __inline BOOL __vcrt_FlsSetValue(DWORD const fls_index, PVOID const fls_data) + { + + return TlsSetValue(fls_index, fls_data); + } + + __inline BOOL __vcrt_InitializeCriticalSectionEx( + LPCRITICAL_SECTION const critical_section, + DWORD const spin_count, + DWORD const flags + ) + { + return InitializeCriticalSectionEx(critical_section, spin_count, flags); + } + + __inline PVOID __vcrt_EncodePointer(PVOID const ptr) + { + return ptr; + } + +#elif !defined _VCRT_WINDOWS_BUILD && (defined _ONECORE || _VCRT_WIN32_WINNT >= _WIN32_WINNT_VISTA) // ^^^ Enclave ^^^ // vvv Uplevel vvv // + + + // When building for OneCore, we can directly call these APIs. + __inline DWORD __vcrt_FlsAlloc(PFLS_CALLBACK_FUNCTION const callback) + { + return FlsAlloc(callback); + } + + __inline BOOL __vcrt_FlsFree(DWORD const fls_index) + { + return FlsFree(fls_index); + } + + __inline PVOID __vcrt_FlsGetValue(DWORD const fls_index) + { + return FlsGetValue(fls_index); + } + + __inline BOOL __vcrt_FlsSetValue(DWORD const fls_index, PVOID const fls_data) + { + + return FlsSetValue(fls_index, fls_data); + } + + __inline BOOL __vcrt_InitializeCriticalSectionEx( + LPCRITICAL_SECTION const critical_section, + DWORD const spin_count, + DWORD const flags + ) + { + return InitializeCriticalSectionEx(critical_section, spin_count, flags); + } + + __inline PVOID __vcrt_EncodePointer(PVOID const ptr) + { + return EncodePointer(ptr); + } + +#else // ^^^ Uplevel ^^^ // vvv Downlevel vvv // + + DWORD __cdecl __vcrt_FlsAlloc( + _In_opt_ PFLS_CALLBACK_FUNCTION callback + ); + + BOOL __cdecl __vcrt_FlsFree( + _In_ DWORD fls_index + ); + + PVOID __cdecl __vcrt_FlsGetValue( + _In_ DWORD fls_index + ); + + BOOL __cdecl __vcrt_FlsSetValue( + _In_ DWORD fls_index, + _In_opt_ PVOID fls_data + ); + + BOOL __cdecl __vcrt_InitializeCriticalSectionEx( + _Out_ LPCRITICAL_SECTION critical_section, + _In_ DWORD spin_count, + _In_ DWORD flags + ); + + __inline PVOID __vcrt_EncodePointer(PVOID const ptr) + { + return EncodePointer(ptr); + } + +#endif // Downlevel + +// These APIs are available on all supported operating systems, but they are not +// defined in WindowsApp.lib. We rely on these APIs in the statically-linked +// RTC code, which we build into the CRT for Windows Store apps. To avoid link +// errors in user code, we encapsulate their usage within the VCRuntime DLL. +// When we are MSDK-constrained, these functions simply return failure. +#ifdef _CRT_WINDOWS + // Windows OS components do not need this layer of indirection. To avoid + // dependencies on these exports, we redefine them to map to the real Windows + // APIs. + #define __vcrt_GetModuleFileNameW GetModuleFileNameW + #define __vcrt_GetModuleHandleW GetModuleHandleW + #define __vcrt_LoadLibraryExW LoadLibraryExW +#else // ^^^ _CRT_WINDOWS ^^^ // vvv Public Runtimes vvv // + _Success_(return != 0) _Ret_range_(1, buffer_count) + DWORD __cdecl __vcrt_GetModuleFileNameW( + _In_opt_ HMODULE module_handle, + _Out_writes_to_(buffer_count, ((return < buffer_count) ? (return + 1) : buffer_count)) LPWSTR buffer, + _In_ DWORD buffer_count + ); + + _When_(file_name == NULL, _Ret_notnull_) + _When_(file_name != NULL, _Ret_maybenull_) + HMODULE __cdecl __vcrt_GetModuleHandleW( + _In_opt_ LPCWSTR file_name + ); + + _Ret_maybenull_ + HMODULE __cdecl __vcrt_LoadLibraryExW( + _In_ LPCWSTR file_name, + _Reserved_ HANDLE file_handle, + _In_ DWORD flags + ); +#endif // ^^^ Public Runtimes ^^^ // + + +BOOL __cdecl _ValidateImageBase(PBYTE pImageBase); +PIMAGE_SECTION_HEADER __cdecl _FindPESection(PBYTE pImageBase, DWORD_PTR rva); +BOOL __cdecl _IsNonwritableInCurrentImage(void const* pTarget); + + + +// Type info stuff +#ifdef __cplusplus + struct __type_info_node + { + _SLIST_HEADER _Header; + }; + + void __cdecl __std_type_info_destroy_list(__type_info_node* _RootNode); +#endif + + +// Imports from AppCRT and DesktopCRT that need to be forwarded to the OS-mode global state counterparts when this dll is built as vcruntime_win +#if defined _VCRT_WINDOWS_BUILD && defined _CRT_GLOBAL_STATE_ISOLATION + _ACRTIMP int __cdecl _o__callnewh( + _In_ size_t _Size + ); + + #define _callnewh _o__callnewh +#endif + +// x86 SSE2 exception filter to fix imprecise exception codes +long __CRTDECL _filter_x86_sse2_floating_point_exception(long); + +_CRT_END_C_HEADER diff --git a/vcruntime.src/Shared/winapi_downlevel.cpp b/vcruntime.src/Shared/winapi_downlevel.cpp new file mode 100644 index 0000000..05b8634 --- /dev/null +++ b/vcruntime.src/Shared/winapi_downlevel.cpp @@ -0,0 +1,16 @@ +#include "framework.h" + +#include + + extern "C" BOOL __cdecl __vcrt_InitializeCriticalSectionEx( + LPCRITICAL_SECTION const critical_section, + DWORD const spin_count, + DWORD const flags + ) +{ + //考虑到XP支持,直接使用它 + return InitializeCriticalSectionAndSpinCount(critical_section, spin_count); +} + + + _LCRT_DEFINE_IAT_SYMBOL(__vcrt_InitializeCriticalSectionEx); diff --git a/vcruntime.src/Shared/winapi_thunks.cpp b/vcruntime.src/Shared/winapi_thunks.cpp new file mode 100644 index 0000000..c0b105d --- /dev/null +++ b/vcruntime.src/Shared/winapi_thunks.cpp @@ -0,0 +1,88 @@ +// +// winapi_thunks.cpp +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// Definitions of wrappers for Windows API functions that cannot be called +// by the statically-linked CRT code because they are not part of the MSDK. +// +//#include + +#include "framework.h" + +#include + +#if defined _CRT_APP && !defined _DEBUG + #define USE_ONLY_MSDK_APIS +#endif + +extern "C" DWORD __cdecl __vcrt_GetModuleFileNameW( + HMODULE const module_handle, + LPWSTR const buffer, + DWORD const buffer_count + ) +{ + #ifdef USE_ONLY_MSDK_APIS + + UNREFERENCED_PARAMETER(module_handle); + UNREFERENCED_PARAMETER(buffer); + UNREFERENCED_PARAMETER(buffer_count); + + SetLastError(ERROR_NOT_SUPPORTED); + return 0; + + #else // ^^^ MSDK ^^^ // vvv !MSDK vvv // + + return GetModuleFileNameW(module_handle, buffer, buffer_count); + + #endif // !MSDK +} + +_LCRT_DEFINE_IAT_SYMBOL(__vcrt_GetModuleFileNameW); + + +extern "C" HMODULE __cdecl __vcrt_GetModuleHandleW( + LPCWSTR const file_name + ) +{ + #ifdef USE_ONLY_MSDK_APIS + + UNREFERENCED_PARAMETER(file_name); + + SetLastError(ERROR_NOT_SUPPORTED); + return nullptr; + + #else // ^^^ MSDK ^^^ // vvv !MSDK vvv // + + return GetModuleHandleW(file_name); + + #endif // !MSDK +} + +_LCRT_DEFINE_IAT_SYMBOL(__vcrt_GetModuleHandleW); + + +extern "C" HMODULE __cdecl __vcrt_LoadLibraryExW( + LPCWSTR const file_name, + HANDLE const file_handle, + DWORD const flags + ) +{ + #ifdef USE_ONLY_MSDK_APIS + + UNREFERENCED_PARAMETER(file_name); + UNREFERENCED_PARAMETER(file_handle); + UNREFERENCED_PARAMETER(flags); + + SetLastError(ERROR_NOT_SUPPORTED); + return nullptr; + + #else // ^^^ MSDK ^^^ // vvv !MSDK vvv // + + return LoadLibraryExW(file_name, file_handle, flags); + + #endif // !MSDK +} + +_LCRT_DEFINE_IAT_SYMBOL(__vcrt_LoadLibraryExW); + diff --git a/vcruntime.src/ucrt.vcruntime/ucrt.vcruntime.vcxproj b/vcruntime.src/ucrt.vcruntime/ucrt.vcruntime.vcxproj new file mode 100644 index 0000000..39818ee --- /dev/null +++ b/vcruntime.src/ucrt.vcruntime/ucrt.vcruntime.vcxproj @@ -0,0 +1,430 @@ + + + + + Dynamic + ARM + + + Dynamic + ARM64 + + + Dynamic + Win32 + + + Dynamic + x64 + + + Static + ARM + + + Static + ARM64 + + + Static + Win32 + + + Static + x64 + + + + 16.0 + Win32Proj + {fec996ed-01e9-4258-862f-58bf3aefa893} + ucrt.vcruntime + $([Microsoft.Build.Utilities.ToolLocationHelper]::GetLatestSDKTargetPlatformVersion('Windows', '10.0')) + $(Platform) + x86 + v$(TargetVCRuntimeVersion.Substring(0,4).Remove(2,1)) + + 10.0.10240.0 + ucrt.vcruntime + $([System.Version]::Parse('$(WindowsTargetPlatformMinVersion)').Build) + + + + StaticLibrary + false + false + Unicode + $(DefaultPlatformToolset) + + + StaticLibrary + false + false + Unicode + $(DefaultPlatformToolset) + + + StaticLibrary + false + false + Unicode + $(DefaultPlatformToolset) + + + StaticLibrary + false + false + Unicode + $(DefaultPlatformToolset) + + + StaticLibrary + false + false + Unicode + $(DefaultPlatformToolset) + + + StaticLibrary + false + false + Unicode + $(DefaultPlatformToolset) + + + StaticLibrary + false + false + Unicode + $(DefaultPlatformToolset) + + + StaticLibrary + false + false + Unicode + $(DefaultPlatformToolset) + + + + $(VCToolsVersion) + + + + + + + + + + + + + + + + + + false + libvcruntime.objs + $(SolutionDir)ucrt\$(WindowsTargetPlatformMinVersion)\lib\$(Platform)\ + $(Platform)\$(Configuration)\$(WindowsTargetPlatformMinVersion)\ + $(ProjectDir)..\Shared;$(IncludePath) + + + false + libvcruntime.objs + $(SolutionDir)ucrt\$(WindowsTargetPlatformMinVersion)\lib\$(Platform)\ + $(ProjectDir)..\Shared;$(IncludePath) + $(Platform)\$(Configuration)\$(WindowsTargetPlatformMinVersion)\ + + + false + vcruntime.objs + $(SolutionDir)ucrt\$(WindowsTargetPlatformMinVersion)\lib\$(Platform)\ + $(Platform)\$(Configuration)\$(WindowsTargetPlatformMinVersion)\ + $(ProjectDir)..\Shared;$(IncludePath) + + + false + vcruntime.objs + $(SolutionDir)ucrt\$(WindowsTargetPlatformMinVersion)\lib\$(Platform)\ + $(ProjectDir)..\Shared;$(IncludePath) + $(Platform)\$(Configuration)\$(WindowsTargetPlatformMinVersion)\ + + + false + $(SolutionDir)ucrt\$(WindowsTargetPlatformMinVersion)\lib\$(Platform)\ + libvcruntime.objs + $(Platform)\$(Configuration)\$(WindowsTargetPlatformMinVersion)\ + $(ProjectDir)..\Shared;$(IncludePath) + + + false + $(SolutionDir)ucrt\$(WindowsTargetPlatformMinVersion)\lib\$(Platform)\ + libvcruntime.objs + $(Platform)\$(Configuration)\$(WindowsTargetPlatformMinVersion)\ + $(ProjectDir)..\Shared;$(IncludePath) + + + false + $(SolutionDir)ucrt\$(WindowsTargetPlatformMinVersion)\lib\$(Platform)\ + vcruntime.objs + $(Platform)\$(Configuration)\$(WindowsTargetPlatformMinVersion)\ + $(ProjectDir)..\Shared;$(IncludePath) + + + false + $(SolutionDir)ucrt\$(WindowsTargetPlatformMinVersion)\lib\$(Platform)\ + vcruntime.objs + $(Platform)\$(Configuration)\$(WindowsTargetPlatformMinVersion)\ + $(ProjectDir)..\Shared;$(IncludePath) + + + + Level3 + true + true + TargetVCRuntimeVersion=(($([System.Version]::Parse('$(TargetVCRuntimeVersion)').Major.ToString('00')) << 12) + ($([System.Version]::Parse('$(TargetVCRuntimeVersion)').Minor.ToString('00')) << 8) + $([System.Version]::Parse('$(TargetVCRuntimeVersion)').Build));WindowsTargetPlatformMinVersion=(($([System.Version]::Parse('$(WindowsTargetPlatformMinVersion)').Major.ToString('00')) << 12) + ($([System.Version]::Parse('$(WindowsTargetPlatformMinVersion)').Minor.ToString('00')) << 8) + $([System.Version]::Parse('$(WindowsTargetPlatformMinVersion)').Build));_VCRT_ALLOW_INTERNALS;_ALLOW_ITERATOR_DEBUG_LEVEL_MISMATCH;_ALLOW_RUNTIME_LIBRARY_MISMATCH;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions);%(PreprocessorDefinitions);%(PreprocessorDefinitions);%(PreprocessorDefinitions);%(PreprocessorDefinitions) + true + NotUsing + pch.h + false + true + MultiThreaded + NoExtensions + + + + + true + true + true + + + + + Level3 + true + true + TargetVCRuntimeVersion=(($([System.Version]::Parse('$(TargetVCRuntimeVersion)').Major.ToString('00')) << 12) + ($([System.Version]::Parse('$(TargetVCRuntimeVersion)').Minor.ToString('00')) << 8) + $([System.Version]::Parse('$(TargetVCRuntimeVersion)').Build));WindowsTargetPlatformMinVersion=(($([System.Version]::Parse('$(WindowsTargetPlatformMinVersion)').Major.ToString('00')) << 12) + ($([System.Version]::Parse('$(WindowsTargetPlatformMinVersion)').Minor.ToString('00')) << 8) + $([System.Version]::Parse('$(WindowsTargetPlatformMinVersion)').Build));_VCRT_ALLOW_INTERNALS;_ALLOW_ITERATOR_DEBUG_LEVEL_MISMATCH;_ALLOW_RUNTIME_LIBRARY_MISMATCH;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions);%(PreprocessorDefinitions);%(PreprocessorDefinitions);%(PreprocessorDefinitions);%(PreprocessorDefinitions);%(PreprocessorDefinitions) + true + NotUsing + pch.h + false + true + MultiThreaded + + + + + true + true + true + + + + + Level3 + true + true + TargetVCRuntimeVersion=(($([System.Version]::Parse('$(TargetVCRuntimeVersion)').Major.ToString('00')) << 12) + ($([System.Version]::Parse('$(TargetVCRuntimeVersion)').Minor.ToString('00')) << 8) + $([System.Version]::Parse('$(TargetVCRuntimeVersion)').Build));WindowsTargetPlatformMinVersion=(($([System.Version]::Parse('$(WindowsTargetPlatformMinVersion)').Major.ToString('00')) << 12) + ($([System.Version]::Parse('$(WindowsTargetPlatformMinVersion)').Minor.ToString('00')) << 8) + $([System.Version]::Parse('$(WindowsTargetPlatformMinVersion)').Build));_VCRT_ALLOW_INTERNALS;_ALLOW_ITERATOR_DEBUG_LEVEL_MISMATCH;_ALLOW_RUNTIME_LIBRARY_MISMATCH;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions);%(PreprocessorDefinitions);%(PreprocessorDefinitions);%(PreprocessorDefinitions);%(PreprocessorDefinitions) + true + NotUsing + pch.h + false + true + OldStyle + NoExtensions + + + + + true + true + true + + + + + Level3 + true + true + TargetVCRuntimeVersion=(($([System.Version]::Parse('$(TargetVCRuntimeVersion)').Major.ToString('00')) << 12) + ($([System.Version]::Parse('$(TargetVCRuntimeVersion)').Minor.ToString('00')) << 8) + $([System.Version]::Parse('$(TargetVCRuntimeVersion)').Build));WindowsTargetPlatformMinVersion=(($([System.Version]::Parse('$(WindowsTargetPlatformMinVersion)').Major.ToString('00')) << 12) + ($([System.Version]::Parse('$(WindowsTargetPlatformMinVersion)').Minor.ToString('00')) << 8) + $([System.Version]::Parse('$(WindowsTargetPlatformMinVersion)').Build));_VCRT_ALLOW_INTERNALS;_ALLOW_ITERATOR_DEBUG_LEVEL_MISMATCH;_ALLOW_RUNTIME_LIBRARY_MISMATCH;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions);%(PreprocessorDefinitions);%(PreprocessorDefinitions);%(PreprocessorDefinitions);%(PreprocessorDefinitions);%(PreprocessorDefinitions) + true + NotUsing + pch.h + false + true + OldStyle + + + + + true + true + true + + + + + Level3 + true + true + TargetVCRuntimeVersion=(($([System.Version]::Parse('$(TargetVCRuntimeVersion)').Major.ToString('00')) << 12) + ($([System.Version]::Parse('$(TargetVCRuntimeVersion)').Minor.ToString('00')) << 8) + $([System.Version]::Parse('$(TargetVCRuntimeVersion)').Build));WindowsTargetPlatformMinVersion=(($([System.Version]::Parse('$(WindowsTargetPlatformMinVersion)').Major.ToString('00')) << 12) + ($([System.Version]::Parse('$(WindowsTargetPlatformMinVersion)').Minor.ToString('00')) << 8) + $([System.Version]::Parse('$(WindowsTargetPlatformMinVersion)').Build));_VCRT_ALLOW_INTERNALS;_ALLOW_ITERATOR_DEBUG_LEVEL_MISMATCH;_ALLOW_RUNTIME_LIBRARY_MISMATCH;NDEBUG;_LIB;%(PreprocessorDefinitions);%(PreprocessorDefinitions);%(PreprocessorDefinitions);%(PreprocessorDefinitions);%(PreprocessorDefinitions);%(PreprocessorDefinitions) + true + NotUsing + pch.h + false + true + MultiThreaded + + + + + true + true + true + + + + + Level3 + true + true + TargetVCRuntimeVersion=(($([System.Version]::Parse('$(TargetVCRuntimeVersion)').Major.ToString('00')) << 12) + ($([System.Version]::Parse('$(TargetVCRuntimeVersion)').Minor.ToString('00')) << 8) + $([System.Version]::Parse('$(TargetVCRuntimeVersion)').Build));WindowsTargetPlatformMinVersion=(($([System.Version]::Parse('$(WindowsTargetPlatformMinVersion)').Major.ToString('00')) << 12) + ($([System.Version]::Parse('$(WindowsTargetPlatformMinVersion)').Minor.ToString('00')) << 8) + $([System.Version]::Parse('$(WindowsTargetPlatformMinVersion)').Build));_VCRT_ALLOW_INTERNALS;_ALLOW_ITERATOR_DEBUG_LEVEL_MISMATCH;_ALLOW_RUNTIME_LIBRARY_MISMATCH;NDEBUG;_LIB;%(PreprocessorDefinitions);%(PreprocessorDefinitions);%(PreprocessorDefinitions);%(PreprocessorDefinitions);%(PreprocessorDefinitions);%(PreprocessorDefinitions) + true + NotUsing + pch.h + false + true + MultiThreaded + + + + + true + true + true + + + + + Level3 + true + true + TargetVCRuntimeVersion=(($([System.Version]::Parse('$(TargetVCRuntimeVersion)').Major.ToString('00')) << 12) + ($([System.Version]::Parse('$(TargetVCRuntimeVersion)').Minor.ToString('00')) << 8) + $([System.Version]::Parse('$(TargetVCRuntimeVersion)').Build));WindowsTargetPlatformMinVersion=(($([System.Version]::Parse('$(WindowsTargetPlatformMinVersion)').Major.ToString('00')) << 12) + ($([System.Version]::Parse('$(WindowsTargetPlatformMinVersion)').Minor.ToString('00')) << 8) + $([System.Version]::Parse('$(WindowsTargetPlatformMinVersion)').Build));_VCRT_ALLOW_INTERNALS;_ALLOW_ITERATOR_DEBUG_LEVEL_MISMATCH;_ALLOW_RUNTIME_LIBRARY_MISMATCH;NDEBUG;_LIB;%(PreprocessorDefinitions);%(PreprocessorDefinitions);%(PreprocessorDefinitions);%(PreprocessorDefinitions);%(PreprocessorDefinitions);%(PreprocessorDefinitions) + true + NotUsing + pch.h + false + true + OldStyle + + + + + true + true + true + + + + + Level3 + true + true + TargetVCRuntimeVersion=(($([System.Version]::Parse('$(TargetVCRuntimeVersion)').Major.ToString('00')) << 12) + ($([System.Version]::Parse('$(TargetVCRuntimeVersion)').Minor.ToString('00')) << 8) + $([System.Version]::Parse('$(TargetVCRuntimeVersion)').Build));WindowsTargetPlatformMinVersion=(($([System.Version]::Parse('$(WindowsTargetPlatformMinVersion)').Major.ToString('00')) << 12) + ($([System.Version]::Parse('$(WindowsTargetPlatformMinVersion)').Minor.ToString('00')) << 8) + $([System.Version]::Parse('$(WindowsTargetPlatformMinVersion)').Build));_VCRT_ALLOW_INTERNALS;_ALLOW_ITERATOR_DEBUG_LEVEL_MISMATCH;_ALLOW_RUNTIME_LIBRARY_MISMATCH;NDEBUG;_LIB;%(PreprocessorDefinitions);%(PreprocessorDefinitions);%(PreprocessorDefinitions);%(PreprocessorDefinitions);%(PreprocessorDefinitions);%(PreprocessorDefinitions) + true + NotUsing + pch.h + false + true + OldStyle + + + + + true + true + true + + + + + + + + true + + + true + true + + + stdcpp17 + true + + + stdcpp17 + true + + + stdcpp17 + true + + + true + + + stdcpp17 + true + + + + true + + + + + + + + + + + + + + + true + true + true + + + + + + + $(SolutionDir)bin\$(TargetVCRuntimeVersion)\$(Platform)\vcruntime.lib + $(IntDir)vcruntime_no_ec.lib + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vcruntime.src/ucrt.vcruntime/ucrt.vcruntime.vcxproj.filters b/vcruntime.src/ucrt.vcruntime/ucrt.vcruntime.vcxproj.filters new file mode 100644 index 0000000..d1781bd --- /dev/null +++ b/vcruntime.src/ucrt.vcruntime/ucrt.vcruntime.vcxproj.filters @@ -0,0 +1,63 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {d51362f9-6761-4c0c-9b19-2ac364b62a92} + + + {32758ddc-e38a-4fb6-9210-c19748a53663} + + + + + 头文件 + + + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件 + + + 源文件\Static + + + 源文件 + + + 源文件 + + + 源文件\internal + + + 源文件 + + + 源文件 + + + \ No newline at end of file