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>
10c9157d92SDimitry 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.h>
17*e710425bSDimitry Andric #include <string>
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 {
29c9157d92SDimitry 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:
50*e710425bSDimitry Andric __attribute__((unused)) const char* handle_strerror_r_return(char* strerror_return, char* buffer) {
510b57cec5SDimitry Andric   // GNU always returns a string pointer in its return value. The
520b57cec5SDimitry Andric   // string might point to either the input buffer, or a static
530b57cec5SDimitry Andric   // buffer, but we don't care which.
540b57cec5SDimitry Andric   return strerror_return;
550b57cec5SDimitry Andric }
560b57cec5SDimitry Andric 
570b57cec5SDimitry Andric // For the POSIX variant: an int return value.
58*e710425bSDimitry Andric __attribute__((unused)) const char* handle_strerror_r_return(int strerror_return, char* buffer) {
590b57cec5SDimitry Andric   // The POSIX variant either:
600b57cec5SDimitry Andric   // - fills in the provided buffer and returns 0
610b57cec5SDimitry Andric   // - returns a positive error value, or
620b57cec5SDimitry Andric   // - returns -1 and fills in errno with an error value.
630b57cec5SDimitry Andric   if (strerror_return == 0)
640b57cec5SDimitry Andric     return buffer;
650b57cec5SDimitry Andric 
660b57cec5SDimitry Andric   // Only handle EINVAL. Other errors abort.
670b57cec5SDimitry Andric   int new_errno = strerror_return == -1 ? errno : strerror_return;
680b57cec5SDimitry Andric   if (new_errno == EINVAL)
690b57cec5SDimitry Andric     return "";
700b57cec5SDimitry Andric 
71fe013be4SDimitry Andric   _LIBCPP_ASSERT_UNCATEGORIZED(new_errno == ERANGE, "unexpected error from ::strerror_r");
720b57cec5SDimitry Andric   // FIXME maybe? 'strerror_buff_size' is likely to exceed the
730b57cec5SDimitry Andric   // maximum error size so ERANGE shouldn't be returned.
740b57cec5SDimitry Andric   std::abort();
750b57cec5SDimitry Andric }
760b57cec5SDimitry Andric 
770b57cec5SDimitry Andric // This function handles both GNU and POSIX variants, dispatching to
780b57cec5SDimitry Andric // one of the two above functions.
790b57cec5SDimitry Andric string do_strerror_r(int ev) {
800b57cec5SDimitry Andric   char buffer[strerror_buff_size];
810b57cec5SDimitry Andric   // Preserve errno around the call. (The C++ standard requires that
820b57cec5SDimitry Andric   // system_error functions not modify errno).
830b57cec5SDimitry Andric   const int old_errno       = errno;
84*e710425bSDimitry Andric   const char* error_message = handle_strerror_r_return(::strerror_r(ev, buffer, strerror_buff_size), buffer);
850b57cec5SDimitry Andric   // If we didn't get any message, print one now.
860b57cec5SDimitry Andric   if (!error_message[0]) {
870b57cec5SDimitry Andric     std::snprintf(buffer, strerror_buff_size, "Unknown error %d", ev);
880b57cec5SDimitry Andric     error_message = buffer;
890b57cec5SDimitry Andric   }
900b57cec5SDimitry Andric   errno = old_errno;
910b57cec5SDimitry Andric   return string(error_message);
920b57cec5SDimitry Andric }
930b57cec5SDimitry Andric #  endif
94c9157d92SDimitry Andric 
95c9157d92SDimitry Andric #endif // !defined(_LIBCPP_HAS_NO_THREADS)
96c9157d92SDimitry Andric 
97c9157d92SDimitry Andric string make_error_str(const error_code& ec, string what_arg) {
98c9157d92SDimitry Andric   if (ec) {
99c9157d92SDimitry Andric     if (!what_arg.empty()) {
100c9157d92SDimitry Andric       what_arg += ": ";
101c9157d92SDimitry Andric     }
102c9157d92SDimitry Andric     what_arg += ec.message();
103c9157d92SDimitry Andric   }
104c9157d92SDimitry Andric   return what_arg;
105c9157d92SDimitry Andric }
106c9157d92SDimitry Andric 
107c9157d92SDimitry Andric string make_error_str(const error_code& ec) {
108c9157d92SDimitry Andric   if (ec) {
109c9157d92SDimitry Andric     return ec.message();
110c9157d92SDimitry Andric   }
111c9157d92SDimitry Andric   return string();
112c9157d92SDimitry Andric }
1130b57cec5SDimitry Andric } // end namespace
1140b57cec5SDimitry Andric 
115*e710425bSDimitry Andric string __do_message::message(int ev) const {
1160b57cec5SDimitry Andric #if defined(_LIBCPP_HAS_NO_THREADS)
1170b57cec5SDimitry Andric   return string(::strerror(ev));
1180b57cec5SDimitry Andric #else
1190b57cec5SDimitry Andric   return do_strerror_r(ev);
1200b57cec5SDimitry Andric #endif
1210b57cec5SDimitry Andric }
1220b57cec5SDimitry Andric 
123*e710425bSDimitry Andric class _LIBCPP_HIDDEN __generic_error_category : public __do_message {
1240b57cec5SDimitry Andric public:
125fe6060f1SDimitry Andric   virtual const char* name() const noexcept;
1260b57cec5SDimitry Andric   virtual string message(int ev) const;
1270b57cec5SDimitry Andric };
1280b57cec5SDimitry Andric 
129*e710425bSDimitry Andric const char* __generic_error_category::name() const noexcept { return "generic"; }
1300b57cec5SDimitry Andric 
131*e710425bSDimitry Andric string __generic_error_category::message(int ev) const {
1320b57cec5SDimitry Andric #ifdef _LIBCPP_ELAST
1330b57cec5SDimitry Andric   if (ev > _LIBCPP_ELAST)
1340b57cec5SDimitry Andric     return string("unspecified generic_category error");
1350b57cec5SDimitry Andric #endif // _LIBCPP_ELAST
1360b57cec5SDimitry Andric   return __do_message::message(ev);
1370b57cec5SDimitry Andric }
1380b57cec5SDimitry Andric 
139*e710425bSDimitry Andric const error_category& generic_category() noexcept {
140c9157d92SDimitry Andric   union AvoidDestroyingGenericCategory {
141c9157d92SDimitry Andric     __generic_error_category generic_error_category;
142c9157d92SDimitry Andric     constexpr explicit AvoidDestroyingGenericCategory() : generic_error_category() {}
143c9157d92SDimitry Andric     ~AvoidDestroyingGenericCategory() {}
144c9157d92SDimitry Andric   };
145c9157d92SDimitry Andric   constinit static AvoidDestroyingGenericCategory helper;
146c9157d92SDimitry Andric   return helper.generic_error_category;
1470b57cec5SDimitry Andric }
1480b57cec5SDimitry Andric 
149*e710425bSDimitry Andric class _LIBCPP_HIDDEN __system_error_category : public __do_message {
1500b57cec5SDimitry Andric public:
151fe6060f1SDimitry Andric   virtual const char* name() const noexcept;
1520b57cec5SDimitry Andric   virtual string message(int ev) const;
153fe6060f1SDimitry Andric   virtual error_condition default_error_condition(int ev) const noexcept;
1540b57cec5SDimitry Andric };
1550b57cec5SDimitry Andric 
156*e710425bSDimitry Andric const char* __system_error_category::name() const noexcept { return "system"; }
1570b57cec5SDimitry Andric 
158*e710425bSDimitry Andric string __system_error_category::message(int ev) const {
1590b57cec5SDimitry Andric #ifdef _LIBCPP_ELAST
1600b57cec5SDimitry Andric   if (ev > _LIBCPP_ELAST)
1610b57cec5SDimitry Andric     return string("unspecified system_category error");
1620b57cec5SDimitry Andric #endif // _LIBCPP_ELAST
1630b57cec5SDimitry Andric   return __do_message::message(ev);
1640b57cec5SDimitry Andric }
1650b57cec5SDimitry Andric 
166*e710425bSDimitry Andric error_condition __system_error_category::default_error_condition(int ev) const noexcept {
1670b57cec5SDimitry Andric #ifdef _LIBCPP_ELAST
1680b57cec5SDimitry Andric   if (ev > _LIBCPP_ELAST)
1690b57cec5SDimitry Andric     return error_condition(ev, system_category());
1700b57cec5SDimitry Andric #endif // _LIBCPP_ELAST
1710b57cec5SDimitry Andric   return error_condition(ev, generic_category());
1720b57cec5SDimitry Andric }
1730b57cec5SDimitry Andric 
174*e710425bSDimitry Andric const error_category& system_category() noexcept {
175c9157d92SDimitry Andric   union AvoidDestroyingSystemCategory {
176c9157d92SDimitry Andric     __system_error_category system_error_category;
177c9157d92SDimitry Andric     constexpr explicit AvoidDestroyingSystemCategory() : system_error_category() {}
178c9157d92SDimitry Andric     ~AvoidDestroyingSystemCategory() {}
179c9157d92SDimitry Andric   };
180c9157d92SDimitry Andric   constinit static AvoidDestroyingSystemCategory helper;
181c9157d92SDimitry Andric   return helper.system_error_category;
1820b57cec5SDimitry Andric }
1830b57cec5SDimitry Andric 
1840b57cec5SDimitry Andric // error_condition
1850b57cec5SDimitry Andric 
186*e710425bSDimitry Andric string error_condition::message() const { return __cat_->message(__val_); }
1870b57cec5SDimitry Andric 
1880b57cec5SDimitry Andric // error_code
1890b57cec5SDimitry Andric 
190*e710425bSDimitry Andric string error_code::message() const { return __cat_->message(__val_); }
1910b57cec5SDimitry Andric 
1920b57cec5SDimitry Andric // system_error
1930b57cec5SDimitry Andric 
1940b57cec5SDimitry Andric system_error::system_error(error_code ec, const string& what_arg)
195*e710425bSDimitry Andric     : runtime_error(make_error_str(ec, what_arg)), __ec_(ec) {}
1960b57cec5SDimitry Andric 
1970b57cec5SDimitry Andric system_error::system_error(error_code ec, const char* what_arg)
198*e710425bSDimitry Andric     : runtime_error(make_error_str(ec, what_arg)), __ec_(ec) {}
1990b57cec5SDimitry Andric 
200*e710425bSDimitry Andric system_error::system_error(error_code ec) : runtime_error(make_error_str(ec)), __ec_(ec) {}
2010b57cec5SDimitry Andric 
2020b57cec5SDimitry Andric system_error::system_error(int ev, const error_category& ecat, const string& what_arg)
203*e710425bSDimitry Andric     : runtime_error(make_error_str(error_code(ev, ecat), what_arg)), __ec_(error_code(ev, ecat)) {}
2040b57cec5SDimitry Andric 
2050b57cec5SDimitry Andric system_error::system_error(int ev, const error_category& ecat, const char* what_arg)
206*e710425bSDimitry Andric     : runtime_error(make_error_str(error_code(ev, ecat), what_arg)), __ec_(error_code(ev, ecat)) {}
2070b57cec5SDimitry Andric 
2080b57cec5SDimitry Andric system_error::system_error(int ev, const error_category& ecat)
209*e710425bSDimitry Andric     : runtime_error(make_error_str(error_code(ev, ecat))), __ec_(error_code(ev, ecat)) {}
2100b57cec5SDimitry Andric 
211*e710425bSDimitry Andric system_error::~system_error() noexcept {}
2120b57cec5SDimitry Andric 
213*e710425bSDimitry Andric void __throw_system_error(int ev, const char* what_arg) {
214fe013be4SDimitry Andric #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
215c9157d92SDimitry Andric   std::__throw_system_error(error_code(ev, system_category()), what_arg);
2160b57cec5SDimitry Andric #else
217c9157d92SDimitry Andric   // The above could also handle the no-exception case, but for size, avoid referencing system_category() unnecessarily.
218*e710425bSDimitry Andric   _LIBCPP_VERBOSE_ABORT(
219*e710425bSDimitry Andric       "system_error was thrown in -fno-exceptions mode with error %i and message \"%s\"", ev, what_arg);
2200b57cec5SDimitry Andric #endif
2210b57cec5SDimitry Andric }
2220b57cec5SDimitry Andric 
2230b57cec5SDimitry Andric _LIBCPP_END_NAMESPACE_STD
224