Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-15 08:43:39

0001 /* Proposed SG14 status_code
0002 (C) 2018-2024 Niall Douglas <http://www.nedproductions.biz/> (5 commits)
0003 File Created: Feb 2018
0004 
0005 
0006 Boost Software License - Version 1.0 - August 17th, 2003
0007 
0008 Permission is hereby granted, free of charge, to any person or organization
0009 obtaining a copy of the software and accompanying documentation covered by
0010 this license (the "Software") to use, reproduce, display, distribute,
0011 execute, and transmit the Software, and to prepare derivative works of the
0012 Software, and to permit third-parties to whom the Software is furnished to
0013 do so, all subject to the following:
0014 
0015 The copyright notices in the Software and this entire statement, including
0016 the above license grant, this restriction and the following disclaimer,
0017 must be included in all copies of the Software, in whole or in part, and
0018 all derivative works of the Software, unless such copies or derivative
0019 works are solely in the form of machine-executable object code generated by
0020 a source language processor.
0021 
0022 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0023 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0024 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
0025 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
0026 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
0027 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
0028 DEALINGS IN THE SOFTWARE.
0029 */
0030 
0031 #ifndef BOOST_OUTCOME_SYSTEM_ERROR2_NT_CODE_HPP
0032 #define BOOST_OUTCOME_SYSTEM_ERROR2_NT_CODE_HPP
0033 
0034 #if !defined(_WIN32) && !defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
0035 #error This file should only be included on Windows
0036 #endif
0037 
0038 #include "win32_code.hpp"
0039 
0040 #if defined(_MSC_VER) && !defined(__clang__)
0041 #pragma warning(push)
0042 #pragma warning(disable : 6326)  // constant comparison
0043 #endif
0044 
0045 BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_BEGIN
0046 
0047 //! \exclude
0048 namespace win32
0049 {
0050 #ifdef __MINGW32__
0051   extern "C"
0052   {
0053 #endif
0054     // A Win32 NTSTATUS
0055     using NTSTATUS = long;
0056     // A Win32 HMODULE
0057     using HMODULE = void *;
0058     // Used to retrieve where the NTDLL DLL is mapped into memory
0059     extern HMODULE __stdcall GetModuleHandleW(const wchar_t *lpModuleName);
0060 #ifdef __MINGW32__
0061   }
0062 #else
0063 #pragma comment(lib, "kernel32.lib")
0064 #if(defined(__x86_64__) || defined(_M_X64)) || (defined(__aarch64__) || defined(_M_ARM64))
0065 #pragma comment(linker, "/alternatename:?GetModuleHandleW@win32@system_error2@@YAPEAXPEB_W@Z=GetModuleHandleW")
0066 #elif defined(__x86__) || defined(_M_IX86) || defined(__i386__)
0067 #pragma comment(linker, "/alternatename:?GetModuleHandleW@win32@system_error2@@YGPAXPB_W@Z=_GetModuleHandleW@4")
0068 #elif defined(__arm__) || defined(_M_ARM)
0069 #pragma comment(linker, "/alternatename:?GetModuleHandleW@win32@system_error2@@YAPAXPB_W@Z=GetModuleHandleW")
0070 #else
0071 #error Unknown architecture
0072 #endif
0073 #endif
0074 }  // namespace win32
0075 
0076 class _nt_code_domain;
0077 //! (Windows only) A NT error code, those returned by NT kernel functions.
0078 using nt_code = status_code<_nt_code_domain>;
0079 //! (Windows only) A specialisation of `status_error` for the NT error code domain.
0080 using nt_error = status_error<_nt_code_domain>;
0081 
0082 /*! (Windows only) The implementation of the domain for NT error codes, those returned by NT kernel functions.
0083  */
0084 class _nt_code_domain : public status_code_domain
0085 {
0086   template <class DomainType> friend class status_code;
0087   friend class _com_code_domain;
0088   using _base = status_code_domain;
0089   static int _nt_code_to_errno(win32::NTSTATUS c)
0090   {
0091     if(c >= 0)
0092     {
0093       return 0;  // success
0094     }
0095     switch(static_cast<unsigned>(c))
0096     {
0097 #include "detail/nt_code_to_generic_code.ipp"
0098     }
0099     return -1;
0100   }
0101   static win32::DWORD _nt_code_to_win32_code(win32::NTSTATUS c)  // NOLINT
0102   {
0103     if(c >= 0)
0104     {
0105       return 0;  // success
0106     }
0107     switch(static_cast<unsigned>(c))
0108     {
0109 #include "detail/nt_code_to_win32_code.ipp"
0110     }
0111     return static_cast<win32::DWORD>(-1);
0112   }
0113   //! Construct from a NT error code
0114   static _base::string_ref _make_string_ref(win32::NTSTATUS c) noexcept
0115   {
0116     wchar_t buffer[32768];
0117     static win32::HMODULE ntdll = win32::GetModuleHandleW(L"NTDLL.DLL");
0118     win32::DWORD wlen =
0119     win32::FormatMessageW(0x00000800 /*FORMAT_MESSAGE_FROM_HMODULE*/ | 0x00001000 /*FORMAT_MESSAGE_FROM_SYSTEM*/ | 0x00000200 /*FORMAT_MESSAGE_IGNORE_INSERTS*/,
0120                           ntdll, c, (1 << 10) /*MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT)*/, buffer, 32768, nullptr);
0121     size_t allocation = wlen + (wlen >> 1);
0122     win32::DWORD bytes;
0123     if(wlen == 0)
0124     {
0125       return _base::string_ref("failed to get message from system");
0126     }
0127     for(;;)
0128     {
0129       auto *p = static_cast<char *>(malloc(allocation));  // NOLINT
0130       if(p == nullptr)
0131       {
0132         return _base::string_ref("failed to get message from system");
0133       }
0134       bytes = win32::WideCharToMultiByte(65001 /*CP_UTF8*/, 0, buffer, (int) (wlen + 1), p, (int) allocation, nullptr, nullptr);
0135       if(bytes != 0)
0136       {
0137         char *end = strchr(p, 0);
0138         while(end[-1] == 10 || end[-1] == 13)
0139         {
0140           --end;
0141         }
0142         *end = 0;  // NOLINT
0143         return _base::atomic_refcounted_string_ref(p, end - p);
0144       }
0145       free(p);  // NOLINT
0146       if(win32::GetLastError() == 0x7a /*ERROR_INSUFFICIENT_BUFFER*/)
0147       {
0148         allocation += allocation >> 2;
0149         continue;
0150       }
0151       return _base::string_ref("failed to get message from system");
0152     }
0153   }
0154 
0155 public:
0156   //! The value type of the NT code, which is a `win32::NTSTATUS`
0157   using value_type = win32::NTSTATUS;
0158   using _base::string_ref;
0159 
0160 public:
0161   //! Default constructor
0162   constexpr explicit _nt_code_domain(typename _base::unique_id_type id = 0x93f3b4487e4af25b) noexcept
0163       : _base(id)
0164   {
0165   }
0166   _nt_code_domain(const _nt_code_domain &) = default;
0167   _nt_code_domain(_nt_code_domain &&) = default;
0168   _nt_code_domain &operator=(const _nt_code_domain &) = default;
0169   _nt_code_domain &operator=(_nt_code_domain &&) = default;
0170   ~_nt_code_domain() = default;
0171 
0172   //! Constexpr singleton getter. Returns the constexpr nt_code_domain variable.
0173   static inline constexpr const _nt_code_domain &get();
0174 
0175   virtual string_ref name() const noexcept override { return string_ref("NT domain"); }  // NOLINT
0176 
0177   virtual payload_info_t payload_info() const noexcept override
0178   {
0179     return {sizeof(value_type), sizeof(status_code_domain *) + sizeof(value_type),
0180             (alignof(value_type) > alignof(status_code_domain *)) ? alignof(value_type) : alignof(status_code_domain *)};
0181   }
0182 
0183 protected:
0184   virtual bool _do_failure(const status_code<void> &code) const noexcept override  // NOLINT
0185   {
0186     assert(code.domain() == *this);
0187     return static_cast<const nt_code &>(code).value() < 0;  // NOLINT
0188   }
0189   virtual bool _do_equivalent(const status_code<void> &code1, const status_code<void> &code2) const noexcept override  // NOLINT
0190   {
0191     assert(code1.domain() == *this);
0192     const auto &c1 = static_cast<const nt_code &>(code1);  // NOLINT
0193     if(code2.domain() == *this)
0194     {
0195       const auto &c2 = static_cast<const nt_code &>(code2);  // NOLINT
0196       return c1.value() == c2.value();
0197     }
0198     if(code2.domain() == generic_code_domain)
0199     {
0200       const auto &c2 = static_cast<const generic_code &>(code2);  // NOLINT
0201       if(static_cast<int>(c2.value()) == _nt_code_to_errno(c1.value()))
0202       {
0203         return true;
0204       }
0205     }
0206     if(code2.domain() == win32_code_domain)
0207     {
0208       const auto &c2 = static_cast<const win32_code &>(code2);  // NOLINT
0209       if(c2.value() == _nt_code_to_win32_code(c1.value()))
0210       {
0211         return true;
0212       }
0213     }
0214     return false;
0215   }
0216   virtual generic_code _generic_code(const status_code<void> &code) const noexcept override  // NOLINT
0217   {
0218     assert(code.domain() == *this);
0219     const auto &c = static_cast<const nt_code &>(code);  // NOLINT
0220     return generic_code(static_cast<errc>(_nt_code_to_errno(c.value())));
0221   }
0222   virtual string_ref _do_message(const status_code<void> &code) const noexcept override  // NOLINT
0223   {
0224     assert(code.domain() == *this);
0225     const auto &c = static_cast<const nt_code &>(code);  // NOLINT
0226     return _make_string_ref(c.value());
0227   }
0228 #if defined(_CPPUNWIND) || defined(__EXCEPTIONS) || defined(BOOST_OUTCOME_STANDARDESE_IS_IN_THE_HOUSE)
0229   BOOST_OUTCOME_SYSTEM_ERROR2_NORETURN virtual void _do_throw_exception(const status_code<void> &code) const override  // NOLINT
0230   {
0231     assert(code.domain() == *this);
0232     const auto &c = static_cast<const nt_code &>(code);  // NOLINT
0233     throw status_error<_nt_code_domain>(c);
0234   }
0235 #endif
0236 };
0237 //! (Windows only) A constexpr source variable for the NT code domain, which is that of NT kernel functions. Returned by `_nt_code_domain::get()`.
0238 constexpr _nt_code_domain nt_code_domain;
0239 inline constexpr const _nt_code_domain &_nt_code_domain::get()
0240 {
0241   return nt_code_domain;
0242 }
0243 
0244 BOOST_OUTCOME_SYSTEM_ERROR2_NAMESPACE_END
0245 
0246 #if defined(_MSC_VER) && !defined(__clang__)
0247 #pragma warning(pop)
0248 #endif
0249 
0250 #endif