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