1349cc55cSDimitry Andric //===----------------------------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
981ad6265SDimitry Andric #include <__config>
1081ad6265SDimitry Andric #ifdef _LIBCPP_DEPRECATED_ABI_LEGACY_LIBRARY_DEFINITIONS_FOR_INLINE_FUNCTIONS
1181ad6265SDimitry Andric #   define _LIBCPP_ERROR_CATEGORY_DEFINE_LEGACY_INLINE_FUNCTIONS
1281ad6265SDimitry Andric #endif
130b57cec5SDimitry Andric 
1481ad6265SDimitry Andric #include <__assert>
15*fe013be4SDimitry Andric #include <__verbose_abort>
1681ad6265SDimitry Andric #include <cerrno>
1781ad6265SDimitry Andric #include <cstdio>
1881ad6265SDimitry Andric #include <cstdlib>
1981ad6265SDimitry Andric #include <cstring>
2081ad6265SDimitry Andric #include <string>
2181ad6265SDimitry Andric #include <string.h>
2281ad6265SDimitry Andric #include <system_error>
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric #include "include/config_elast.h"
250b57cec5SDimitry Andric 
260b57cec5SDimitry Andric #if defined(__ANDROID__)
270b57cec5SDimitry Andric #include <android/api-level.h>
280b57cec5SDimitry Andric #endif
290b57cec5SDimitry Andric 
300b57cec5SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD
310b57cec5SDimitry Andric 
320b57cec5SDimitry Andric // class error_category
330b57cec5SDimitry Andric 
3481ad6265SDimitry Andric #if defined(_LIBCPP_ERROR_CATEGORY_DEFINE_LEGACY_INLINE_FUNCTIONS)
35fe6060f1SDimitry Andric error_category::error_category() noexcept
360b57cec5SDimitry Andric {
370b57cec5SDimitry Andric }
380b57cec5SDimitry Andric #endif
390b57cec5SDimitry Andric 
40fe6060f1SDimitry Andric error_category::~error_category() noexcept
410b57cec5SDimitry Andric {
420b57cec5SDimitry Andric }
430b57cec5SDimitry Andric 
440b57cec5SDimitry Andric error_condition
45fe6060f1SDimitry Andric error_category::default_error_condition(int ev) const noexcept
460b57cec5SDimitry Andric {
470b57cec5SDimitry Andric     return error_condition(ev, *this);
480b57cec5SDimitry Andric }
490b57cec5SDimitry Andric 
500b57cec5SDimitry Andric bool
51fe6060f1SDimitry Andric error_category::equivalent(int code, const error_condition& condition) const noexcept
520b57cec5SDimitry Andric {
530b57cec5SDimitry Andric     return default_error_condition(code) == condition;
540b57cec5SDimitry Andric }
550b57cec5SDimitry Andric 
560b57cec5SDimitry Andric bool
57fe6060f1SDimitry Andric error_category::equivalent(const error_code& code, int condition) const noexcept
580b57cec5SDimitry Andric {
590b57cec5SDimitry Andric     return *this == code.category() && code.value() == condition;
600b57cec5SDimitry Andric }
610b57cec5SDimitry Andric 
620b57cec5SDimitry Andric #if !defined(_LIBCPP_HAS_NO_THREADS)
630b57cec5SDimitry Andric namespace {
640b57cec5SDimitry Andric 
650b57cec5SDimitry Andric //  GLIBC also uses 1024 as the maximum buffer size internally.
660b57cec5SDimitry Andric constexpr size_t strerror_buff_size = 1024;
670b57cec5SDimitry Andric 
680b57cec5SDimitry Andric string do_strerror_r(int ev);
690b57cec5SDimitry Andric 
700b57cec5SDimitry Andric #if defined(_LIBCPP_MSVCRT_LIKE)
710b57cec5SDimitry Andric string do_strerror_r(int ev) {
720b57cec5SDimitry Andric   char buffer[strerror_buff_size];
730b57cec5SDimitry Andric   if (::strerror_s(buffer, strerror_buff_size, ev) == 0)
740b57cec5SDimitry Andric     return string(buffer);
750b57cec5SDimitry Andric   std::snprintf(buffer, strerror_buff_size, "unknown error %d", ev);
760b57cec5SDimitry Andric   return string(buffer);
770b57cec5SDimitry Andric }
780b57cec5SDimitry Andric #else
790b57cec5SDimitry Andric 
800b57cec5SDimitry Andric // Only one of the two following functions will be used, depending on
810b57cec5SDimitry Andric // the return type of strerror_r:
820b57cec5SDimitry Andric 
830b57cec5SDimitry Andric // For the GNU variant, a char* return value:
840b57cec5SDimitry Andric __attribute__((unused)) const char *
850b57cec5SDimitry Andric handle_strerror_r_return(char *strerror_return, char *buffer) {
860b57cec5SDimitry Andric   // GNU always returns a string pointer in its return value. The
870b57cec5SDimitry Andric   // string might point to either the input buffer, or a static
880b57cec5SDimitry Andric   // buffer, but we don't care which.
890b57cec5SDimitry Andric   return strerror_return;
900b57cec5SDimitry Andric }
910b57cec5SDimitry Andric 
920b57cec5SDimitry Andric // For the POSIX variant: an int return value.
930b57cec5SDimitry Andric __attribute__((unused)) const char *
940b57cec5SDimitry Andric handle_strerror_r_return(int strerror_return, char *buffer) {
950b57cec5SDimitry Andric   // The POSIX variant either:
960b57cec5SDimitry Andric   // - fills in the provided buffer and returns 0
970b57cec5SDimitry Andric   // - returns a positive error value, or
980b57cec5SDimitry Andric   // - returns -1 and fills in errno with an error value.
990b57cec5SDimitry Andric   if (strerror_return == 0)
1000b57cec5SDimitry Andric     return buffer;
1010b57cec5SDimitry Andric 
1020b57cec5SDimitry Andric   // Only handle EINVAL. Other errors abort.
1030b57cec5SDimitry Andric   int new_errno = strerror_return == -1 ? errno : strerror_return;
1040b57cec5SDimitry Andric   if (new_errno == EINVAL)
1050b57cec5SDimitry Andric     return "";
1060b57cec5SDimitry Andric 
107*fe013be4SDimitry Andric   _LIBCPP_ASSERT_UNCATEGORIZED(new_errno == ERANGE, "unexpected error from ::strerror_r");
1080b57cec5SDimitry Andric   // FIXME maybe? 'strerror_buff_size' is likely to exceed the
1090b57cec5SDimitry Andric   // maximum error size so ERANGE shouldn't be returned.
1100b57cec5SDimitry Andric   std::abort();
1110b57cec5SDimitry Andric }
1120b57cec5SDimitry Andric 
1130b57cec5SDimitry Andric // This function handles both GNU and POSIX variants, dispatching to
1140b57cec5SDimitry Andric // one of the two above functions.
1150b57cec5SDimitry Andric string do_strerror_r(int ev) {
1160b57cec5SDimitry Andric     char buffer[strerror_buff_size];
1170b57cec5SDimitry Andric     // Preserve errno around the call. (The C++ standard requires that
1180b57cec5SDimitry Andric     // system_error functions not modify errno).
1190b57cec5SDimitry Andric     const int old_errno = errno;
1200b57cec5SDimitry Andric     const char *error_message = handle_strerror_r_return(
1210b57cec5SDimitry Andric         ::strerror_r(ev, buffer, strerror_buff_size), buffer);
1220b57cec5SDimitry Andric     // If we didn't get any message, print one now.
1230b57cec5SDimitry Andric     if (!error_message[0]) {
1240b57cec5SDimitry Andric       std::snprintf(buffer, strerror_buff_size, "Unknown error %d", ev);
1250b57cec5SDimitry Andric       error_message = buffer;
1260b57cec5SDimitry Andric     }
1270b57cec5SDimitry Andric     errno = old_errno;
1280b57cec5SDimitry Andric     return string(error_message);
1290b57cec5SDimitry Andric }
1300b57cec5SDimitry Andric #endif
1310b57cec5SDimitry Andric } // end namespace
1320b57cec5SDimitry Andric #endif
1330b57cec5SDimitry Andric 
1340b57cec5SDimitry Andric string
1350b57cec5SDimitry Andric __do_message::message(int ev) const
1360b57cec5SDimitry Andric {
1370b57cec5SDimitry Andric #if defined(_LIBCPP_HAS_NO_THREADS)
1380b57cec5SDimitry Andric     return string(::strerror(ev));
1390b57cec5SDimitry Andric #else
1400b57cec5SDimitry Andric     return do_strerror_r(ev);
1410b57cec5SDimitry Andric #endif
1420b57cec5SDimitry Andric }
1430b57cec5SDimitry Andric 
1440b57cec5SDimitry Andric class _LIBCPP_HIDDEN __generic_error_category
1450b57cec5SDimitry Andric     : public __do_message
1460b57cec5SDimitry Andric {
1470b57cec5SDimitry Andric public:
148fe6060f1SDimitry Andric     virtual const char* name() const noexcept;
1490b57cec5SDimitry Andric     virtual string message(int ev) const;
1500b57cec5SDimitry Andric };
1510b57cec5SDimitry Andric 
1520b57cec5SDimitry Andric const char*
153fe6060f1SDimitry Andric __generic_error_category::name() const noexcept
1540b57cec5SDimitry Andric {
1550b57cec5SDimitry Andric     return "generic";
1560b57cec5SDimitry Andric }
1570b57cec5SDimitry Andric 
1580b57cec5SDimitry Andric string
1590b57cec5SDimitry Andric __generic_error_category::message(int ev) const
1600b57cec5SDimitry Andric {
1610b57cec5SDimitry Andric #ifdef _LIBCPP_ELAST
1620b57cec5SDimitry Andric     if (ev > _LIBCPP_ELAST)
1630b57cec5SDimitry Andric       return string("unspecified generic_category error");
1640b57cec5SDimitry Andric #endif // _LIBCPP_ELAST
1650b57cec5SDimitry Andric     return __do_message::message(ev);
1660b57cec5SDimitry Andric }
1670b57cec5SDimitry Andric 
1680b57cec5SDimitry Andric const error_category&
169fe6060f1SDimitry Andric generic_category() noexcept
1700b57cec5SDimitry Andric {
1710b57cec5SDimitry Andric     static __generic_error_category s;
1720b57cec5SDimitry Andric     return s;
1730b57cec5SDimitry Andric }
1740b57cec5SDimitry Andric 
1750b57cec5SDimitry Andric class _LIBCPP_HIDDEN __system_error_category
1760b57cec5SDimitry Andric     : public __do_message
1770b57cec5SDimitry Andric {
1780b57cec5SDimitry Andric public:
179fe6060f1SDimitry Andric     virtual const char* name() const noexcept;
1800b57cec5SDimitry Andric     virtual string message(int ev) const;
181fe6060f1SDimitry Andric     virtual error_condition default_error_condition(int ev) const noexcept;
1820b57cec5SDimitry Andric };
1830b57cec5SDimitry Andric 
1840b57cec5SDimitry Andric const char*
185fe6060f1SDimitry Andric __system_error_category::name() const noexcept
1860b57cec5SDimitry Andric {
1870b57cec5SDimitry Andric     return "system";
1880b57cec5SDimitry Andric }
1890b57cec5SDimitry Andric 
1900b57cec5SDimitry Andric string
1910b57cec5SDimitry Andric __system_error_category::message(int ev) const
1920b57cec5SDimitry Andric {
1930b57cec5SDimitry Andric #ifdef _LIBCPP_ELAST
1940b57cec5SDimitry Andric     if (ev > _LIBCPP_ELAST)
1950b57cec5SDimitry Andric       return string("unspecified system_category error");
1960b57cec5SDimitry Andric #endif // _LIBCPP_ELAST
1970b57cec5SDimitry Andric     return __do_message::message(ev);
1980b57cec5SDimitry Andric }
1990b57cec5SDimitry Andric 
2000b57cec5SDimitry Andric error_condition
201fe6060f1SDimitry Andric __system_error_category::default_error_condition(int ev) const noexcept
2020b57cec5SDimitry Andric {
2030b57cec5SDimitry Andric #ifdef _LIBCPP_ELAST
2040b57cec5SDimitry Andric     if (ev > _LIBCPP_ELAST)
2050b57cec5SDimitry Andric       return error_condition(ev, system_category());
2060b57cec5SDimitry Andric #endif // _LIBCPP_ELAST
2070b57cec5SDimitry Andric     return error_condition(ev, generic_category());
2080b57cec5SDimitry Andric }
2090b57cec5SDimitry Andric 
2100b57cec5SDimitry Andric const error_category&
211fe6060f1SDimitry Andric system_category() noexcept
2120b57cec5SDimitry Andric {
2130b57cec5SDimitry Andric     static __system_error_category s;
2140b57cec5SDimitry Andric     return s;
2150b57cec5SDimitry Andric }
2160b57cec5SDimitry Andric 
2170b57cec5SDimitry Andric // error_condition
2180b57cec5SDimitry Andric 
2190b57cec5SDimitry Andric string
2200b57cec5SDimitry Andric error_condition::message() const
2210b57cec5SDimitry Andric {
2220b57cec5SDimitry Andric     return __cat_->message(__val_);
2230b57cec5SDimitry Andric }
2240b57cec5SDimitry Andric 
2250b57cec5SDimitry Andric // error_code
2260b57cec5SDimitry Andric 
2270b57cec5SDimitry Andric string
2280b57cec5SDimitry Andric error_code::message() const
2290b57cec5SDimitry Andric {
2300b57cec5SDimitry Andric     return __cat_->message(__val_);
2310b57cec5SDimitry Andric }
2320b57cec5SDimitry Andric 
2330b57cec5SDimitry Andric // system_error
2340b57cec5SDimitry Andric 
2350b57cec5SDimitry Andric string
2360b57cec5SDimitry Andric system_error::__init(const error_code& ec, string what_arg)
2370b57cec5SDimitry Andric {
2380b57cec5SDimitry Andric     if (ec)
2390b57cec5SDimitry Andric     {
2400b57cec5SDimitry Andric         if (!what_arg.empty())
2410b57cec5SDimitry Andric             what_arg += ": ";
2420b57cec5SDimitry Andric         what_arg += ec.message();
2430b57cec5SDimitry Andric     }
2440b57cec5SDimitry Andric     return what_arg;
2450b57cec5SDimitry Andric }
2460b57cec5SDimitry Andric 
2470b57cec5SDimitry Andric system_error::system_error(error_code ec, const string& what_arg)
2480b57cec5SDimitry Andric     : runtime_error(__init(ec, what_arg)),
2490b57cec5SDimitry Andric       __ec_(ec)
2500b57cec5SDimitry Andric {
2510b57cec5SDimitry Andric }
2520b57cec5SDimitry Andric 
2530b57cec5SDimitry Andric system_error::system_error(error_code ec, const char* what_arg)
2540b57cec5SDimitry Andric     : runtime_error(__init(ec, what_arg)),
2550b57cec5SDimitry Andric       __ec_(ec)
2560b57cec5SDimitry Andric {
2570b57cec5SDimitry Andric }
2580b57cec5SDimitry Andric 
2590b57cec5SDimitry Andric system_error::system_error(error_code ec)
2600b57cec5SDimitry Andric     : runtime_error(__init(ec, "")),
2610b57cec5SDimitry Andric       __ec_(ec)
2620b57cec5SDimitry Andric {
2630b57cec5SDimitry Andric }
2640b57cec5SDimitry Andric 
2650b57cec5SDimitry Andric system_error::system_error(int ev, const error_category& ecat, const string& what_arg)
2660b57cec5SDimitry Andric     : runtime_error(__init(error_code(ev, ecat), what_arg)),
2670b57cec5SDimitry Andric       __ec_(error_code(ev, ecat))
2680b57cec5SDimitry Andric {
2690b57cec5SDimitry Andric }
2700b57cec5SDimitry Andric 
2710b57cec5SDimitry Andric system_error::system_error(int ev, const error_category& ecat, const char* what_arg)
2720b57cec5SDimitry Andric     : runtime_error(__init(error_code(ev, ecat), what_arg)),
2730b57cec5SDimitry Andric       __ec_(error_code(ev, ecat))
2740b57cec5SDimitry Andric {
2750b57cec5SDimitry Andric }
2760b57cec5SDimitry Andric 
2770b57cec5SDimitry Andric system_error::system_error(int ev, const error_category& ecat)
2780b57cec5SDimitry Andric     : runtime_error(__init(error_code(ev, ecat), "")),
2790b57cec5SDimitry Andric       __ec_(error_code(ev, ecat))
2800b57cec5SDimitry Andric {
2810b57cec5SDimitry Andric }
2820b57cec5SDimitry Andric 
283fe6060f1SDimitry Andric system_error::~system_error() noexcept
2840b57cec5SDimitry Andric {
2850b57cec5SDimitry Andric }
2860b57cec5SDimitry Andric 
2870b57cec5SDimitry Andric void
2880b57cec5SDimitry Andric __throw_system_error(int ev, const char* what_arg)
2890b57cec5SDimitry Andric {
290*fe013be4SDimitry Andric #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
2910b57cec5SDimitry Andric     throw system_error(error_code(ev, system_category()), what_arg);
2920b57cec5SDimitry Andric #else
293*fe013be4SDimitry Andric     _LIBCPP_VERBOSE_ABORT("system_error was thrown in -fno-exceptions mode with error %i and message \"%s\"", ev, what_arg);
2940b57cec5SDimitry Andric #endif
2950b57cec5SDimitry Andric }
2960b57cec5SDimitry Andric 
2970b57cec5SDimitry Andric _LIBCPP_END_NAMESPACE_STD
298