17a984708SDavid Chisnall //===---------------------- system_error.cpp ------------------------------===//
27a984708SDavid Chisnall //
37a984708SDavid Chisnall //                     The LLVM Compiler Infrastructure
47a984708SDavid Chisnall //
57a984708SDavid Chisnall // This file is dual licensed under the MIT and the University of Illinois Open
67a984708SDavid Chisnall // Source Licenses. See LICENSE.TXT for details.
77a984708SDavid Chisnall //
87a984708SDavid Chisnall //===----------------------------------------------------------------------===//
97a984708SDavid Chisnall 
10d72607e9SDimitry Andric #include "__config"
11854fa44bSDimitry Andric 
127a984708SDavid Chisnall #include "system_error"
13854fa44bSDimitry Andric 
149729cf09SDimitry Andric #include "include/config_elast.h"
157c82a1ecSDimitry Andric #include "cerrno"
167a984708SDavid Chisnall #include "cstring"
177c82a1ecSDimitry Andric #include "cstdio"
187c82a1ecSDimitry Andric #include "cstdlib"
19854fa44bSDimitry Andric #include "string"
207c82a1ecSDimitry Andric #include "string.h"
21540d2a8bSDimitry Andric #include "__debug"
227c82a1ecSDimitry Andric 
237c82a1ecSDimitry Andric #if defined(__ANDROID__)
247c82a1ecSDimitry Andric #include <android/api-level.h>
257c82a1ecSDimitry Andric #endif
267a984708SDavid Chisnall 
277a984708SDavid Chisnall _LIBCPP_BEGIN_NAMESPACE_STD
287a984708SDavid Chisnall 
297a984708SDavid Chisnall // class error_category
307a984708SDavid Chisnall 
31540d2a8bSDimitry Andric #if defined(_LIBCPP_DEPRECATED_ABI_LEGACY_LIBRARY_DEFINITIONS_FOR_INLINE_FUNCTIONS)
error_category()327a984708SDavid Chisnall error_category::error_category() _NOEXCEPT
337a984708SDavid Chisnall {
347a984708SDavid Chisnall }
35aed8d94eSDimitry Andric #endif
367a984708SDavid Chisnall 
~error_category()377a984708SDavid Chisnall error_category::~error_category() _NOEXCEPT
387a984708SDavid Chisnall {
397a984708SDavid Chisnall }
407a984708SDavid Chisnall 
417a984708SDavid Chisnall error_condition
default_error_condition(int ev) const427a984708SDavid Chisnall error_category::default_error_condition(int ev) const _NOEXCEPT
437a984708SDavid Chisnall {
447a984708SDavid Chisnall     return error_condition(ev, *this);
457a984708SDavid Chisnall }
467a984708SDavid Chisnall 
477a984708SDavid Chisnall bool
equivalent(int code,const error_condition & condition) const487a984708SDavid Chisnall error_category::equivalent(int code, const error_condition& condition) const _NOEXCEPT
497a984708SDavid Chisnall {
507a984708SDavid Chisnall     return default_error_condition(code) == condition;
517a984708SDavid Chisnall }
527a984708SDavid Chisnall 
537a984708SDavid Chisnall bool
equivalent(const error_code & code,int condition) const547a984708SDavid Chisnall error_category::equivalent(const error_code& code, int condition) const _NOEXCEPT
557a984708SDavid Chisnall {
567a984708SDavid Chisnall     return *this == code.category() && code.value() == condition;
577a984708SDavid Chisnall }
587a984708SDavid Chisnall 
59aed8d94eSDimitry Andric #if !defined(_LIBCPP_HAS_NO_THREADS)
607c82a1ecSDimitry Andric namespace {
617c82a1ecSDimitry Andric 
627c82a1ecSDimitry Andric //  GLIBC also uses 1024 as the maximum buffer size internally.
637c82a1ecSDimitry Andric constexpr size_t strerror_buff_size = 1024;
647c82a1ecSDimitry Andric 
657c82a1ecSDimitry Andric string do_strerror_r(int ev);
667c82a1ecSDimitry Andric 
67f9448bf3SDimitry Andric #if defined(_LIBCPP_MSVCRT_LIKE)
do_strerror_r(int ev)68aed8d94eSDimitry Andric string do_strerror_r(int ev) {
69aed8d94eSDimitry Andric   char buffer[strerror_buff_size];
70aed8d94eSDimitry Andric   if (::strerror_s(buffer, strerror_buff_size, ev) == 0)
71aed8d94eSDimitry Andric     return string(buffer);
72aed8d94eSDimitry Andric   std::snprintf(buffer, strerror_buff_size, "unknown error %d", ev);
73aed8d94eSDimitry Andric   return string(buffer);
74aed8d94eSDimitry Andric }
757c82a1ecSDimitry Andric #else
76b2c7081bSDimitry Andric 
77b2c7081bSDimitry Andric // Only one of the two following functions will be used, depending on
78b2c7081bSDimitry Andric // the return type of strerror_r:
79b2c7081bSDimitry Andric 
80b2c7081bSDimitry Andric // For the GNU variant, a char* return value:
81b2c7081bSDimitry Andric __attribute__((unused)) const char *
handle_strerror_r_return(char * strerror_return,char * buffer)82b2c7081bSDimitry Andric handle_strerror_r_return(char *strerror_return, char *buffer) {
83b2c7081bSDimitry Andric   // GNU always returns a string pointer in its return value. The
84b2c7081bSDimitry Andric   // string might point to either the input buffer, or a static
85b2c7081bSDimitry Andric   // buffer, but we don't care which.
86b2c7081bSDimitry Andric   return strerror_return;
87b2c7081bSDimitry Andric }
88b2c7081bSDimitry Andric 
89b2c7081bSDimitry Andric // For the POSIX variant: an int return value.
90b2c7081bSDimitry Andric __attribute__((unused)) const char *
handle_strerror_r_return(int strerror_return,char * buffer)91b2c7081bSDimitry Andric handle_strerror_r_return(int strerror_return, char *buffer) {
92b2c7081bSDimitry Andric   // The POSIX variant either:
93b2c7081bSDimitry Andric   // - fills in the provided buffer and returns 0
94b2c7081bSDimitry Andric   // - returns a positive error value, or
95b2c7081bSDimitry Andric   // - returns -1 and fills in errno with an error value.
96b2c7081bSDimitry Andric   if (strerror_return == 0)
97b2c7081bSDimitry Andric     return buffer;
98b2c7081bSDimitry Andric 
99b2c7081bSDimitry Andric   // Only handle EINVAL. Other errors abort.
100b2c7081bSDimitry Andric   int new_errno = strerror_return == -1 ? errno : strerror_return;
101b2c7081bSDimitry Andric   if (new_errno == EINVAL)
102b2c7081bSDimitry Andric     return "";
103b2c7081bSDimitry Andric 
104b2c7081bSDimitry Andric   _LIBCPP_ASSERT(new_errno == ERANGE, "unexpected error from ::strerror_r");
1057c82a1ecSDimitry Andric   // FIXME maybe? 'strerror_buff_size' is likely to exceed the
1067c82a1ecSDimitry Andric   // maximum error size so ERANGE shouldn't be returned.
1077c82a1ecSDimitry Andric   std::abort();
1087c82a1ecSDimitry Andric }
109b2c7081bSDimitry Andric 
110b2c7081bSDimitry Andric // This function handles both GNU and POSIX variants, dispatching to
111b2c7081bSDimitry Andric // one of the two above functions.
do_strerror_r(int ev)112b2c7081bSDimitry Andric string do_strerror_r(int ev) {
113b2c7081bSDimitry Andric     char buffer[strerror_buff_size];
114b2c7081bSDimitry Andric     // Preserve errno around the call. (The C++ standard requires that
115b2c7081bSDimitry Andric     // system_error functions not modify errno).
116b2c7081bSDimitry Andric     const int old_errno = errno;
117b2c7081bSDimitry Andric     const char *error_message = handle_strerror_r_return(
118b2c7081bSDimitry Andric         ::strerror_r(ev, buffer, strerror_buff_size), buffer);
119b2c7081bSDimitry Andric     // If we didn't get any message, print one now.
120b2c7081bSDimitry Andric     if (!error_message[0]) {
121b2c7081bSDimitry Andric       std::snprintf(buffer, strerror_buff_size, "Unknown error %d", ev);
122b2c7081bSDimitry Andric       error_message = buffer;
1237c82a1ecSDimitry Andric     }
124b2c7081bSDimitry Andric     errno = old_errno;
125b2c7081bSDimitry Andric     return string(error_message);
1267c82a1ecSDimitry Andric }
1277c82a1ecSDimitry Andric #endif
1287c82a1ecSDimitry Andric } // end namespace
129aed8d94eSDimitry Andric #endif
1307c82a1ecSDimitry Andric 
1317a984708SDavid Chisnall string
message(int ev) const1327a984708SDavid Chisnall __do_message::message(int ev) const
1337a984708SDavid Chisnall {
1347c82a1ecSDimitry Andric #if defined(_LIBCPP_HAS_NO_THREADS)
1357c82a1ecSDimitry Andric     return string(::strerror(ev));
1367c82a1ecSDimitry Andric #else
1377c82a1ecSDimitry Andric     return do_strerror_r(ev);
1387c82a1ecSDimitry Andric #endif
1397a984708SDavid Chisnall }
1407a984708SDavid Chisnall 
1417a984708SDavid Chisnall class _LIBCPP_HIDDEN __generic_error_category
1427a984708SDavid Chisnall     : public __do_message
1437a984708SDavid Chisnall {
1447a984708SDavid Chisnall public:
1457a984708SDavid Chisnall     virtual const char* name() const _NOEXCEPT;
1467a984708SDavid Chisnall     virtual string message(int ev) const;
1477a984708SDavid Chisnall };
1487a984708SDavid Chisnall 
1497a984708SDavid Chisnall const char*
name() const1507a984708SDavid Chisnall __generic_error_category::name() const _NOEXCEPT
1517a984708SDavid Chisnall {
1527a984708SDavid Chisnall     return "generic";
1537a984708SDavid Chisnall }
1547a984708SDavid Chisnall 
1557a984708SDavid Chisnall string
message(int ev) const1567a984708SDavid Chisnall __generic_error_category::message(int ev) const
1577a984708SDavid Chisnall {
158d72607e9SDimitry Andric #ifdef _LIBCPP_ELAST
159d72607e9SDimitry Andric     if (ev > _LIBCPP_ELAST)
1607a984708SDavid Chisnall       return string("unspecified generic_category error");
161d72607e9SDimitry Andric #endif  // _LIBCPP_ELAST
1627a984708SDavid Chisnall     return __do_message::message(ev);
1637a984708SDavid Chisnall }
1647a984708SDavid Chisnall 
1657a984708SDavid Chisnall const error_category&
generic_category()1667a984708SDavid Chisnall generic_category() _NOEXCEPT
1677a984708SDavid Chisnall {
1687a984708SDavid Chisnall     static __generic_error_category s;
1697a984708SDavid Chisnall     return s;
1707a984708SDavid Chisnall }
1717a984708SDavid Chisnall 
1727a984708SDavid Chisnall class _LIBCPP_HIDDEN __system_error_category
1737a984708SDavid Chisnall     : public __do_message
1747a984708SDavid Chisnall {
1757a984708SDavid Chisnall public:
1767a984708SDavid Chisnall     virtual const char* name() const _NOEXCEPT;
1777a984708SDavid Chisnall     virtual string message(int ev) const;
1787a984708SDavid Chisnall     virtual error_condition default_error_condition(int ev) const _NOEXCEPT;
1797a984708SDavid Chisnall };
1807a984708SDavid Chisnall 
1817a984708SDavid Chisnall const char*
name() const1827a984708SDavid Chisnall __system_error_category::name() const _NOEXCEPT
1837a984708SDavid Chisnall {
1847a984708SDavid Chisnall     return "system";
1857a984708SDavid Chisnall }
1867a984708SDavid Chisnall 
1877a984708SDavid Chisnall string
message(int ev) const1887a984708SDavid Chisnall __system_error_category::message(int ev) const
1897a984708SDavid Chisnall {
190d72607e9SDimitry Andric #ifdef _LIBCPP_ELAST
191d72607e9SDimitry Andric     if (ev > _LIBCPP_ELAST)
1927a984708SDavid Chisnall       return string("unspecified system_category error");
193d72607e9SDimitry Andric #endif  // _LIBCPP_ELAST
1947a984708SDavid Chisnall     return __do_message::message(ev);
1957a984708SDavid Chisnall }
1967a984708SDavid Chisnall 
1977a984708SDavid Chisnall error_condition
default_error_condition(int ev) const1987a984708SDavid Chisnall __system_error_category::default_error_condition(int ev) const _NOEXCEPT
1997a984708SDavid Chisnall {
200d72607e9SDimitry Andric #ifdef _LIBCPP_ELAST
201d72607e9SDimitry Andric     if (ev > _LIBCPP_ELAST)
2027a984708SDavid Chisnall       return error_condition(ev, system_category());
203d72607e9SDimitry Andric #endif  // _LIBCPP_ELAST
2047a984708SDavid Chisnall     return error_condition(ev, generic_category());
2057a984708SDavid Chisnall }
2067a984708SDavid Chisnall 
2077a984708SDavid Chisnall const error_category&
system_category()2087a984708SDavid Chisnall system_category() _NOEXCEPT
2097a984708SDavid Chisnall {
2107a984708SDavid Chisnall     static __system_error_category s;
2117a984708SDavid Chisnall     return s;
2127a984708SDavid Chisnall }
2137a984708SDavid Chisnall 
2147a984708SDavid Chisnall // error_condition
2157a984708SDavid Chisnall 
2167a984708SDavid Chisnall string
message() const2177a984708SDavid Chisnall error_condition::message() const
2187a984708SDavid Chisnall {
2197a984708SDavid Chisnall     return __cat_->message(__val_);
2207a984708SDavid Chisnall }
2217a984708SDavid Chisnall 
2227a984708SDavid Chisnall // error_code
2237a984708SDavid Chisnall 
2247a984708SDavid Chisnall string
message() const2257a984708SDavid Chisnall error_code::message() const
2267a984708SDavid Chisnall {
2277a984708SDavid Chisnall     return __cat_->message(__val_);
2287a984708SDavid Chisnall }
2297a984708SDavid Chisnall 
2307a984708SDavid Chisnall // system_error
2317a984708SDavid Chisnall 
2327a984708SDavid Chisnall string
__init(const error_code & ec,string what_arg)2337a984708SDavid Chisnall system_error::__init(const error_code& ec, string what_arg)
2347a984708SDavid Chisnall {
2357a984708SDavid Chisnall     if (ec)
2367a984708SDavid Chisnall     {
2377a984708SDavid Chisnall         if (!what_arg.empty())
2387a984708SDavid Chisnall             what_arg += ": ";
2397a984708SDavid Chisnall         what_arg += ec.message();
2407a984708SDavid Chisnall     }
241854fa44bSDimitry Andric     return what_arg;
2427a984708SDavid Chisnall }
2437a984708SDavid Chisnall 
system_error(error_code ec,const string & what_arg)2447a984708SDavid Chisnall system_error::system_error(error_code ec, const string& what_arg)
2457a984708SDavid Chisnall     : runtime_error(__init(ec, what_arg)),
2467a984708SDavid Chisnall       __ec_(ec)
2477a984708SDavid Chisnall {
2487a984708SDavid Chisnall }
2497a984708SDavid Chisnall 
system_error(error_code ec,const char * what_arg)2507a984708SDavid Chisnall system_error::system_error(error_code ec, const char* what_arg)
2517a984708SDavid Chisnall     : runtime_error(__init(ec, what_arg)),
2527a984708SDavid Chisnall       __ec_(ec)
2537a984708SDavid Chisnall {
2547a984708SDavid Chisnall }
2557a984708SDavid Chisnall 
system_error(error_code ec)2567a984708SDavid Chisnall system_error::system_error(error_code ec)
2577a984708SDavid Chisnall     : runtime_error(__init(ec, "")),
2587a984708SDavid Chisnall       __ec_(ec)
2597a984708SDavid Chisnall {
2607a984708SDavid Chisnall }
2617a984708SDavid Chisnall 
system_error(int ev,const error_category & ecat,const string & what_arg)2627a984708SDavid Chisnall system_error::system_error(int ev, const error_category& ecat, const string& what_arg)
2637a984708SDavid Chisnall     : runtime_error(__init(error_code(ev, ecat), what_arg)),
2647a984708SDavid Chisnall       __ec_(error_code(ev, ecat))
2657a984708SDavid Chisnall {
2667a984708SDavid Chisnall }
2677a984708SDavid Chisnall 
system_error(int ev,const error_category & ecat,const char * what_arg)2687a984708SDavid Chisnall system_error::system_error(int ev, const error_category& ecat, const char* what_arg)
2697a984708SDavid Chisnall     : runtime_error(__init(error_code(ev, ecat), what_arg)),
2707a984708SDavid Chisnall       __ec_(error_code(ev, ecat))
2717a984708SDavid Chisnall {
2727a984708SDavid Chisnall }
2737a984708SDavid Chisnall 
system_error(int ev,const error_category & ecat)2747a984708SDavid Chisnall system_error::system_error(int ev, const error_category& ecat)
2757a984708SDavid Chisnall     : runtime_error(__init(error_code(ev, ecat), "")),
2767a984708SDavid Chisnall       __ec_(error_code(ev, ecat))
2777a984708SDavid Chisnall {
2787a984708SDavid Chisnall }
2797a984708SDavid Chisnall 
~system_error()2807a984708SDavid Chisnall system_error::~system_error() _NOEXCEPT
2817a984708SDavid Chisnall {
2827a984708SDavid Chisnall }
2837a984708SDavid Chisnall 
2847a984708SDavid Chisnall void
__throw_system_error(int ev,const char * what_arg)2857a984708SDavid Chisnall __throw_system_error(int ev, const char* what_arg)
2867a984708SDavid Chisnall {
2877a984708SDavid Chisnall #ifndef _LIBCPP_NO_EXCEPTIONS
2887a984708SDavid Chisnall     throw system_error(error_code(ev, system_category()), what_arg);
2891bf9f7c1SDimitry Andric #else
2901bf9f7c1SDimitry Andric     (void)ev;
2911bf9f7c1SDimitry Andric     (void)what_arg;
292aed8d94eSDimitry Andric     _VSTD::abort();
2937a984708SDavid Chisnall #endif
2947a984708SDavid Chisnall }
2957a984708SDavid Chisnall 
2967a984708SDavid Chisnall _LIBCPP_END_NAMESPACE_STD
297