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>
17e710425bSDimitry 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)
do_strerror_r(int ev)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:
handle_strerror_r_return(char * strerror_return,char * buffer)50e710425bSDimitry 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.
handle_strerror_r_return(int strerror_return,char * buffer)58e710425bSDimitry 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
71*cdc20ff6SDimitry Andric _LIBCPP_ASSERT_INTERNAL(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.
do_strerror_r(int ev)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;
84e710425bSDimitry 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
make_error_str(const error_code & ec,string what_arg)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
make_error_str(const error_code & ec)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
message(int ev) const115e710425bSDimitry 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
123e710425bSDimitry 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
name() const129e710425bSDimitry Andric const char* __generic_error_category::name() const noexcept { return "generic"; }
1300b57cec5SDimitry Andric
message(int ev) const131e710425bSDimitry 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
generic_category()139e710425bSDimitry 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
149e710425bSDimitry 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
name() const156e710425bSDimitry Andric const char* __system_error_category::name() const noexcept { return "system"; }
1570b57cec5SDimitry Andric
message(int ev) const158e710425bSDimitry 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
default_error_condition(int ev) const166e710425bSDimitry 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
system_category()174e710425bSDimitry 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
message() const186e710425bSDimitry Andric string error_condition::message() const { return __cat_->message(__val_); }
1870b57cec5SDimitry Andric
1880b57cec5SDimitry Andric // error_code
1890b57cec5SDimitry Andric
message() const190e710425bSDimitry Andric string error_code::message() const { return __cat_->message(__val_); }
1910b57cec5SDimitry Andric
1920b57cec5SDimitry Andric // system_error
1930b57cec5SDimitry Andric
system_error(error_code ec,const string & what_arg)1940b57cec5SDimitry Andric system_error::system_error(error_code ec, const string& what_arg)
195e710425bSDimitry Andric : runtime_error(make_error_str(ec, what_arg)), __ec_(ec) {}
1960b57cec5SDimitry Andric
system_error(error_code ec,const char * what_arg)1970b57cec5SDimitry Andric system_error::system_error(error_code ec, const char* what_arg)
198e710425bSDimitry Andric : runtime_error(make_error_str(ec, what_arg)), __ec_(ec) {}
1990b57cec5SDimitry Andric
system_error(error_code ec)200e710425bSDimitry Andric system_error::system_error(error_code ec) : runtime_error(make_error_str(ec)), __ec_(ec) {}
2010b57cec5SDimitry Andric
system_error(int ev,const error_category & ecat,const string & what_arg)2020b57cec5SDimitry Andric system_error::system_error(int ev, const error_category& ecat, const string& what_arg)
203e710425bSDimitry Andric : runtime_error(make_error_str(error_code(ev, ecat), what_arg)), __ec_(error_code(ev, ecat)) {}
2040b57cec5SDimitry Andric
system_error(int ev,const error_category & ecat,const char * what_arg)2050b57cec5SDimitry Andric system_error::system_error(int ev, const error_category& ecat, const char* what_arg)
206e710425bSDimitry Andric : runtime_error(make_error_str(error_code(ev, ecat), what_arg)), __ec_(error_code(ev, ecat)) {}
2070b57cec5SDimitry Andric
system_error(int ev,const error_category & ecat)2080b57cec5SDimitry Andric system_error::system_error(int ev, const error_category& ecat)
209e710425bSDimitry Andric : runtime_error(make_error_str(error_code(ev, ecat))), __ec_(error_code(ev, ecat)) {}
2100b57cec5SDimitry Andric
~system_error()211e710425bSDimitry Andric system_error::~system_error() noexcept {}
2120b57cec5SDimitry Andric
__throw_system_error(int ev,const char * what_arg)213e710425bSDimitry 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.
218e710425bSDimitry Andric _LIBCPP_VERBOSE_ABORT(
219e710425bSDimitry 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