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 <__system_error/throw_system_error.h>
12 #include <__verbose_abort>
19 #include <system_error>
21 #include "include/config_elast.h"
23 #if defined(__ANDROID__)
24 # include <android/api-level.h>
27 _LIBCPP_BEGIN_NAMESPACE_STD
30 #if _LIBCPP_HAS_THREADS
32 // GLIBC also uses 1024 as the maximum buffer size internally.
33 constexpr size_t strerror_buff_size
= 1024;
35 string
do_strerror_r(int ev
);
37 # if defined(_LIBCPP_MSVCRT_LIKE)
38 string
do_strerror_r(int ev
) {
39 char buffer
[strerror_buff_size
];
40 if (::strerror_s(buffer
, strerror_buff_size
, ev
) == 0)
41 return string(buffer
);
42 std::snprintf(buffer
, strerror_buff_size
, "unknown error %d", ev
);
43 return string(buffer
);
47 // Only one of the two following functions will be used, depending on
48 // the return type of strerror_r:
50 // For the GNU variant, a char* return value:
51 __attribute__((unused
)) const char* 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* handle_strerror_r_return(int strerror_return
, char* buffer
) {
60 // The POSIX variant either:
61 // - fills in the provided buffer and returns 0
62 // - returns a positive error value, or
63 // - returns -1 and fills in errno with an error value.
64 if (strerror_return
== 0)
67 // Only handle EINVAL. Other errors abort.
68 int new_errno
= strerror_return
== -1 ? errno
: strerror_return
;
69 if (new_errno
== EINVAL
)
72 _LIBCPP_ASSERT_INTERNAL(new_errno
== ERANGE
, "unexpected error from ::strerror_r");
73 // FIXME maybe? 'strerror_buff_size' is likely to exceed the
74 // maximum error size so ERANGE shouldn't be returned.
78 // This function handles both GNU and POSIX variants, dispatching to
79 // one of the two above functions.
80 string
do_strerror_r(int ev
) {
81 char buffer
[strerror_buff_size
];
82 // Preserve errno around the call. (The C++ standard requires that
83 // system_error functions not modify errno).
84 const int old_errno
= errno
;
85 const char* error_message
= handle_strerror_r_return(::strerror_r(ev
, buffer
, strerror_buff_size
), buffer
);
86 // If we didn't get any message, print one now.
87 if (!error_message
[0]) {
88 std::snprintf(buffer
, strerror_buff_size
, "Unknown error %d", ev
);
89 error_message
= buffer
;
92 return string(error_message
);
96 #endif // _LIBCPP_HAS_THREADS
98 string
make_error_str(const error_code
& ec
, string what_arg
) {
100 if (!what_arg
.empty()) {
103 what_arg
+= ec
.message();
108 string
make_error_str(const error_code
& ec
) {
116 string
__do_message::message(int ev
) const {
117 #if !_LIBCPP_HAS_THREADS
118 return string(::strerror(ev
));
120 return do_strerror_r(ev
);
124 class _LIBCPP_HIDDEN __generic_error_category
: public __do_message
{
126 virtual const char* name() const noexcept
;
127 virtual string
message(int ev
) const;
130 const char* __generic_error_category::name() const noexcept
{ return "generic"; }
132 string
__generic_error_category::message(int ev
) const {
134 if (ev
> _LIBCPP_ELAST
)
135 return string("unspecified generic_category error");
136 #endif // _LIBCPP_ELAST
137 return __do_message::message(ev
);
140 const error_category
& generic_category() noexcept
{
141 union AvoidDestroyingGenericCategory
{
142 __generic_error_category generic_error_category
;
143 constexpr explicit AvoidDestroyingGenericCategory() : generic_error_category() {}
144 ~AvoidDestroyingGenericCategory() {}
146 constinit
static AvoidDestroyingGenericCategory helper
;
147 return helper
.generic_error_category
;
150 class _LIBCPP_HIDDEN __system_error_category
: public __do_message
{
152 virtual const char* name() const noexcept
;
153 virtual string
message(int ev
) const;
154 virtual error_condition
default_error_condition(int ev
) const noexcept
;
157 const char* __system_error_category::name() const noexcept
{ return "system"; }
159 string
__system_error_category::message(int ev
) const {
161 if (ev
> _LIBCPP_ELAST
)
162 return string("unspecified system_category error");
163 #endif // _LIBCPP_ELAST
164 return __do_message::message(ev
);
167 error_condition
__system_error_category::default_error_condition(int ev
) const noexcept
{
169 if (ev
> _LIBCPP_ELAST
)
170 return error_condition(ev
, system_category());
171 #endif // _LIBCPP_ELAST
172 return error_condition(ev
, generic_category());
175 const error_category
& system_category() noexcept
{
176 union AvoidDestroyingSystemCategory
{
177 __system_error_category system_error_category
;
178 constexpr explicit AvoidDestroyingSystemCategory() : system_error_category() {}
179 ~AvoidDestroyingSystemCategory() {}
181 constinit
static AvoidDestroyingSystemCategory helper
;
182 return helper
.system_error_category
;
187 string
error_condition::message() const { return __cat_
->message(__val_
); }
191 string
error_code::message() const { return __cat_
->message(__val_
); }
195 system_error::system_error(error_code ec
, const string
& what_arg
)
196 : runtime_error(make_error_str(ec
, what_arg
)), __ec_(ec
) {}
198 system_error::system_error(error_code ec
, const char* what_arg
)
199 : runtime_error(make_error_str(ec
, what_arg
)), __ec_(ec
) {}
201 system_error::system_error(error_code ec
) : runtime_error(make_error_str(ec
)), __ec_(ec
) {}
203 system_error::system_error(int ev
, const error_category
& ecat
, const string
& what_arg
)
204 : runtime_error(make_error_str(error_code(ev
, ecat
), what_arg
)), __ec_(error_code(ev
, ecat
)) {}
206 system_error::system_error(int ev
, const error_category
& ecat
, const char* what_arg
)
207 : runtime_error(make_error_str(error_code(ev
, ecat
), what_arg
)), __ec_(error_code(ev
, ecat
)) {}
209 system_error::system_error(int ev
, const error_category
& ecat
)
210 : runtime_error(make_error_str(error_code(ev
, ecat
))), __ec_(error_code(ev
, ecat
)) {}
212 system_error::~system_error() noexcept
{}
214 void __throw_system_error(int ev
, const char* what_arg
) {
215 #if _LIBCPP_HAS_EXCEPTIONS
216 std::__throw_system_error(error_code(ev
, system_category()), what_arg
);
218 // The above could also handle the no-exception case, but for size, avoid referencing system_category() unnecessarily.
219 _LIBCPP_VERBOSE_ABORT(
220 "system_error was thrown in -fno-exceptions mode with error %i and message \"%s\"", ev
, what_arg
);
224 _LIBCPP_END_NAMESPACE_STD