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