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>
105f757f3fSDimitry Andric #include <__config>
1106c3fb27SDimitry 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>
17cb14a3feSDimitry 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 {
295f757f3fSDimitry 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)50cb14a3feSDimitry 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)58cb14a3feSDimitry 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*1db9f3b2SDimitry 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;
84cb14a3feSDimitry 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
945f757f3fSDimitry Andric
955f757f3fSDimitry Andric #endif // !defined(_LIBCPP_HAS_NO_THREADS)
965f757f3fSDimitry Andric
make_error_str(const error_code & ec,string what_arg)975f757f3fSDimitry Andric string make_error_str(const error_code& ec, string what_arg) {
985f757f3fSDimitry Andric if (ec) {
995f757f3fSDimitry Andric if (!what_arg.empty()) {
1005f757f3fSDimitry Andric what_arg += ": ";
1015f757f3fSDimitry Andric }
1025f757f3fSDimitry Andric what_arg += ec.message();
1035f757f3fSDimitry Andric }
1045f757f3fSDimitry Andric return what_arg;
1055f757f3fSDimitry Andric }
1065f757f3fSDimitry Andric
make_error_str(const error_code & ec)1075f757f3fSDimitry Andric string make_error_str(const error_code& ec) {
1085f757f3fSDimitry Andric if (ec) {
1095f757f3fSDimitry Andric return ec.message();
1105f757f3fSDimitry Andric }
1115f757f3fSDimitry Andric return string();
1125f757f3fSDimitry Andric }
1130b57cec5SDimitry Andric } // end namespace
1140b57cec5SDimitry Andric
message(int ev) const115cb14a3feSDimitry 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
123cb14a3feSDimitry 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() const129cb14a3feSDimitry Andric const char* __generic_error_category::name() const noexcept { return "generic"; }
1300b57cec5SDimitry Andric
message(int ev) const131cb14a3feSDimitry 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()139cb14a3feSDimitry Andric const error_category& generic_category() noexcept {
1405f757f3fSDimitry Andric union AvoidDestroyingGenericCategory {
1415f757f3fSDimitry Andric __generic_error_category generic_error_category;
1425f757f3fSDimitry Andric constexpr explicit AvoidDestroyingGenericCategory() : generic_error_category() {}
1435f757f3fSDimitry Andric ~AvoidDestroyingGenericCategory() {}
1445f757f3fSDimitry Andric };
1455f757f3fSDimitry Andric constinit static AvoidDestroyingGenericCategory helper;
1465f757f3fSDimitry Andric return helper.generic_error_category;
1470b57cec5SDimitry Andric }
1480b57cec5SDimitry Andric
149cb14a3feSDimitry 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() const156cb14a3feSDimitry Andric const char* __system_error_category::name() const noexcept { return "system"; }
1570b57cec5SDimitry Andric
message(int ev) const158cb14a3feSDimitry 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) const166cb14a3feSDimitry 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()174cb14a3feSDimitry Andric const error_category& system_category() noexcept {
1755f757f3fSDimitry Andric union AvoidDestroyingSystemCategory {
1765f757f3fSDimitry Andric __system_error_category system_error_category;
1775f757f3fSDimitry Andric constexpr explicit AvoidDestroyingSystemCategory() : system_error_category() {}
1785f757f3fSDimitry Andric ~AvoidDestroyingSystemCategory() {}
1795f757f3fSDimitry Andric };
1805f757f3fSDimitry Andric constinit static AvoidDestroyingSystemCategory helper;
1815f757f3fSDimitry Andric return helper.system_error_category;
1820b57cec5SDimitry Andric }
1830b57cec5SDimitry Andric
1840b57cec5SDimitry Andric // error_condition
1850b57cec5SDimitry Andric
message() const186cb14a3feSDimitry Andric string error_condition::message() const { return __cat_->message(__val_); }
1870b57cec5SDimitry Andric
1880b57cec5SDimitry Andric // error_code
1890b57cec5SDimitry Andric
message() const190cb14a3feSDimitry 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)
195cb14a3feSDimitry 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)
198cb14a3feSDimitry Andric : runtime_error(make_error_str(ec, what_arg)), __ec_(ec) {}
1990b57cec5SDimitry Andric
system_error(error_code ec)200cb14a3feSDimitry 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)
203cb14a3feSDimitry 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)
206cb14a3feSDimitry 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)
209cb14a3feSDimitry Andric : runtime_error(make_error_str(error_code(ev, ecat))), __ec_(error_code(ev, ecat)) {}
2100b57cec5SDimitry Andric
~system_error()211cb14a3feSDimitry Andric system_error::~system_error() noexcept {}
2120b57cec5SDimitry Andric
__throw_system_error(int ev,const char * what_arg)213cb14a3feSDimitry Andric void __throw_system_error(int ev, const char* what_arg) {
21406c3fb27SDimitry Andric #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
2155f757f3fSDimitry Andric std::__throw_system_error(error_code(ev, system_category()), what_arg);
2160b57cec5SDimitry Andric #else
2175f757f3fSDimitry Andric // The above could also handle the no-exception case, but for size, avoid referencing system_category() unnecessarily.
218cb14a3feSDimitry Andric _LIBCPP_VERBOSE_ABORT(
219cb14a3feSDimitry 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