1 //===----------------------------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
11 #include <__verbose_abort>
18 #include <system_error>
20 #include "include/config_elast.h"
22 #if defined(__ANDROID__)
23 #include <android/api-level.h>
26 _LIBCPP_BEGIN_NAMESPACE_STD
29 #if !defined(_LIBCPP_HAS_NO_THREADS)
31 // GLIBC also uses 1024 as the maximum buffer size internally.
32 constexpr size_t strerror_buff_size
= 1024;
34 string
do_strerror_r(int ev
);
36 #if defined(_LIBCPP_MSVCRT_LIKE)
37 string
do_strerror_r(int ev
) {
38 char buffer
[strerror_buff_size
];
39 if (::strerror_s(buffer
, strerror_buff_size
, ev
) == 0)
40 return string(buffer
);
41 std::snprintf(buffer
, strerror_buff_size
, "unknown error %d", ev
);
42 return string(buffer
);
46 // Only one of the two following functions will be used, depending on
47 // the return type of strerror_r:
49 // For the GNU variant, a char* return value:
50 __attribute__((unused
)) const char *
51 handle_strerror_r_return(char *strerror_return
, char *buffer
) {
52 // GNU always returns a string pointer in its return value. The
53 // string might point to either the input buffer, or a static
54 // buffer, but we don't care which.
55 return strerror_return
;
58 // For the POSIX variant: an int return value.
59 __attribute__((unused
)) const char *
60 handle_strerror_r_return(int strerror_return
, char *buffer
) {
61 // The POSIX variant either:
62 // - fills in the provided buffer and returns 0
63 // - returns a positive error value, or
64 // - returns -1 and fills in errno with an error value.
65 if (strerror_return
== 0)
68 // Only handle EINVAL. Other errors abort.
69 int new_errno
= strerror_return
== -1 ? errno
: strerror_return
;
70 if (new_errno
== EINVAL
)
73 _LIBCPP_ASSERT_UNCATEGORIZED(new_errno
== ERANGE
, "unexpected error from ::strerror_r");
74 // FIXME maybe? 'strerror_buff_size' is likely to exceed the
75 // maximum error size so ERANGE shouldn't be returned.
79 // This function handles both GNU and POSIX variants, dispatching to
80 // one of the two above functions.
81 string
do_strerror_r(int ev
) {
82 char buffer
[strerror_buff_size
];
83 // Preserve errno around the call. (The C++ standard requires that
84 // system_error functions not modify errno).
85 const int old_errno
= errno
;
86 const char *error_message
= handle_strerror_r_return(
87 ::strerror_r(ev
, buffer
, strerror_buff_size
), buffer
);
88 // If we didn't get any message, print one now.
89 if (!error_message
[0]) {
90 std::snprintf(buffer
, strerror_buff_size
, "Unknown error %d", ev
);
91 error_message
= buffer
;
94 return string(error_message
);
98 #endif // !defined(_LIBCPP_HAS_NO_THREADS)
100 string
make_error_str(const error_code
& ec
, string what_arg
) {
102 if (!what_arg
.empty()) {
105 what_arg
+= ec
.message();
110 string
make_error_str(const error_code
& ec
) {
119 __do_message::message(int ev
) const
121 #if defined(_LIBCPP_HAS_NO_THREADS)
122 return string(::strerror(ev
));
124 return do_strerror_r(ev
);
128 class _LIBCPP_HIDDEN __generic_error_category
129 : public __do_message
132 virtual const char* name() const noexcept
;
133 virtual string
message(int ev
) const;
137 __generic_error_category::name() const noexcept
143 __generic_error_category::message(int ev
) const
146 if (ev
> _LIBCPP_ELAST
)
147 return string("unspecified generic_category error");
148 #endif // _LIBCPP_ELAST
149 return __do_message::message(ev
);
152 const error_category
&
153 generic_category() noexcept
155 union AvoidDestroyingGenericCategory
{
156 __generic_error_category generic_error_category
;
157 constexpr explicit AvoidDestroyingGenericCategory() : generic_error_category() {}
158 ~AvoidDestroyingGenericCategory() {}
160 constinit
static AvoidDestroyingGenericCategory helper
;
161 return helper
.generic_error_category
;
164 class _LIBCPP_HIDDEN __system_error_category
165 : public __do_message
168 virtual const char* name() const noexcept
;
169 virtual string
message(int ev
) const;
170 virtual error_condition
default_error_condition(int ev
) const noexcept
;
174 __system_error_category::name() const noexcept
180 __system_error_category::message(int ev
) const
183 if (ev
> _LIBCPP_ELAST
)
184 return string("unspecified system_category error");
185 #endif // _LIBCPP_ELAST
186 return __do_message::message(ev
);
190 __system_error_category::default_error_condition(int ev
) const noexcept
193 if (ev
> _LIBCPP_ELAST
)
194 return error_condition(ev
, system_category());
195 #endif // _LIBCPP_ELAST
196 return error_condition(ev
, generic_category());
199 const error_category
&
200 system_category() noexcept
202 union AvoidDestroyingSystemCategory
{
203 __system_error_category system_error_category
;
204 constexpr explicit AvoidDestroyingSystemCategory() : system_error_category() {}
205 ~AvoidDestroyingSystemCategory() {}
207 constinit
static AvoidDestroyingSystemCategory helper
;
208 return helper
.system_error_category
;
214 error_condition::message() const
216 return __cat_
->message(__val_
);
222 error_code::message() const
224 return __cat_
->message(__val_
);
229 system_error::system_error(error_code ec
, const string
& what_arg
)
230 : runtime_error(make_error_str(ec
, what_arg
)),
235 system_error::system_error(error_code ec
, const char* what_arg
)
236 : runtime_error(make_error_str(ec
, what_arg
)),
241 system_error::system_error(error_code ec
)
242 : runtime_error(make_error_str(ec
)),
247 system_error::system_error(int ev
, const error_category
& ecat
, const string
& what_arg
)
248 : runtime_error(make_error_str(error_code(ev
, ecat
), what_arg
)),
249 __ec_(error_code(ev
, ecat
))
253 system_error::system_error(int ev
, const error_category
& ecat
, const char* what_arg
)
254 : runtime_error(make_error_str(error_code(ev
, ecat
), what_arg
)),
255 __ec_(error_code(ev
, ecat
))
259 system_error::system_error(int ev
, const error_category
& ecat
)
260 : runtime_error(make_error_str(error_code(ev
, ecat
))),
261 __ec_(error_code(ev
, ecat
))
265 system_error::~system_error() noexcept
270 __throw_system_error(int ev
, const char* what_arg
)
272 #ifndef _LIBCPP_HAS_NO_EXCEPTIONS
273 std::__throw_system_error(error_code(ev
, system_category()), what_arg
);
275 // The above could also handle the no-exception case, but for size, avoid referencing system_category() unnecessarily.
276 _LIBCPP_VERBOSE_ABORT("system_error was thrown in -fno-exceptions mode with error %i and message \"%s\"", ev
, what_arg
);
280 _LIBCPP_END_NAMESPACE_STD