// // 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 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. 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