mirror of
https://github.com/Chuyu-Team/VC-LTL5.git
synced 2026-10-29 04:17:42 +08:00
773 lines
29 KiB
C++
773 lines
29 KiB
C++
//
|
|
// internal_shared.h
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
// Header-only utilities used by both the VCRuntime and the CoreCRT.
|
|
//
|
|
#pragma once
|
|
|
|
#include <LTL_Tools.h>
|
|
#include <crtdbg.h>
|
|
#include <intrin.h>
|
|
#include <malloc.h>
|
|
#include <stdlib.h>
|
|
#include <vcruntime.h>
|
|
#include <Windows.h>
|
|
|
|
_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 <typename Result>
|
|
struct __crt_seh_guarded_call
|
|
{
|
|
template <typename Setup, typename Action, typename Cleanup>
|
|
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<void>
|
|
{
|
|
template <typename Setup, typename Action, typename Cleanup>
|
|
void operator()(Setup&& setup, Action&& action, Cleanup&& cleanup)
|
|
{
|
|
setup();
|
|
__try
|
|
{
|
|
action();
|
|
}
|
|
__finally
|
|
{
|
|
cleanup();
|
|
}
|
|
}
|
|
};
|
|
|
|
template <typename Action, typename Cleanup>
|
|
auto __crt_call_and_cleanup(Action&& action, Cleanup&& cleanup)
|
|
-> decltype(action())
|
|
{
|
|
return __crt_seh_guarded_call<decltype(action())>()([](){}, 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 <typename T>
|
|
void operator()(T const* const p) const noexcept
|
|
{
|
|
_free_crt(const_cast<T*>(p));
|
|
}
|
|
};
|
|
|
|
struct __crt_public_free_policy
|
|
{
|
|
template <typename T>
|
|
void operator()(T const* const p) const noexcept
|
|
{
|
|
free(const_cast<T*>(p));
|
|
}
|
|
};
|
|
|
|
template <typename T, typename Free = __crt_internal_free_policy>
|
|
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 <typename T>
|
|
struct __crt_scoped_stack_ptr_tag
|
|
{
|
|
__crt_scoped_stack_ptr_tag(T* const p) noexcept
|
|
: _p(p)
|
|
{
|
|
}
|
|
|
|
T* _p;
|
|
};
|
|
|
|
template <typename T>
|
|
class __crt_scoped_stack_ptr
|
|
{
|
|
public:
|
|
|
|
explicit __crt_scoped_stack_ptr(__crt_scoped_stack_ptr_tag<T> 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 <t>(static_cast<t*>(_calloc_crt ( (n), sizeof(t)))))
|
|
#define _malloc_crt_t(t, n) (__crt_unique_heap_ptr <t>(static_cast<t*>(_malloc_crt ( (n) * sizeof(t)))))
|
|
#define _recalloc_crt_t(t, p, n) (__crt_unique_heap_ptr <t>(static_cast<t*>(_recalloc_crt((p), (n), sizeof(t)))))
|
|
#define _malloca_crt_t(t, n) (__crt_scoped_stack_ptr_tag<t>(static_cast<t*>(_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 <typename T>
|
|
T __crt_fast_decode_pointer(T const p) noexcept
|
|
{
|
|
return reinterpret_cast<T>(
|
|
__crt_rotate_pointer_value(
|
|
reinterpret_cast<uintptr_t>(p) ^ __security_cookie,
|
|
__security_cookie % __crt_maximum_pointer_shift
|
|
)
|
|
);
|
|
}
|
|
|
|
template <typename T>
|
|
T __crt_fast_encode_pointer(T const p) noexcept
|
|
{
|
|
return reinterpret_cast<T>(
|
|
__crt_rotate_pointer_value(
|
|
reinterpret_cast<uintptr_t>(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 <typename T>
|
|
operator T*() const noexcept
|
|
{
|
|
return __crt_fast_encode_pointer(static_cast<T*>(nullptr));
|
|
}
|
|
};
|
|
|
|
inline __crt_fast_encoded_nullptr_t __crt_fast_encode_pointer(decltype(nullptr)) noexcept
|
|
{
|
|
return __crt_fast_encoded_nullptr_t();
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
T __crt_get_proc_address(HMODULE const m, char const* const f) noexcept
|
|
{
|
|
return reinterpret_cast<T>(::GetProcAddress(m, f));
|
|
}
|
|
|
|
template <typename T, typename V>
|
|
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<T*>(_InterlockedExchangePointer((void**)target, (void*)value));
|
|
}
|
|
|
|
template <typename T, typename E, typename C>
|
|
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<T>(_InterlockedCompareExchange(
|
|
reinterpret_cast<LONG*>(target), (LONG)exchange, (LONG)comparand));
|
|
}
|
|
|
|
template <typename T, typename E, typename C>
|
|
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<T*>(_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<int const volatile*>(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 <typename T>
|
|
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 <typename T>
|
|
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
|