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 <__assert>
10*c9157d92SDimitry Andric #include <__config>
11fe013be4SDimitry Andric #include <__verbose_abort>
1281ad6265SDimitry Andric #include <cerrno>
1381ad6265SDimitry Andric #include <cstdio>
1481ad6265SDimitry Andric #include <cstdlib>
1581ad6265SDimitry Andric #include <cstring>
1681ad6265SDimitry Andric #include <string>
1781ad6265SDimitry Andric #include <string.h>
1881ad6265SDimitry Andric #include <system_error>
190b57cec5SDimitry Andric 
200b57cec5SDimitry Andric #include "include/config_elast.h"
210b57cec5SDimitry Andric 
220b57cec5SDimitry Andric #if defined(__ANDROID__)
230b57cec5SDimitry Andric #include <android/api-level.h>
240b57cec5SDimitry Andric #endif
250b57cec5SDimitry Andric 
260b57cec5SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric namespace {
29*c9157d92SDimitry Andric #if !defined(_LIBCPP_HAS_NO_THREADS)
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric //  GLIBC also uses 1024 as the maximum buffer size internally.
320b57cec5SDimitry Andric constexpr size_t strerror_buff_size = 1024;
330b57cec5SDimitry Andric 
340b57cec5SDimitry Andric string do_strerror_r(int ev);
350b57cec5SDimitry Andric 
360b57cec5SDimitry Andric #if defined(_LIBCPP_MSVCRT_LIKE)
370b57cec5SDimitry Andric string do_strerror_r(int ev) {
380b57cec5SDimitry Andric   char buffer[strerror_buff_size];
390b57cec5SDimitry Andric   if (::strerror_s(buffer, strerror_buff_size, ev) == 0)
400b57cec5SDimitry Andric     return string(buffer);
410b57cec5SDimitry Andric   std::snprintf(buffer, strerror_buff_size, "unknown error %d", ev);
420b57cec5SDimitry Andric   return string(buffer);
430b57cec5SDimitry Andric }
440b57cec5SDimitry Andric #else
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric // Only one of the two following functions will be used, depending on
470b57cec5SDimitry Andric // the return type of strerror_r:
480b57cec5SDimitry Andric 
490b57cec5SDimitry Andric // For the GNU variant, a char* return value:
500b57cec5SDimitry Andric __attribute__((unused)) const char *
510b57cec5SDimitry Andric handle_strerror_r_return(char *strerror_return, char *buffer) {
520b57cec5SDimitry Andric   // GNU always returns a string pointer in its return value. The
530b57cec5SDimitry Andric   // string might point to either the input buffer, or a static
540b57cec5SDimitry Andric   // buffer, but we don't care which.
550b57cec5SDimitry Andric   return strerror_return;
560b57cec5SDimitry Andric }
570b57cec5SDimitry Andric 
580b57cec5SDimitry Andric // For the POSIX variant: an int return value.
590b57cec5SDimitry Andric __attribute__((unused)) const char *
600b57cec5SDimitry Andric handle_strerror_r_return(int strerror_return, char *buffer) {
610b57cec5SDimitry Andric   // The POSIX variant either:
620b57cec5SDimitry Andric   // - fills in the provided buffer and returns 0
630b57cec5SDimitry Andric   // - returns a positive error value, or
640b57cec5SDimitry Andric   // - returns -1 and fills in errno with an error value.
650b57cec5SDimitry Andric   if (strerror_return == 0)
660b57cec5SDimitry Andric     return buffer;
670b57cec5SDimitry Andric 
680b57cec5SDimitry Andric   // Only handle EINVAL. Other errors abort.
690b57cec5SDimitry Andric   int new_errno = strerror_return == -1 ? errno : strerror_return;
700b57cec5SDimitry Andric   if (new_errno == EINVAL)
710b57cec5SDimitry Andric     return "";
720b57cec5SDimitry Andric 
73fe013be4SDimitry Andric   _LIBCPP_ASSERT_UNCATEGORIZED(new_errno == ERANGE, "unexpected error from ::strerror_r");
740b57cec5SDimitry Andric   // FIXME maybe? 'strerror_buff_size' is likely to exceed the
750b57cec5SDimitry Andric   // maximum error size so ERANGE shouldn't be returned.
760b57cec5SDimitry Andric   std::abort();
770b57cec5SDimitry Andric }
780b57cec5SDimitry Andric 
790b57cec5SDimitry Andric // This function handles both GNU and POSIX variants, dispatching to
800b57cec5SDimitry Andric // one of the two above functions.
810b57cec5SDimitry Andric string do_strerror_r(int ev) {
820b57cec5SDimitry Andric     char buffer[strerror_buff_size];
830b57cec5SDimitry Andric     // Preserve errno around the call. (The C++ standard requires that
840b57cec5SDimitry Andric     // system_error functions not modify errno).
850b57cec5SDimitry Andric     const int old_errno = errno;
860b57cec5SDimitry Andric     const char *error_message = handle_strerror_r_return(
870b57cec5SDimitry Andric         ::strerror_r(ev, buffer, strerror_buff_size), buffer);
880b57cec5SDimitry Andric     // If we didn't get any message, print one now.
890b57cec5SDimitry Andric     if (!error_message[0]) {
900b57cec5SDimitry Andric       std::snprintf(buffer, strerror_buff_size, "Unknown error %d", ev);
910b57cec5SDimitry Andric       error_message = buffer;
920b57cec5SDimitry Andric     }
930b57cec5SDimitry Andric     errno = old_errno;
940b57cec5SDimitry Andric     return string(error_message);
950b57cec5SDimitry Andric }
960b57cec5SDimitry Andric #endif
97*c9157d92SDimitry Andric 
98*c9157d92SDimitry Andric #endif // !defined(_LIBCPP_HAS_NO_THREADS)
99*c9157d92SDimitry Andric 
100*c9157d92SDimitry Andric string make_error_str(const error_code& ec, string what_arg) {
101*c9157d92SDimitry Andric     if (ec) {
102*c9157d92SDimitry Andric         if (!what_arg.empty()) {
103*c9157d92SDimitry Andric             what_arg += ": ";
104*c9157d92SDimitry Andric         }
105*c9157d92SDimitry Andric         what_arg += ec.message();
106*c9157d92SDimitry Andric     }
107*c9157d92SDimitry Andric     return what_arg;
108*c9157d92SDimitry Andric }
109*c9157d92SDimitry Andric 
110*c9157d92SDimitry Andric string make_error_str(const error_code& ec) {
111*c9157d92SDimitry Andric     if (ec) {
112*c9157d92SDimitry Andric         return ec.message();
113*c9157d92SDimitry Andric     }
114*c9157d92SDimitry Andric     return string();
115*c9157d92SDimitry Andric }
1160b57cec5SDimitry Andric } // end namespace
1170b57cec5SDimitry Andric 
1180b57cec5SDimitry Andric string
1190b57cec5SDimitry Andric __do_message::message(int ev) const
1200b57cec5SDimitry Andric {
1210b57cec5SDimitry Andric #if defined(_LIBCPP_HAS_NO_THREADS)
1220b57cec5SDimitry Andric     return string(::strerror(ev));
1230b57cec5SDimitry Andric #else
1240b57cec5SDimitry Andric     return do_strerror_r(ev);
1250b57cec5SDimitry Andric #endif
1260b57cec5SDimitry Andric }
1270b57cec5SDimitry Andric 
1280b57cec5SDimitry Andric class _LIBCPP_HIDDEN __generic_error_category
1290b57cec5SDimitry Andric     : public __do_message
1300b57cec5SDimitry Andric {
1310b57cec5SDimitry Andric public:
132fe6060f1SDimitry Andric     virtual const char* name() const noexcept;
1330b57cec5SDimitry Andric     virtual string message(int ev) const;
1340b57cec5SDimitry Andric };
1350b57cec5SDimitry Andric 
1360b57cec5SDimitry Andric const char*
137fe6060f1SDimitry Andric __generic_error_category::name() const noexcept
1380b57cec5SDimitry Andric {
1390b57cec5SDimitry Andric     return "generic";
1400b57cec5SDimitry Andric }
1410b57cec5SDimitry Andric 
1420b57cec5SDimitry Andric string
1430b57cec5SDimitry Andric __generic_error_category::message(int ev) const
1440b57cec5SDimitry Andric {
1450b57cec5SDimitry Andric #ifdef _LIBCPP_ELAST
1460b57cec5SDimitry Andric     if (ev > _LIBCPP_ELAST)
1470b57cec5SDimitry Andric       return string("unspecified generic_category error");
1480b57cec5SDimitry Andric #endif // _LIBCPP_ELAST
1490b57cec5SDimitry Andric     return __do_message::message(ev);
1500b57cec5SDimitry Andric }
1510b57cec5SDimitry Andric 
1520b57cec5SDimitry Andric const error_category&
153fe6060f1SDimitry Andric generic_category() noexcept
1540b57cec5SDimitry Andric {
155*c9157d92SDimitry Andric     union AvoidDestroyingGenericCategory {
156*c9157d92SDimitry Andric         __generic_error_category generic_error_category;
157*c9157d92SDimitry Andric         constexpr explicit AvoidDestroyingGenericCategory() : generic_error_category() {}
158*c9157d92SDimitry Andric         ~AvoidDestroyingGenericCategory() {}
159*c9157d92SDimitry Andric     };
160*c9157d92SDimitry Andric     constinit static AvoidDestroyingGenericCategory helper;
161*c9157d92SDimitry Andric     return helper.generic_error_category;
1620b57cec5SDimitry Andric }
1630b57cec5SDimitry Andric 
1640b57cec5SDimitry Andric class _LIBCPP_HIDDEN __system_error_category
1650b57cec5SDimitry Andric     : public __do_message
1660b57cec5SDimitry Andric {
1670b57cec5SDimitry Andric public:
168fe6060f1SDimitry Andric     virtual const char* name() const noexcept;
1690b57cec5SDimitry Andric     virtual string message(int ev) const;
170fe6060f1SDimitry Andric     virtual error_condition default_error_condition(int ev) const noexcept;
1710b57cec5SDimitry Andric };
1720b57cec5SDimitry Andric 
1730b57cec5SDimitry Andric const char*
174fe6060f1SDimitry Andric __system_error_category::name() const noexcept
1750b57cec5SDimitry Andric {
1760b57cec5SDimitry Andric     return "system";
1770b57cec5SDimitry Andric }
1780b57cec5SDimitry Andric 
1790b57cec5SDimitry Andric string
1800b57cec5SDimitry Andric __system_error_category::message(int ev) const
1810b57cec5SDimitry Andric {
1820b57cec5SDimitry Andric #ifdef _LIBCPP_ELAST
1830b57cec5SDimitry Andric     if (ev > _LIBCPP_ELAST)
1840b57cec5SDimitry Andric       return string("unspecified system_category error");
1850b57cec5SDimitry Andric #endif // _LIBCPP_ELAST
1860b57cec5SDimitry Andric     return __do_message::message(ev);
1870b57cec5SDimitry Andric }
1880b57cec5SDimitry Andric 
1890b57cec5SDimitry Andric error_condition
190fe6060f1SDimitry Andric __system_error_category::default_error_condition(int ev) const noexcept
1910b57cec5SDimitry Andric {
1920b57cec5SDimitry Andric #ifdef _LIBCPP_ELAST
1930b57cec5SDimitry Andric     if (ev > _LIBCPP_ELAST)
1940b57cec5SDimitry Andric       return error_condition(ev, system_category());
1950b57cec5SDimitry Andric #endif // _LIBCPP_ELAST
1960b57cec5SDimitry Andric     return error_condition(ev, generic_category());
1970b57cec5SDimitry Andric }
1980b57cec5SDimitry Andric 
1990b57cec5SDimitry Andric const error_category&
200fe6060f1SDimitry Andric system_category() noexcept
2010b57cec5SDimitry Andric {
202*c9157d92SDimitry Andric     union AvoidDestroyingSystemCategory {
203*c9157d92SDimitry Andric         __system_error_category system_error_category;
204*c9157d92SDimitry Andric         constexpr explicit AvoidDestroyingSystemCategory() : system_error_category() {}
205*c9157d92SDimitry Andric         ~AvoidDestroyingSystemCategory() {}
206*c9157d92SDimitry Andric     };
207*c9157d92SDimitry Andric     constinit static AvoidDestroyingSystemCategory helper;
208*c9157d92SDimitry Andric     return helper.system_error_category;
2090b57cec5SDimitry Andric }
2100b57cec5SDimitry Andric 
2110b57cec5SDimitry Andric // error_condition
2120b57cec5SDimitry Andric 
2130b57cec5SDimitry Andric string
2140b57cec5SDimitry Andric error_condition::message() const
2150b57cec5SDimitry Andric {
2160b57cec5SDimitry Andric     return __cat_->message(__val_);
2170b57cec5SDimitry Andric }
2180b57cec5SDimitry Andric 
2190b57cec5SDimitry Andric // error_code
2200b57cec5SDimitry Andric 
2210b57cec5SDimitry Andric string
2220b57cec5SDimitry Andric error_code::message() const
2230b57cec5SDimitry Andric {
2240b57cec5SDimitry Andric     return __cat_->message(__val_);
2250b57cec5SDimitry Andric }
2260b57cec5SDimitry Andric 
2270b57cec5SDimitry Andric // system_error
2280b57cec5SDimitry Andric 
2290b57cec5SDimitry Andric system_error::system_error(error_code ec, const string& what_arg)
230*c9157d92SDimitry Andric     : runtime_error(make_error_str(ec, what_arg)),
2310b57cec5SDimitry Andric       __ec_(ec)
2320b57cec5SDimitry Andric {
2330b57cec5SDimitry Andric }
2340b57cec5SDimitry Andric 
2350b57cec5SDimitry Andric system_error::system_error(error_code ec, const char* what_arg)
236*c9157d92SDimitry Andric     : runtime_error(make_error_str(ec, what_arg)),
2370b57cec5SDimitry Andric       __ec_(ec)
2380b57cec5SDimitry Andric {
2390b57cec5SDimitry Andric }
2400b57cec5SDimitry Andric 
2410b57cec5SDimitry Andric system_error::system_error(error_code ec)
242*c9157d92SDimitry Andric     : runtime_error(make_error_str(ec)),
2430b57cec5SDimitry Andric       __ec_(ec)
2440b57cec5SDimitry Andric {
2450b57cec5SDimitry Andric }
2460b57cec5SDimitry Andric 
2470b57cec5SDimitry Andric system_error::system_error(int ev, const error_category& ecat, const string& what_arg)
248*c9157d92SDimitry Andric     : runtime_error(make_error_str(error_code(ev, ecat), what_arg)),
2490b57cec5SDimitry Andric       __ec_(error_code(ev, ecat))
2500b57cec5SDimitry Andric {
2510b57cec5SDimitry Andric }
2520b57cec5SDimitry Andric 
2530b57cec5SDimitry Andric system_error::system_error(int ev, const error_category& ecat, const char* what_arg)
254*c9157d92SDimitry Andric     : runtime_error(make_error_str(error_code(ev, ecat), what_arg)),
2550b57cec5SDimitry Andric       __ec_(error_code(ev, ecat))
2560b57cec5SDimitry Andric {
2570b57cec5SDimitry Andric }
2580b57cec5SDimitry Andric 
2590b57cec5SDimitry Andric system_error::system_error(int ev, const error_category& ecat)
260*c9157d92SDimitry Andric     : runtime_error(make_error_str(error_code(ev, ecat))),
2610b57cec5SDimitry Andric       __ec_(error_code(ev, ecat))
2620b57cec5SDimitry Andric {
2630b57cec5SDimitry Andric }
2640b57cec5SDimitry Andric 
265fe6060f1SDimitry Andric system_error::~system_error() noexcept
2660b57cec5SDimitry Andric {
2670b57cec5SDimitry Andric }
2680b57cec5SDimitry Andric 
2690b57cec5SDimitry Andric void
2700b57cec5SDimitry Andric __throw_system_error(int ev, const char* what_arg)
2710b57cec5SDimitry Andric {
272fe013be4SDimitry Andric #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
273*c9157d92SDimitry Andric     std::__throw_system_error(error_code(ev, system_category()), what_arg);
2740b57cec5SDimitry Andric #else
275*c9157d92SDimitry Andric     // The above could also handle the no-exception case, but for size, avoid referencing system_category() unnecessarily.
276fe013be4SDimitry Andric     _LIBCPP_VERBOSE_ABORT("system_error was thrown in -fno-exceptions mode with error %i and message \"%s\"", ev, what_arg);
2770b57cec5SDimitry Andric #endif
2780b57cec5SDimitry Andric }
2790b57cec5SDimitry Andric 
2800b57cec5SDimitry Andric _LIBCPP_END_NAMESPACE_STD
281