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> 10*c9157d92SDimitry 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> 1781ad6265SDimitry Andric #include <string.h> 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 { 29*c9157d92SDimitry 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: 500b57cec5SDimitry Andric __attribute__((unused)) const char * 510b57cec5SDimitry Andric handle_strerror_r_return(char *strerror_return, char *buffer) { 520b57cec5SDimitry Andric // GNU always returns a string pointer in its return value. The 530b57cec5SDimitry Andric // string might point to either the input buffer, or a static 540b57cec5SDimitry Andric // buffer, but we don't care which. 550b57cec5SDimitry Andric return strerror_return; 560b57cec5SDimitry Andric } 570b57cec5SDimitry Andric 580b57cec5SDimitry Andric // For the POSIX variant: an int return value. 590b57cec5SDimitry Andric __attribute__((unused)) const char * 600b57cec5SDimitry Andric handle_strerror_r_return(int strerror_return, char *buffer) { 610b57cec5SDimitry Andric // The POSIX variant either: 620b57cec5SDimitry Andric // - fills in the provided buffer and returns 0 630b57cec5SDimitry Andric // - returns a positive error value, or 640b57cec5SDimitry Andric // - returns -1 and fills in errno with an error value. 650b57cec5SDimitry Andric if (strerror_return == 0) 660b57cec5SDimitry Andric return buffer; 670b57cec5SDimitry Andric 680b57cec5SDimitry Andric // Only handle EINVAL. Other errors abort. 690b57cec5SDimitry Andric int new_errno = strerror_return == -1 ? errno : strerror_return; 700b57cec5SDimitry Andric if (new_errno == EINVAL) 710b57cec5SDimitry Andric return ""; 720b57cec5SDimitry Andric 73fe013be4SDimitry Andric _LIBCPP_ASSERT_UNCATEGORIZED(new_errno == ERANGE, "unexpected error from ::strerror_r"); 740b57cec5SDimitry Andric // FIXME maybe? 'strerror_buff_size' is likely to exceed the 750b57cec5SDimitry Andric // maximum error size so ERANGE shouldn't be returned. 760b57cec5SDimitry Andric std::abort(); 770b57cec5SDimitry Andric } 780b57cec5SDimitry Andric 790b57cec5SDimitry Andric // This function handles both GNU and POSIX variants, dispatching to 800b57cec5SDimitry Andric // one of the two above functions. 810b57cec5SDimitry Andric string do_strerror_r(int ev) { 820b57cec5SDimitry Andric char buffer[strerror_buff_size]; 830b57cec5SDimitry Andric // Preserve errno around the call. (The C++ standard requires that 840b57cec5SDimitry Andric // system_error functions not modify errno). 850b57cec5SDimitry Andric const int old_errno = errno; 860b57cec5SDimitry Andric const char *error_message = handle_strerror_r_return( 870b57cec5SDimitry Andric ::strerror_r(ev, buffer, strerror_buff_size), buffer); 880b57cec5SDimitry Andric // If we didn't get any message, print one now. 890b57cec5SDimitry Andric if (!error_message[0]) { 900b57cec5SDimitry Andric std::snprintf(buffer, strerror_buff_size, "Unknown error %d", ev); 910b57cec5SDimitry Andric error_message = buffer; 920b57cec5SDimitry Andric } 930b57cec5SDimitry Andric errno = old_errno; 940b57cec5SDimitry Andric return string(error_message); 950b57cec5SDimitry Andric } 960b57cec5SDimitry Andric #endif 97*c9157d92SDimitry Andric 98*c9157d92SDimitry Andric #endif // !defined(_LIBCPP_HAS_NO_THREADS) 99*c9157d92SDimitry Andric 100*c9157d92SDimitry Andric string make_error_str(const error_code& ec, string what_arg) { 101*c9157d92SDimitry Andric if (ec) { 102*c9157d92SDimitry Andric if (!what_arg.empty()) { 103*c9157d92SDimitry Andric what_arg += ": "; 104*c9157d92SDimitry Andric } 105*c9157d92SDimitry Andric what_arg += ec.message(); 106*c9157d92SDimitry Andric } 107*c9157d92SDimitry Andric return what_arg; 108*c9157d92SDimitry Andric } 109*c9157d92SDimitry Andric 110*c9157d92SDimitry Andric string make_error_str(const error_code& ec) { 111*c9157d92SDimitry Andric if (ec) { 112*c9157d92SDimitry Andric return ec.message(); 113*c9157d92SDimitry Andric } 114*c9157d92SDimitry Andric return string(); 115*c9157d92SDimitry Andric } 1160b57cec5SDimitry Andric } // end namespace 1170b57cec5SDimitry Andric 1180b57cec5SDimitry Andric string 1190b57cec5SDimitry Andric __do_message::message(int ev) const 1200b57cec5SDimitry Andric { 1210b57cec5SDimitry Andric #if defined(_LIBCPP_HAS_NO_THREADS) 1220b57cec5SDimitry Andric return string(::strerror(ev)); 1230b57cec5SDimitry Andric #else 1240b57cec5SDimitry Andric return do_strerror_r(ev); 1250b57cec5SDimitry Andric #endif 1260b57cec5SDimitry Andric } 1270b57cec5SDimitry Andric 1280b57cec5SDimitry Andric class _LIBCPP_HIDDEN __generic_error_category 1290b57cec5SDimitry Andric : public __do_message 1300b57cec5SDimitry Andric { 1310b57cec5SDimitry Andric public: 132fe6060f1SDimitry Andric virtual const char* name() const noexcept; 1330b57cec5SDimitry Andric virtual string message(int ev) const; 1340b57cec5SDimitry Andric }; 1350b57cec5SDimitry Andric 1360b57cec5SDimitry Andric const char* 137fe6060f1SDimitry Andric __generic_error_category::name() const noexcept 1380b57cec5SDimitry Andric { 1390b57cec5SDimitry Andric return "generic"; 1400b57cec5SDimitry Andric } 1410b57cec5SDimitry Andric 1420b57cec5SDimitry Andric string 1430b57cec5SDimitry Andric __generic_error_category::message(int ev) const 1440b57cec5SDimitry Andric { 1450b57cec5SDimitry Andric #ifdef _LIBCPP_ELAST 1460b57cec5SDimitry Andric if (ev > _LIBCPP_ELAST) 1470b57cec5SDimitry Andric return string("unspecified generic_category error"); 1480b57cec5SDimitry Andric #endif // _LIBCPP_ELAST 1490b57cec5SDimitry Andric return __do_message::message(ev); 1500b57cec5SDimitry Andric } 1510b57cec5SDimitry Andric 1520b57cec5SDimitry Andric const error_category& 153fe6060f1SDimitry Andric generic_category() noexcept 1540b57cec5SDimitry Andric { 155*c9157d92SDimitry Andric union AvoidDestroyingGenericCategory { 156*c9157d92SDimitry Andric __generic_error_category generic_error_category; 157*c9157d92SDimitry Andric constexpr explicit AvoidDestroyingGenericCategory() : generic_error_category() {} 158*c9157d92SDimitry Andric ~AvoidDestroyingGenericCategory() {} 159*c9157d92SDimitry Andric }; 160*c9157d92SDimitry Andric constinit static AvoidDestroyingGenericCategory helper; 161*c9157d92SDimitry Andric return helper.generic_error_category; 1620b57cec5SDimitry Andric } 1630b57cec5SDimitry Andric 1640b57cec5SDimitry Andric class _LIBCPP_HIDDEN __system_error_category 1650b57cec5SDimitry Andric : public __do_message 1660b57cec5SDimitry Andric { 1670b57cec5SDimitry Andric public: 168fe6060f1SDimitry Andric virtual const char* name() const noexcept; 1690b57cec5SDimitry Andric virtual string message(int ev) const; 170fe6060f1SDimitry Andric virtual error_condition default_error_condition(int ev) const noexcept; 1710b57cec5SDimitry Andric }; 1720b57cec5SDimitry Andric 1730b57cec5SDimitry Andric const char* 174fe6060f1SDimitry Andric __system_error_category::name() const noexcept 1750b57cec5SDimitry Andric { 1760b57cec5SDimitry Andric return "system"; 1770b57cec5SDimitry Andric } 1780b57cec5SDimitry Andric 1790b57cec5SDimitry Andric string 1800b57cec5SDimitry Andric __system_error_category::message(int ev) const 1810b57cec5SDimitry Andric { 1820b57cec5SDimitry Andric #ifdef _LIBCPP_ELAST 1830b57cec5SDimitry Andric if (ev > _LIBCPP_ELAST) 1840b57cec5SDimitry Andric return string("unspecified system_category error"); 1850b57cec5SDimitry Andric #endif // _LIBCPP_ELAST 1860b57cec5SDimitry Andric return __do_message::message(ev); 1870b57cec5SDimitry Andric } 1880b57cec5SDimitry Andric 1890b57cec5SDimitry Andric error_condition 190fe6060f1SDimitry Andric __system_error_category::default_error_condition(int ev) const noexcept 1910b57cec5SDimitry Andric { 1920b57cec5SDimitry Andric #ifdef _LIBCPP_ELAST 1930b57cec5SDimitry Andric if (ev > _LIBCPP_ELAST) 1940b57cec5SDimitry Andric return error_condition(ev, system_category()); 1950b57cec5SDimitry Andric #endif // _LIBCPP_ELAST 1960b57cec5SDimitry Andric return error_condition(ev, generic_category()); 1970b57cec5SDimitry Andric } 1980b57cec5SDimitry Andric 1990b57cec5SDimitry Andric const error_category& 200fe6060f1SDimitry Andric system_category() noexcept 2010b57cec5SDimitry Andric { 202*c9157d92SDimitry Andric union AvoidDestroyingSystemCategory { 203*c9157d92SDimitry Andric __system_error_category system_error_category; 204*c9157d92SDimitry Andric constexpr explicit AvoidDestroyingSystemCategory() : system_error_category() {} 205*c9157d92SDimitry Andric ~AvoidDestroyingSystemCategory() {} 206*c9157d92SDimitry Andric }; 207*c9157d92SDimitry Andric constinit static AvoidDestroyingSystemCategory helper; 208*c9157d92SDimitry Andric return helper.system_error_category; 2090b57cec5SDimitry Andric } 2100b57cec5SDimitry Andric 2110b57cec5SDimitry Andric // error_condition 2120b57cec5SDimitry Andric 2130b57cec5SDimitry Andric string 2140b57cec5SDimitry Andric error_condition::message() const 2150b57cec5SDimitry Andric { 2160b57cec5SDimitry Andric return __cat_->message(__val_); 2170b57cec5SDimitry Andric } 2180b57cec5SDimitry Andric 2190b57cec5SDimitry Andric // error_code 2200b57cec5SDimitry Andric 2210b57cec5SDimitry Andric string 2220b57cec5SDimitry Andric error_code::message() const 2230b57cec5SDimitry Andric { 2240b57cec5SDimitry Andric return __cat_->message(__val_); 2250b57cec5SDimitry Andric } 2260b57cec5SDimitry Andric 2270b57cec5SDimitry Andric // system_error 2280b57cec5SDimitry Andric 2290b57cec5SDimitry Andric system_error::system_error(error_code ec, const string& what_arg) 230*c9157d92SDimitry Andric : runtime_error(make_error_str(ec, what_arg)), 2310b57cec5SDimitry Andric __ec_(ec) 2320b57cec5SDimitry Andric { 2330b57cec5SDimitry Andric } 2340b57cec5SDimitry Andric 2350b57cec5SDimitry Andric system_error::system_error(error_code ec, const char* what_arg) 236*c9157d92SDimitry Andric : runtime_error(make_error_str(ec, what_arg)), 2370b57cec5SDimitry Andric __ec_(ec) 2380b57cec5SDimitry Andric { 2390b57cec5SDimitry Andric } 2400b57cec5SDimitry Andric 2410b57cec5SDimitry Andric system_error::system_error(error_code ec) 242*c9157d92SDimitry Andric : runtime_error(make_error_str(ec)), 2430b57cec5SDimitry Andric __ec_(ec) 2440b57cec5SDimitry Andric { 2450b57cec5SDimitry Andric } 2460b57cec5SDimitry Andric 2470b57cec5SDimitry Andric system_error::system_error(int ev, const error_category& ecat, const string& what_arg) 248*c9157d92SDimitry Andric : runtime_error(make_error_str(error_code(ev, ecat), what_arg)), 2490b57cec5SDimitry Andric __ec_(error_code(ev, ecat)) 2500b57cec5SDimitry Andric { 2510b57cec5SDimitry Andric } 2520b57cec5SDimitry Andric 2530b57cec5SDimitry Andric system_error::system_error(int ev, const error_category& ecat, const char* what_arg) 254*c9157d92SDimitry Andric : runtime_error(make_error_str(error_code(ev, ecat), what_arg)), 2550b57cec5SDimitry Andric __ec_(error_code(ev, ecat)) 2560b57cec5SDimitry Andric { 2570b57cec5SDimitry Andric } 2580b57cec5SDimitry Andric 2590b57cec5SDimitry Andric system_error::system_error(int ev, const error_category& ecat) 260*c9157d92SDimitry Andric : runtime_error(make_error_str(error_code(ev, ecat))), 2610b57cec5SDimitry Andric __ec_(error_code(ev, ecat)) 2620b57cec5SDimitry Andric { 2630b57cec5SDimitry Andric } 2640b57cec5SDimitry Andric 265fe6060f1SDimitry Andric system_error::~system_error() noexcept 2660b57cec5SDimitry Andric { 2670b57cec5SDimitry Andric } 2680b57cec5SDimitry Andric 2690b57cec5SDimitry Andric void 2700b57cec5SDimitry Andric __throw_system_error(int ev, const char* what_arg) 2710b57cec5SDimitry Andric { 272fe013be4SDimitry Andric #ifndef _LIBCPP_HAS_NO_EXCEPTIONS 273*c9157d92SDimitry Andric std::__throw_system_error(error_code(ev, system_category()), what_arg); 2740b57cec5SDimitry Andric #else 275*c9157d92SDimitry Andric // The above could also handle the no-exception case, but for size, avoid referencing system_category() unnecessarily. 276fe013be4SDimitry Andric _LIBCPP_VERBOSE_ABORT("system_error was thrown in -fno-exceptions mode with error %i and message \"%s\"", ev, what_arg); 2770b57cec5SDimitry Andric #endif 2780b57cec5SDimitry Andric } 2790b57cec5SDimitry Andric 2800b57cec5SDimitry Andric _LIBCPP_END_NAMESPACE_STD 281