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 <__system_error/throw_system_error.h> 12 #include <__verbose_abort> 13 #include <cerrno> 14 #include <cstdio> 15 #include <cstdlib> 16 #include <cstring> 17 #include <optional> 18 #include <string.h> 19 #include <string> 20 #include <system_error> 21 22 #include "include/config_elast.h" 23 24 #if defined(__ANDROID__) 25 # include <android/api-level.h> 26 #endif 27 28 #if defined(_LIBCPP_WIN32API) 29 # include <windows.h> 30 # include <winerror.h> 31 #endif 32 33 _LIBCPP_BEGIN_NAMESPACE_STD 34 35 #if defined(_LIBCPP_WIN32API) 36 37 namespace { 38 std::optional<errc> __win_err_to_errc(int err) { 39 switch (err) { 40 case ERROR_ACCESS_DENIED: 41 return errc::permission_denied; 42 case ERROR_ALREADY_EXISTS: 43 return errc::file_exists; 44 case ERROR_BAD_NETPATH: 45 return errc::no_such_file_or_directory; 46 case ERROR_BAD_PATHNAME: 47 return errc::no_such_file_or_directory; 48 case ERROR_BAD_UNIT: 49 return errc::no_such_device; 50 case ERROR_BROKEN_PIPE: 51 return errc::broken_pipe; 52 case ERROR_BUFFER_OVERFLOW: 53 return errc::filename_too_long; 54 case ERROR_BUSY: 55 return errc::device_or_resource_busy; 56 case ERROR_BUSY_DRIVE: 57 return errc::device_or_resource_busy; 58 case ERROR_CANNOT_MAKE: 59 return errc::permission_denied; 60 case ERROR_CANTOPEN: 61 return errc::io_error; 62 case ERROR_CANTREAD: 63 return errc::io_error; 64 case ERROR_CANTWRITE: 65 return errc::io_error; 66 case ERROR_CURRENT_DIRECTORY: 67 return errc::permission_denied; 68 case ERROR_DEV_NOT_EXIST: 69 return errc::no_such_device; 70 case ERROR_DEVICE_IN_USE: 71 return errc::device_or_resource_busy; 72 case ERROR_DIR_NOT_EMPTY: 73 return errc::directory_not_empty; 74 case ERROR_DIRECTORY: 75 return errc::invalid_argument; 76 case ERROR_DISK_FULL: 77 return errc::no_space_on_device; 78 case ERROR_FILE_EXISTS: 79 return errc::file_exists; 80 case ERROR_FILE_NOT_FOUND: 81 return errc::no_such_file_or_directory; 82 case ERROR_HANDLE_DISK_FULL: 83 return errc::no_space_on_device; 84 case ERROR_INVALID_ACCESS: 85 return errc::permission_denied; 86 case ERROR_INVALID_DRIVE: 87 return errc::no_such_device; 88 case ERROR_INVALID_FUNCTION: 89 return errc::function_not_supported; 90 case ERROR_INVALID_HANDLE: 91 return errc::invalid_argument; 92 case ERROR_INVALID_NAME: 93 return errc::no_such_file_or_directory; 94 case ERROR_INVALID_PARAMETER: 95 return errc::invalid_argument; 96 case ERROR_LOCK_VIOLATION: 97 return errc::no_lock_available; 98 case ERROR_LOCKED: 99 return errc::no_lock_available; 100 case ERROR_NEGATIVE_SEEK: 101 return errc::invalid_argument; 102 case ERROR_NOACCESS: 103 return errc::permission_denied; 104 case ERROR_NOT_ENOUGH_MEMORY: 105 return errc::not_enough_memory; 106 case ERROR_NOT_READY: 107 return errc::resource_unavailable_try_again; 108 case ERROR_NOT_SAME_DEVICE: 109 return errc::cross_device_link; 110 case ERROR_NOT_SUPPORTED: 111 return errc::not_supported; 112 case ERROR_OPEN_FAILED: 113 return errc::io_error; 114 case ERROR_OPEN_FILES: 115 return errc::device_or_resource_busy; 116 case ERROR_OPERATION_ABORTED: 117 return errc::operation_canceled; 118 case ERROR_OUTOFMEMORY: 119 return errc::not_enough_memory; 120 case ERROR_PATH_NOT_FOUND: 121 return errc::no_such_file_or_directory; 122 case ERROR_READ_FAULT: 123 return errc::io_error; 124 case ERROR_REPARSE_TAG_INVALID: 125 return errc::invalid_argument; 126 case ERROR_RETRY: 127 return errc::resource_unavailable_try_again; 128 case ERROR_SEEK: 129 return errc::io_error; 130 case ERROR_SHARING_VIOLATION: 131 return errc::permission_denied; 132 case ERROR_TOO_MANY_OPEN_FILES: 133 return errc::too_many_files_open; 134 case ERROR_WRITE_FAULT: 135 return errc::io_error; 136 case ERROR_WRITE_PROTECT: 137 return errc::permission_denied; 138 default: 139 return {}; 140 } 141 } 142 } // namespace 143 #endif 144 145 namespace { 146 #if _LIBCPP_HAS_THREADS 147 148 // GLIBC also uses 1024 as the maximum buffer size internally. 149 constexpr size_t strerror_buff_size = 1024; 150 151 string do_strerror_r(int ev); 152 153 # if defined(_LIBCPP_MSVCRT_LIKE) 154 string do_strerror_r(int ev) { 155 char buffer[strerror_buff_size]; 156 if (::strerror_s(buffer, strerror_buff_size, ev) == 0) 157 return string(buffer); 158 std::snprintf(buffer, strerror_buff_size, "unknown error %d", ev); 159 return string(buffer); 160 } 161 # else 162 163 // Only one of the two following functions will be used, depending on 164 // the return type of strerror_r: 165 166 // For the GNU variant, a char* return value: 167 __attribute__((unused)) const char* handle_strerror_r_return(char* strerror_return, char* buffer) { 168 // GNU always returns a string pointer in its return value. The 169 // string might point to either the input buffer, or a static 170 // buffer, but we don't care which. 171 return strerror_return; 172 } 173 174 // For the POSIX variant: an int return value. 175 __attribute__((unused)) const char* handle_strerror_r_return(int strerror_return, char* buffer) { 176 // The POSIX variant either: 177 // - fills in the provided buffer and returns 0 178 // - returns a positive error value, or 179 // - returns -1 and fills in errno with an error value. 180 if (strerror_return == 0) 181 return buffer; 182 183 // Only handle EINVAL. Other errors abort. 184 int new_errno = strerror_return == -1 ? errno : strerror_return; 185 if (new_errno == EINVAL) 186 return ""; 187 188 _LIBCPP_ASSERT_INTERNAL(new_errno == ERANGE, "unexpected error from ::strerror_r"); 189 // FIXME maybe? 'strerror_buff_size' is likely to exceed the 190 // maximum error size so ERANGE shouldn't be returned. 191 std::abort(); 192 } 193 194 // This function handles both GNU and POSIX variants, dispatching to 195 // one of the two above functions. 196 string do_strerror_r(int ev) { 197 char buffer[strerror_buff_size]; 198 // Preserve errno around the call. (The C++ standard requires that 199 // system_error functions not modify errno). 200 const int old_errno = errno; 201 const char* error_message = handle_strerror_r_return(::strerror_r(ev, buffer, strerror_buff_size), buffer); 202 // If we didn't get any message, print one now. 203 if (!error_message[0]) { 204 std::snprintf(buffer, strerror_buff_size, "Unknown error %d", ev); 205 error_message = buffer; 206 } 207 errno = old_errno; 208 return string(error_message); 209 } 210 # endif 211 212 #endif // _LIBCPP_HAS_THREADS 213 214 string make_error_str(const error_code& ec, string what_arg) { 215 if (ec) { 216 if (!what_arg.empty()) { 217 what_arg += ": "; 218 } 219 what_arg += ec.message(); 220 } 221 return what_arg; 222 } 223 224 string make_error_str(const error_code& ec) { 225 if (ec) { 226 return ec.message(); 227 } 228 return string(); 229 } 230 } // namespace 231 232 string __do_message::message(int ev) const { 233 #if !_LIBCPP_HAS_THREADS 234 return string(::strerror(ev)); 235 #else 236 return do_strerror_r(ev); 237 #endif 238 } 239 240 class _LIBCPP_HIDDEN __generic_error_category : public __do_message { 241 public: 242 virtual const char* name() const noexcept; 243 virtual string message(int ev) const; 244 }; 245 246 const char* __generic_error_category::name() const noexcept { return "generic"; } 247 248 string __generic_error_category::message(int ev) const { 249 #ifdef _LIBCPP_ELAST 250 if (ev > _LIBCPP_ELAST) 251 return string("unspecified generic_category error"); 252 #endif // _LIBCPP_ELAST 253 return __do_message::message(ev); 254 } 255 256 const error_category& generic_category() noexcept { 257 union AvoidDestroyingGenericCategory { 258 __generic_error_category generic_error_category; 259 constexpr explicit AvoidDestroyingGenericCategory() : generic_error_category() {} 260 ~AvoidDestroyingGenericCategory() {} 261 }; 262 constinit static AvoidDestroyingGenericCategory helper; 263 return helper.generic_error_category; 264 } 265 266 class _LIBCPP_HIDDEN __system_error_category : public __do_message { 267 public: 268 virtual const char* name() const noexcept; 269 virtual string message(int ev) const; 270 virtual error_condition default_error_condition(int ev) const noexcept; 271 }; 272 273 const char* __system_error_category::name() const noexcept { return "system"; } 274 275 string __system_error_category::message(int ev) const { 276 #ifdef _LIBCPP_WIN32API 277 std::string result; 278 char* str = nullptr; 279 unsigned long num_chars = ::FormatMessageA( 280 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 281 nullptr, 282 ev, 283 0, 284 reinterpret_cast<char*>(&str), 285 0, 286 nullptr); 287 auto is_whitespace = [](char ch) { return ch == '\n' || ch == '\r' || ch == ' '; }; 288 while (num_chars > 0 && is_whitespace(str[num_chars - 1])) 289 --num_chars; 290 291 if (num_chars) 292 result = std::string(str, num_chars); 293 else 294 result = "Unknown error"; 295 296 LocalFree(str); 297 return result; 298 #else 299 # ifdef _LIBCPP_ELAST 300 if (ev > _LIBCPP_ELAST) 301 return string("unspecified system_category error"); 302 # endif // _LIBCPP_ELAST 303 return __do_message::message(ev); 304 #endif 305 } 306 307 error_condition __system_error_category::default_error_condition(int ev) const noexcept { 308 #ifdef _LIBCPP_WIN32API 309 // Remap windows error codes to generic error codes if possible. 310 if (ev == 0) 311 return error_condition(0, generic_category()); 312 if (auto maybe_errc = __win_err_to_errc(ev)) 313 return error_condition(static_cast<int>(*maybe_errc), generic_category()); 314 return error_condition(ev, system_category()); 315 #else 316 # ifdef _LIBCPP_ELAST 317 if (ev > _LIBCPP_ELAST) 318 return error_condition(ev, system_category()); 319 # endif // _LIBCPP_ELAST 320 return error_condition(ev, generic_category()); 321 #endif 322 } 323 324 const error_category& system_category() noexcept { 325 union AvoidDestroyingSystemCategory { 326 __system_error_category system_error_category; 327 constexpr explicit AvoidDestroyingSystemCategory() : system_error_category() {} 328 ~AvoidDestroyingSystemCategory() {} 329 }; 330 constinit static AvoidDestroyingSystemCategory helper; 331 return helper.system_error_category; 332 } 333 334 // error_condition 335 336 string error_condition::message() const { return __cat_->message(__val_); } 337 338 // error_code 339 340 string error_code::message() const { return __cat_->message(__val_); } 341 342 // system_error 343 344 system_error::system_error(error_code ec, const string& what_arg) 345 : runtime_error(make_error_str(ec, what_arg)), __ec_(ec) {} 346 347 system_error::system_error(error_code ec, const char* what_arg) 348 : runtime_error(make_error_str(ec, what_arg)), __ec_(ec) {} 349 350 system_error::system_error(error_code ec) : runtime_error(make_error_str(ec)), __ec_(ec) {} 351 352 system_error::system_error(int ev, const error_category& ecat, const string& what_arg) 353 : runtime_error(make_error_str(error_code(ev, ecat), what_arg)), __ec_(error_code(ev, ecat)) {} 354 355 system_error::system_error(int ev, const error_category& ecat, const char* what_arg) 356 : runtime_error(make_error_str(error_code(ev, ecat), what_arg)), __ec_(error_code(ev, ecat)) {} 357 358 system_error::system_error(int ev, const error_category& ecat) 359 : runtime_error(make_error_str(error_code(ev, ecat))), __ec_(error_code(ev, ecat)) {} 360 361 system_error::~system_error() noexcept {} 362 363 void __throw_system_error(int ev, const char* what_arg) { 364 #if _LIBCPP_HAS_EXCEPTIONS 365 std::__throw_system_error(error_code(ev, generic_category()), what_arg); 366 #else 367 // The above could also handle the no-exception case, but for size, avoid referencing system_category() unnecessarily. 368 _LIBCPP_VERBOSE_ABORT( 369 "system_error was thrown in -fno-exceptions mode with error %i and message \"%s\"", ev, what_arg); 370 #endif 371 } 372 373 _LIBCPP_END_NAMESPACE_STD 374