1349cc55cSDimitry Andric //===----------------------------------------------------------------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric 981ad6265SDimitry Andric #include <__assert> 10c9157d92SDimitry Andric #include <__config> 11fe013be4SDimitry Andric #include <__verbose_abort> 1281ad6265SDimitry Andric #include <cerrno> 1381ad6265SDimitry Andric #include <cstdio> 1481ad6265SDimitry Andric #include <cstdlib> 1581ad6265SDimitry Andric #include <cstring> 1681ad6265SDimitry Andric #include <string.h> 17*e710425bSDimitry Andric #include <string> 1881ad6265SDimitry Andric #include <system_error> 190b57cec5SDimitry Andric 200b57cec5SDimitry Andric #include "include/config_elast.h" 210b57cec5SDimitry Andric 220b57cec5SDimitry Andric #if defined(__ANDROID__) 230b57cec5SDimitry Andric # include <android/api-level.h> 240b57cec5SDimitry Andric #endif 250b57cec5SDimitry Andric 260b57cec5SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD 270b57cec5SDimitry Andric 280b57cec5SDimitry Andric namespace { 29c9157d92SDimitry Andric #if !defined(_LIBCPP_HAS_NO_THREADS) 300b57cec5SDimitry Andric 310b57cec5SDimitry Andric // GLIBC also uses 1024 as the maximum buffer size internally. 320b57cec5SDimitry Andric constexpr size_t strerror_buff_size = 1024; 330b57cec5SDimitry Andric 340b57cec5SDimitry Andric string do_strerror_r(int ev); 350b57cec5SDimitry Andric 360b57cec5SDimitry Andric # if defined(_LIBCPP_MSVCRT_LIKE) 370b57cec5SDimitry Andric string do_strerror_r(int ev) { 380b57cec5SDimitry Andric char buffer[strerror_buff_size]; 390b57cec5SDimitry Andric if (::strerror_s(buffer, strerror_buff_size, ev) == 0) 400b57cec5SDimitry Andric return string(buffer); 410b57cec5SDimitry Andric std::snprintf(buffer, strerror_buff_size, "unknown error %d", ev); 420b57cec5SDimitry Andric return string(buffer); 430b57cec5SDimitry Andric } 440b57cec5SDimitry Andric # else 450b57cec5SDimitry Andric 460b57cec5SDimitry Andric // Only one of the two following functions will be used, depending on 470b57cec5SDimitry Andric // the return type of strerror_r: 480b57cec5SDimitry Andric 490b57cec5SDimitry Andric // For the GNU variant, a char* return value: 50*e710425bSDimitry Andric __attribute__((unused)) const char* handle_strerror_r_return(char* strerror_return, char* buffer) { 510b57cec5SDimitry Andric // GNU always returns a string pointer in its return value. The 520b57cec5SDimitry Andric // string might point to either the input buffer, or a static 530b57cec5SDimitry Andric // buffer, but we don't care which. 540b57cec5SDimitry Andric return strerror_return; 550b57cec5SDimitry Andric } 560b57cec5SDimitry Andric 570b57cec5SDimitry Andric // For the POSIX variant: an int return value. 58*e710425bSDimitry Andric __attribute__((unused)) const char* handle_strerror_r_return(int strerror_return, char* buffer) { 590b57cec5SDimitry Andric // The POSIX variant either: 600b57cec5SDimitry Andric // - fills in the provided buffer and returns 0 610b57cec5SDimitry Andric // - returns a positive error value, or 620b57cec5SDimitry Andric // - returns -1 and fills in errno with an error value. 630b57cec5SDimitry Andric if (strerror_return == 0) 640b57cec5SDimitry Andric return buffer; 650b57cec5SDimitry Andric 660b57cec5SDimitry Andric // Only handle EINVAL. Other errors abort. 670b57cec5SDimitry Andric int new_errno = strerror_return == -1 ? errno : strerror_return; 680b57cec5SDimitry Andric if (new_errno == EINVAL) 690b57cec5SDimitry Andric return ""; 700b57cec5SDimitry Andric 71fe013be4SDimitry Andric _LIBCPP_ASSERT_UNCATEGORIZED(new_errno == ERANGE, "unexpected error from ::strerror_r"); 720b57cec5SDimitry Andric // FIXME maybe? 'strerror_buff_size' is likely to exceed the 730b57cec5SDimitry Andric // maximum error size so ERANGE shouldn't be returned. 740b57cec5SDimitry Andric std::abort(); 750b57cec5SDimitry Andric } 760b57cec5SDimitry Andric 770b57cec5SDimitry Andric // This function handles both GNU and POSIX variants, dispatching to 780b57cec5SDimitry Andric // one of the two above functions. 790b57cec5SDimitry Andric string do_strerror_r(int ev) { 800b57cec5SDimitry Andric char buffer[strerror_buff_size]; 810b57cec5SDimitry Andric // Preserve errno around the call. (The C++ standard requires that 820b57cec5SDimitry Andric // system_error functions not modify errno). 830b57cec5SDimitry Andric const int old_errno = errno; 84*e710425bSDimitry Andric const char* error_message = handle_strerror_r_return(::strerror_r(ev, buffer, strerror_buff_size), buffer); 850b57cec5SDimitry Andric // If we didn't get any message, print one now. 860b57cec5SDimitry Andric if (!error_message[0]) { 870b57cec5SDimitry Andric std::snprintf(buffer, strerror_buff_size, "Unknown error %d", ev); 880b57cec5SDimitry Andric error_message = buffer; 890b57cec5SDimitry Andric } 900b57cec5SDimitry Andric errno = old_errno; 910b57cec5SDimitry Andric return string(error_message); 920b57cec5SDimitry Andric } 930b57cec5SDimitry Andric # endif 94c9157d92SDimitry Andric 95c9157d92SDimitry Andric #endif // !defined(_LIBCPP_HAS_NO_THREADS) 96c9157d92SDimitry Andric 97c9157d92SDimitry Andric string make_error_str(const error_code& ec, string what_arg) { 98c9157d92SDimitry Andric if (ec) { 99c9157d92SDimitry Andric if (!what_arg.empty()) { 100c9157d92SDimitry Andric what_arg += ": "; 101c9157d92SDimitry Andric } 102c9157d92SDimitry Andric what_arg += ec.message(); 103c9157d92SDimitry Andric } 104c9157d92SDimitry Andric return what_arg; 105c9157d92SDimitry Andric } 106c9157d92SDimitry Andric 107c9157d92SDimitry Andric string make_error_str(const error_code& ec) { 108c9157d92SDimitry Andric if (ec) { 109c9157d92SDimitry Andric return ec.message(); 110c9157d92SDimitry Andric } 111c9157d92SDimitry Andric return string(); 112c9157d92SDimitry Andric } 1130b57cec5SDimitry Andric } // end namespace 1140b57cec5SDimitry Andric 115*e710425bSDimitry Andric string __do_message::message(int ev) const { 1160b57cec5SDimitry Andric #if defined(_LIBCPP_HAS_NO_THREADS) 1170b57cec5SDimitry Andric return string(::strerror(ev)); 1180b57cec5SDimitry Andric #else 1190b57cec5SDimitry Andric return do_strerror_r(ev); 1200b57cec5SDimitry Andric #endif 1210b57cec5SDimitry Andric } 1220b57cec5SDimitry Andric 123*e710425bSDimitry Andric class _LIBCPP_HIDDEN __generic_error_category : public __do_message { 1240b57cec5SDimitry Andric public: 125fe6060f1SDimitry Andric virtual const char* name() const noexcept; 1260b57cec5SDimitry Andric virtual string message(int ev) const; 1270b57cec5SDimitry Andric }; 1280b57cec5SDimitry Andric 129*e710425bSDimitry Andric const char* __generic_error_category::name() const noexcept { return "generic"; } 1300b57cec5SDimitry Andric 131*e710425bSDimitry Andric string __generic_error_category::message(int ev) const { 1320b57cec5SDimitry Andric #ifdef _LIBCPP_ELAST 1330b57cec5SDimitry Andric if (ev > _LIBCPP_ELAST) 1340b57cec5SDimitry Andric return string("unspecified generic_category error"); 1350b57cec5SDimitry Andric #endif // _LIBCPP_ELAST 1360b57cec5SDimitry Andric return __do_message::message(ev); 1370b57cec5SDimitry Andric } 1380b57cec5SDimitry Andric 139*e710425bSDimitry Andric const error_category& generic_category() noexcept { 140c9157d92SDimitry Andric union AvoidDestroyingGenericCategory { 141c9157d92SDimitry Andric __generic_error_category generic_error_category; 142c9157d92SDimitry Andric constexpr explicit AvoidDestroyingGenericCategory() : generic_error_category() {} 143c9157d92SDimitry Andric ~AvoidDestroyingGenericCategory() {} 144c9157d92SDimitry Andric }; 145c9157d92SDimitry Andric constinit static AvoidDestroyingGenericCategory helper; 146c9157d92SDimitry Andric return helper.generic_error_category; 1470b57cec5SDimitry Andric } 1480b57cec5SDimitry Andric 149*e710425bSDimitry Andric class _LIBCPP_HIDDEN __system_error_category : public __do_message { 1500b57cec5SDimitry Andric public: 151fe6060f1SDimitry Andric virtual const char* name() const noexcept; 1520b57cec5SDimitry Andric virtual string message(int ev) const; 153fe6060f1SDimitry Andric virtual error_condition default_error_condition(int ev) const noexcept; 1540b57cec5SDimitry Andric }; 1550b57cec5SDimitry Andric 156*e710425bSDimitry Andric const char* __system_error_category::name() const noexcept { return "system"; } 1570b57cec5SDimitry Andric 158*e710425bSDimitry Andric string __system_error_category::message(int ev) const { 1590b57cec5SDimitry Andric #ifdef _LIBCPP_ELAST 1600b57cec5SDimitry Andric if (ev > _LIBCPP_ELAST) 1610b57cec5SDimitry Andric return string("unspecified system_category error"); 1620b57cec5SDimitry Andric #endif // _LIBCPP_ELAST 1630b57cec5SDimitry Andric return __do_message::message(ev); 1640b57cec5SDimitry Andric } 1650b57cec5SDimitry Andric 166*e710425bSDimitry Andric error_condition __system_error_category::default_error_condition(int ev) const noexcept { 1670b57cec5SDimitry Andric #ifdef _LIBCPP_ELAST 1680b57cec5SDimitry Andric if (ev > _LIBCPP_ELAST) 1690b57cec5SDimitry Andric return error_condition(ev, system_category()); 1700b57cec5SDimitry Andric #endif // _LIBCPP_ELAST 1710b57cec5SDimitry Andric return error_condition(ev, generic_category()); 1720b57cec5SDimitry Andric } 1730b57cec5SDimitry Andric 174*e710425bSDimitry Andric const error_category& system_category() noexcept { 175c9157d92SDimitry Andric union AvoidDestroyingSystemCategory { 176c9157d92SDimitry Andric __system_error_category system_error_category; 177c9157d92SDimitry Andric constexpr explicit AvoidDestroyingSystemCategory() : system_error_category() {} 178c9157d92SDimitry Andric ~AvoidDestroyingSystemCategory() {} 179c9157d92SDimitry Andric }; 180c9157d92SDimitry Andric constinit static AvoidDestroyingSystemCategory helper; 181c9157d92SDimitry Andric return helper.system_error_category; 1820b57cec5SDimitry Andric } 1830b57cec5SDimitry Andric 1840b57cec5SDimitry Andric // error_condition 1850b57cec5SDimitry Andric 186*e710425bSDimitry Andric string error_condition::message() const { return __cat_->message(__val_); } 1870b57cec5SDimitry Andric 1880b57cec5SDimitry Andric // error_code 1890b57cec5SDimitry Andric 190*e710425bSDimitry Andric string error_code::message() const { return __cat_->message(__val_); } 1910b57cec5SDimitry Andric 1920b57cec5SDimitry Andric // system_error 1930b57cec5SDimitry Andric 1940b57cec5SDimitry Andric system_error::system_error(error_code ec, const string& what_arg) 195*e710425bSDimitry Andric : runtime_error(make_error_str(ec, what_arg)), __ec_(ec) {} 1960b57cec5SDimitry Andric 1970b57cec5SDimitry Andric system_error::system_error(error_code ec, const char* what_arg) 198*e710425bSDimitry Andric : runtime_error(make_error_str(ec, what_arg)), __ec_(ec) {} 1990b57cec5SDimitry Andric 200*e710425bSDimitry Andric system_error::system_error(error_code ec) : runtime_error(make_error_str(ec)), __ec_(ec) {} 2010b57cec5SDimitry Andric 2020b57cec5SDimitry Andric system_error::system_error(int ev, const error_category& ecat, const string& what_arg) 203*e710425bSDimitry Andric : runtime_error(make_error_str(error_code(ev, ecat), what_arg)), __ec_(error_code(ev, ecat)) {} 2040b57cec5SDimitry Andric 2050b57cec5SDimitry Andric system_error::system_error(int ev, const error_category& ecat, const char* what_arg) 206*e710425bSDimitry Andric : runtime_error(make_error_str(error_code(ev, ecat), what_arg)), __ec_(error_code(ev, ecat)) {} 2070b57cec5SDimitry Andric 2080b57cec5SDimitry Andric system_error::system_error(int ev, const error_category& ecat) 209*e710425bSDimitry Andric : runtime_error(make_error_str(error_code(ev, ecat))), __ec_(error_code(ev, ecat)) {} 2100b57cec5SDimitry Andric 211*e710425bSDimitry Andric system_error::~system_error() noexcept {} 2120b57cec5SDimitry Andric 213*e710425bSDimitry Andric void __throw_system_error(int ev, const char* what_arg) { 214fe013be4SDimitry Andric #ifndef _LIBCPP_HAS_NO_EXCEPTIONS 215c9157d92SDimitry Andric std::__throw_system_error(error_code(ev, system_category()), what_arg); 2160b57cec5SDimitry Andric #else 217c9157d92SDimitry Andric // The above could also handle the no-exception case, but for size, avoid referencing system_category() unnecessarily. 218*e710425bSDimitry Andric _LIBCPP_VERBOSE_ABORT( 219*e710425bSDimitry Andric "system_error was thrown in -fno-exceptions mode with error %i and message \"%s\"", ev, what_arg); 2200b57cec5SDimitry Andric #endif 2210b57cec5SDimitry Andric } 2220b57cec5SDimitry Andric 2230b57cec5SDimitry Andric _LIBCPP_END_NAMESPACE_STD 224