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