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 #if !defined(_LIBCPP_HAS_NO_THREADS) 63 namespace { 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 } // end namespace 132 #endif 133 134 string 135 __do_message::message(int ev) const 136 { 137 #if defined(_LIBCPP_HAS_NO_THREADS) 138 return string(::strerror(ev)); 139 #else 140 return do_strerror_r(ev); 141 #endif 142 } 143 144 class _LIBCPP_HIDDEN __generic_error_category 145 : public __do_message 146 { 147 public: 148 virtual const char* name() const noexcept; 149 virtual string message(int ev) const; 150 }; 151 152 const char* 153 __generic_error_category::name() const noexcept 154 { 155 return "generic"; 156 } 157 158 string 159 __generic_error_category::message(int ev) const 160 { 161 #ifdef _LIBCPP_ELAST 162 if (ev > _LIBCPP_ELAST) 163 return string("unspecified generic_category error"); 164 #endif // _LIBCPP_ELAST 165 return __do_message::message(ev); 166 } 167 168 const error_category& 169 generic_category() noexcept 170 { 171 static __generic_error_category s; 172 return s; 173 } 174 175 class _LIBCPP_HIDDEN __system_error_category 176 : public __do_message 177 { 178 public: 179 virtual const char* name() const noexcept; 180 virtual string message(int ev) const; 181 virtual error_condition default_error_condition(int ev) const noexcept; 182 }; 183 184 const char* 185 __system_error_category::name() const noexcept 186 { 187 return "system"; 188 } 189 190 string 191 __system_error_category::message(int ev) const 192 { 193 #ifdef _LIBCPP_ELAST 194 if (ev > _LIBCPP_ELAST) 195 return string("unspecified system_category error"); 196 #endif // _LIBCPP_ELAST 197 return __do_message::message(ev); 198 } 199 200 error_condition 201 __system_error_category::default_error_condition(int ev) const noexcept 202 { 203 #ifdef _LIBCPP_ELAST 204 if (ev > _LIBCPP_ELAST) 205 return error_condition(ev, system_category()); 206 #endif // _LIBCPP_ELAST 207 return error_condition(ev, generic_category()); 208 } 209 210 const error_category& 211 system_category() noexcept 212 { 213 static __system_error_category s; 214 return s; 215 } 216 217 // error_condition 218 219 string 220 error_condition::message() const 221 { 222 return __cat_->message(__val_); 223 } 224 225 // error_code 226 227 string 228 error_code::message() const 229 { 230 return __cat_->message(__val_); 231 } 232 233 // system_error 234 235 string 236 system_error::__init(const error_code& ec, string what_arg) 237 { 238 if (ec) 239 { 240 if (!what_arg.empty()) 241 what_arg += ": "; 242 what_arg += ec.message(); 243 } 244 return what_arg; 245 } 246 247 system_error::system_error(error_code ec, const string& what_arg) 248 : runtime_error(__init(ec, what_arg)), 249 __ec_(ec) 250 { 251 } 252 253 system_error::system_error(error_code ec, const char* what_arg) 254 : runtime_error(__init(ec, what_arg)), 255 __ec_(ec) 256 { 257 } 258 259 system_error::system_error(error_code ec) 260 : runtime_error(__init(ec, "")), 261 __ec_(ec) 262 { 263 } 264 265 system_error::system_error(int ev, const error_category& ecat, const string& what_arg) 266 : runtime_error(__init(error_code(ev, ecat), what_arg)), 267 __ec_(error_code(ev, ecat)) 268 { 269 } 270 271 system_error::system_error(int ev, const error_category& ecat, const char* what_arg) 272 : runtime_error(__init(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) 278 : runtime_error(__init(error_code(ev, ecat), "")), 279 __ec_(error_code(ev, ecat)) 280 { 281 } 282 283 system_error::~system_error() noexcept 284 { 285 } 286 287 void 288 __throw_system_error(int ev, const char* what_arg) 289 { 290 #ifndef _LIBCPP_HAS_NO_EXCEPTIONS 291 throw system_error(error_code(ev, system_category()), what_arg); 292 #else 293 _LIBCPP_VERBOSE_ABORT("system_error was thrown in -fno-exceptions mode with error %i and message \"%s\"", ev, what_arg); 294 #endif 295 } 296 297 _LIBCPP_END_NAMESPACE_STD 298