1*0b57cec5SDimitry Andric //===---------------------- system_error.cpp ------------------------------===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric 9*0b57cec5SDimitry Andric #include "__config" 10*0b57cec5SDimitry Andric 11*0b57cec5SDimitry Andric #include "system_error" 12*0b57cec5SDimitry Andric 13*0b57cec5SDimitry Andric #include "include/config_elast.h" 14*0b57cec5SDimitry Andric #include "cerrno" 15*0b57cec5SDimitry Andric #include "cstring" 16*0b57cec5SDimitry Andric #include "cstdio" 17*0b57cec5SDimitry Andric #include "cstdlib" 18*0b57cec5SDimitry Andric #include "string" 19*0b57cec5SDimitry Andric #include "string.h" 20*0b57cec5SDimitry Andric #include "__debug" 21*0b57cec5SDimitry Andric 22*0b57cec5SDimitry Andric #if defined(__ANDROID__) 23*0b57cec5SDimitry Andric #include <android/api-level.h> 24*0b57cec5SDimitry Andric #endif 25*0b57cec5SDimitry Andric 26*0b57cec5SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD 27*0b57cec5SDimitry Andric 28*0b57cec5SDimitry Andric // class error_category 29*0b57cec5SDimitry Andric 30*0b57cec5SDimitry Andric #if defined(_LIBCPP_DEPRECATED_ABI_LEGACY_LIBRARY_DEFINITIONS_FOR_INLINE_FUNCTIONS) 31fe6060f1SDimitry Andric error_category::error_category() noexcept 32*0b57cec5SDimitry Andric { 33*0b57cec5SDimitry Andric } 34*0b57cec5SDimitry Andric #endif 35*0b57cec5SDimitry Andric 36fe6060f1SDimitry Andric error_category::~error_category() noexcept 37*0b57cec5SDimitry Andric { 38*0b57cec5SDimitry Andric } 39*0b57cec5SDimitry Andric 40*0b57cec5SDimitry Andric error_condition 41fe6060f1SDimitry Andric error_category::default_error_condition(int ev) const noexcept 42*0b57cec5SDimitry Andric { 43*0b57cec5SDimitry Andric return error_condition(ev, *this); 44*0b57cec5SDimitry Andric } 45*0b57cec5SDimitry Andric 46*0b57cec5SDimitry Andric bool 47fe6060f1SDimitry Andric error_category::equivalent(int code, const error_condition& condition) const noexcept 48*0b57cec5SDimitry Andric { 49*0b57cec5SDimitry Andric return default_error_condition(code) == condition; 50*0b57cec5SDimitry Andric } 51*0b57cec5SDimitry Andric 52*0b57cec5SDimitry Andric bool 53fe6060f1SDimitry Andric error_category::equivalent(const error_code& code, int condition) const noexcept 54*0b57cec5SDimitry Andric { 55*0b57cec5SDimitry Andric return *this == code.category() && code.value() == condition; 56*0b57cec5SDimitry Andric } 57*0b57cec5SDimitry Andric 58*0b57cec5SDimitry Andric #if !defined(_LIBCPP_HAS_NO_THREADS) 59*0b57cec5SDimitry Andric namespace { 60*0b57cec5SDimitry Andric 61*0b57cec5SDimitry Andric // GLIBC also uses 1024 as the maximum buffer size internally. 62*0b57cec5SDimitry Andric constexpr size_t strerror_buff_size = 1024; 63*0b57cec5SDimitry Andric 64*0b57cec5SDimitry Andric string do_strerror_r(int ev); 65*0b57cec5SDimitry Andric 66*0b57cec5SDimitry Andric #if defined(_LIBCPP_MSVCRT_LIKE) 67*0b57cec5SDimitry Andric string do_strerror_r(int ev) { 68*0b57cec5SDimitry Andric char buffer[strerror_buff_size]; 69*0b57cec5SDimitry Andric if (::strerror_s(buffer, strerror_buff_size, ev) == 0) 70*0b57cec5SDimitry Andric return string(buffer); 71*0b57cec5SDimitry Andric std::snprintf(buffer, strerror_buff_size, "unknown error %d", ev); 72*0b57cec5SDimitry Andric return string(buffer); 73*0b57cec5SDimitry Andric } 74*0b57cec5SDimitry Andric #else 75*0b57cec5SDimitry Andric 76*0b57cec5SDimitry Andric // Only one of the two following functions will be used, depending on 77*0b57cec5SDimitry Andric // the return type of strerror_r: 78*0b57cec5SDimitry Andric 79*0b57cec5SDimitry Andric // For the GNU variant, a char* return value: 80*0b57cec5SDimitry Andric __attribute__((unused)) const char * 81*0b57cec5SDimitry Andric handle_strerror_r_return(char *strerror_return, char *buffer) { 82*0b57cec5SDimitry Andric // GNU always returns a string pointer in its return value. The 83*0b57cec5SDimitry Andric // string might point to either the input buffer, or a static 84*0b57cec5SDimitry Andric // buffer, but we don't care which. 85*0b57cec5SDimitry Andric return strerror_return; 86*0b57cec5SDimitry Andric } 87*0b57cec5SDimitry Andric 88*0b57cec5SDimitry Andric // For the POSIX variant: an int return value. 89*0b57cec5SDimitry Andric __attribute__((unused)) const char * 90*0b57cec5SDimitry Andric handle_strerror_r_return(int strerror_return, char *buffer) { 91*0b57cec5SDimitry Andric // The POSIX variant either: 92*0b57cec5SDimitry Andric // - fills in the provided buffer and returns 0 93*0b57cec5SDimitry Andric // - returns a positive error value, or 94*0b57cec5SDimitry Andric // - returns -1 and fills in errno with an error value. 95*0b57cec5SDimitry Andric if (strerror_return == 0) 96*0b57cec5SDimitry Andric return buffer; 97*0b57cec5SDimitry Andric 98*0b57cec5SDimitry Andric // Only handle EINVAL. Other errors abort. 99*0b57cec5SDimitry Andric int new_errno = strerror_return == -1 ? errno : strerror_return; 100*0b57cec5SDimitry Andric if (new_errno == EINVAL) 101*0b57cec5SDimitry Andric return ""; 102*0b57cec5SDimitry Andric 103*0b57cec5SDimitry Andric _LIBCPP_ASSERT(new_errno == ERANGE, "unexpected error from ::strerror_r"); 104*0b57cec5SDimitry Andric // FIXME maybe? 'strerror_buff_size' is likely to exceed the 105*0b57cec5SDimitry Andric // maximum error size so ERANGE shouldn't be returned. 106*0b57cec5SDimitry Andric std::abort(); 107*0b57cec5SDimitry Andric } 108*0b57cec5SDimitry Andric 109*0b57cec5SDimitry Andric // This function handles both GNU and POSIX variants, dispatching to 110*0b57cec5SDimitry Andric // one of the two above functions. 111*0b57cec5SDimitry Andric string do_strerror_r(int ev) { 112*0b57cec5SDimitry Andric char buffer[strerror_buff_size]; 113*0b57cec5SDimitry Andric // Preserve errno around the call. (The C++ standard requires that 114*0b57cec5SDimitry Andric // system_error functions not modify errno). 115*0b57cec5SDimitry Andric const int old_errno = errno; 116*0b57cec5SDimitry Andric const char *error_message = handle_strerror_r_return( 117*0b57cec5SDimitry Andric ::strerror_r(ev, buffer, strerror_buff_size), buffer); 118*0b57cec5SDimitry Andric // If we didn't get any message, print one now. 119*0b57cec5SDimitry Andric if (!error_message[0]) { 120*0b57cec5SDimitry Andric std::snprintf(buffer, strerror_buff_size, "Unknown error %d", ev); 121*0b57cec5SDimitry Andric error_message = buffer; 122*0b57cec5SDimitry Andric } 123*0b57cec5SDimitry Andric errno = old_errno; 124*0b57cec5SDimitry Andric return string(error_message); 125*0b57cec5SDimitry Andric } 126*0b57cec5SDimitry Andric #endif 127*0b57cec5SDimitry Andric } // end namespace 128*0b57cec5SDimitry Andric #endif 129*0b57cec5SDimitry Andric 130*0b57cec5SDimitry Andric string 131*0b57cec5SDimitry Andric __do_message::message(int ev) const 132*0b57cec5SDimitry Andric { 133*0b57cec5SDimitry Andric #if defined(_LIBCPP_HAS_NO_THREADS) 134*0b57cec5SDimitry Andric return string(::strerror(ev)); 135*0b57cec5SDimitry Andric #else 136*0b57cec5SDimitry Andric return do_strerror_r(ev); 137*0b57cec5SDimitry Andric #endif 138*0b57cec5SDimitry Andric } 139*0b57cec5SDimitry Andric 140*0b57cec5SDimitry Andric class _LIBCPP_HIDDEN __generic_error_category 141*0b57cec5SDimitry Andric : public __do_message 142*0b57cec5SDimitry Andric { 143*0b57cec5SDimitry Andric public: 144fe6060f1SDimitry Andric virtual const char* name() const noexcept; 145*0b57cec5SDimitry Andric virtual string message(int ev) const; 146*0b57cec5SDimitry Andric }; 147*0b57cec5SDimitry Andric 148*0b57cec5SDimitry Andric const char* 149fe6060f1SDimitry Andric __generic_error_category::name() const noexcept 150*0b57cec5SDimitry Andric { 151*0b57cec5SDimitry Andric return "generic"; 152*0b57cec5SDimitry Andric } 153*0b57cec5SDimitry Andric 154*0b57cec5SDimitry Andric string 155*0b57cec5SDimitry Andric __generic_error_category::message(int ev) const 156*0b57cec5SDimitry Andric { 157*0b57cec5SDimitry Andric #ifdef _LIBCPP_ELAST 158*0b57cec5SDimitry Andric if (ev > _LIBCPP_ELAST) 159*0b57cec5SDimitry Andric return string("unspecified generic_category error"); 160*0b57cec5SDimitry Andric #endif // _LIBCPP_ELAST 161*0b57cec5SDimitry Andric return __do_message::message(ev); 162*0b57cec5SDimitry Andric } 163*0b57cec5SDimitry Andric 164*0b57cec5SDimitry Andric const error_category& 165fe6060f1SDimitry Andric generic_category() noexcept 166*0b57cec5SDimitry Andric { 167*0b57cec5SDimitry Andric static __generic_error_category s; 168*0b57cec5SDimitry Andric return s; 169*0b57cec5SDimitry Andric } 170*0b57cec5SDimitry Andric 171*0b57cec5SDimitry Andric class _LIBCPP_HIDDEN __system_error_category 172*0b57cec5SDimitry Andric : public __do_message 173*0b57cec5SDimitry Andric { 174*0b57cec5SDimitry Andric public: 175fe6060f1SDimitry Andric virtual const char* name() const noexcept; 176*0b57cec5SDimitry Andric virtual string message(int ev) const; 177fe6060f1SDimitry Andric virtual error_condition default_error_condition(int ev) const noexcept; 178*0b57cec5SDimitry Andric }; 179*0b57cec5SDimitry Andric 180*0b57cec5SDimitry Andric const char* 181fe6060f1SDimitry Andric __system_error_category::name() const noexcept 182*0b57cec5SDimitry Andric { 183*0b57cec5SDimitry Andric return "system"; 184*0b57cec5SDimitry Andric } 185*0b57cec5SDimitry Andric 186*0b57cec5SDimitry Andric string 187*0b57cec5SDimitry Andric __system_error_category::message(int ev) const 188*0b57cec5SDimitry Andric { 189*0b57cec5SDimitry Andric #ifdef _LIBCPP_ELAST 190*0b57cec5SDimitry Andric if (ev > _LIBCPP_ELAST) 191*0b57cec5SDimitry Andric return string("unspecified system_category error"); 192*0b57cec5SDimitry Andric #endif // _LIBCPP_ELAST 193*0b57cec5SDimitry Andric return __do_message::message(ev); 194*0b57cec5SDimitry Andric } 195*0b57cec5SDimitry Andric 196*0b57cec5SDimitry Andric error_condition 197fe6060f1SDimitry Andric __system_error_category::default_error_condition(int ev) const noexcept 198*0b57cec5SDimitry Andric { 199*0b57cec5SDimitry Andric #ifdef _LIBCPP_ELAST 200*0b57cec5SDimitry Andric if (ev > _LIBCPP_ELAST) 201*0b57cec5SDimitry Andric return error_condition(ev, system_category()); 202*0b57cec5SDimitry Andric #endif // _LIBCPP_ELAST 203*0b57cec5SDimitry Andric return error_condition(ev, generic_category()); 204*0b57cec5SDimitry Andric } 205*0b57cec5SDimitry Andric 206*0b57cec5SDimitry Andric const error_category& 207fe6060f1SDimitry Andric system_category() noexcept 208*0b57cec5SDimitry Andric { 209*0b57cec5SDimitry Andric static __system_error_category s; 210*0b57cec5SDimitry Andric return s; 211*0b57cec5SDimitry Andric } 212*0b57cec5SDimitry Andric 213*0b57cec5SDimitry Andric // error_condition 214*0b57cec5SDimitry Andric 215*0b57cec5SDimitry Andric string 216*0b57cec5SDimitry Andric error_condition::message() const 217*0b57cec5SDimitry Andric { 218*0b57cec5SDimitry Andric return __cat_->message(__val_); 219*0b57cec5SDimitry Andric } 220*0b57cec5SDimitry Andric 221*0b57cec5SDimitry Andric // error_code 222*0b57cec5SDimitry Andric 223*0b57cec5SDimitry Andric string 224*0b57cec5SDimitry Andric error_code::message() const 225*0b57cec5SDimitry Andric { 226*0b57cec5SDimitry Andric return __cat_->message(__val_); 227*0b57cec5SDimitry Andric } 228*0b57cec5SDimitry Andric 229*0b57cec5SDimitry Andric // system_error 230*0b57cec5SDimitry Andric 231*0b57cec5SDimitry Andric string 232*0b57cec5SDimitry Andric system_error::__init(const error_code& ec, string what_arg) 233*0b57cec5SDimitry Andric { 234*0b57cec5SDimitry Andric if (ec) 235*0b57cec5SDimitry Andric { 236*0b57cec5SDimitry Andric if (!what_arg.empty()) 237*0b57cec5SDimitry Andric what_arg += ": "; 238*0b57cec5SDimitry Andric what_arg += ec.message(); 239*0b57cec5SDimitry Andric } 240*0b57cec5SDimitry Andric return what_arg; 241*0b57cec5SDimitry Andric } 242*0b57cec5SDimitry Andric 243*0b57cec5SDimitry Andric system_error::system_error(error_code ec, const string& what_arg) 244*0b57cec5SDimitry Andric : runtime_error(__init(ec, what_arg)), 245*0b57cec5SDimitry Andric __ec_(ec) 246*0b57cec5SDimitry Andric { 247*0b57cec5SDimitry Andric } 248*0b57cec5SDimitry Andric 249*0b57cec5SDimitry Andric system_error::system_error(error_code ec, const char* what_arg) 250*0b57cec5SDimitry Andric : runtime_error(__init(ec, what_arg)), 251*0b57cec5SDimitry Andric __ec_(ec) 252*0b57cec5SDimitry Andric { 253*0b57cec5SDimitry Andric } 254*0b57cec5SDimitry Andric 255*0b57cec5SDimitry Andric system_error::system_error(error_code ec) 256*0b57cec5SDimitry Andric : runtime_error(__init(ec, "")), 257*0b57cec5SDimitry Andric __ec_(ec) 258*0b57cec5SDimitry Andric { 259*0b57cec5SDimitry Andric } 260*0b57cec5SDimitry Andric 261*0b57cec5SDimitry Andric system_error::system_error(int ev, const error_category& ecat, const string& what_arg) 262*0b57cec5SDimitry Andric : runtime_error(__init(error_code(ev, ecat), what_arg)), 263*0b57cec5SDimitry Andric __ec_(error_code(ev, ecat)) 264*0b57cec5SDimitry Andric { 265*0b57cec5SDimitry Andric } 266*0b57cec5SDimitry Andric 267*0b57cec5SDimitry Andric system_error::system_error(int ev, const error_category& ecat, const char* what_arg) 268*0b57cec5SDimitry Andric : runtime_error(__init(error_code(ev, ecat), what_arg)), 269*0b57cec5SDimitry Andric __ec_(error_code(ev, ecat)) 270*0b57cec5SDimitry Andric { 271*0b57cec5SDimitry Andric } 272*0b57cec5SDimitry Andric 273*0b57cec5SDimitry Andric system_error::system_error(int ev, const error_category& ecat) 274*0b57cec5SDimitry Andric : runtime_error(__init(error_code(ev, ecat), "")), 275*0b57cec5SDimitry Andric __ec_(error_code(ev, ecat)) 276*0b57cec5SDimitry Andric { 277*0b57cec5SDimitry Andric } 278*0b57cec5SDimitry Andric 279fe6060f1SDimitry Andric system_error::~system_error() noexcept 280*0b57cec5SDimitry Andric { 281*0b57cec5SDimitry Andric } 282*0b57cec5SDimitry Andric 283*0b57cec5SDimitry Andric void 284*0b57cec5SDimitry Andric __throw_system_error(int ev, const char* what_arg) 285*0b57cec5SDimitry Andric { 286*0b57cec5SDimitry Andric #ifndef _LIBCPP_NO_EXCEPTIONS 287*0b57cec5SDimitry Andric throw system_error(error_code(ev, system_category()), what_arg); 288*0b57cec5SDimitry Andric #else 289*0b57cec5SDimitry Andric (void)ev; 290*0b57cec5SDimitry Andric (void)what_arg; 291*0b57cec5SDimitry Andric _VSTD::abort(); 292*0b57cec5SDimitry Andric #endif 293*0b57cec5SDimitry Andric } 294*0b57cec5SDimitry Andric 295*0b57cec5SDimitry Andric _LIBCPP_END_NAMESPACE_STD 296