1 //===---------------------- system_error.cpp ------------------------------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "__config"
10
11 #include "system_error"
12
13 #include "include/config_elast.h"
14 #include "cerrno"
15 #include "cstring"
16 #include "cstdio"
17 #include "cstdlib"
18 #include "string"
19 #include "string.h"
20 #include "__debug"
21
22 #if defined(__ANDROID__)
23 #include <android/api-level.h>
24 #endif
25
26 _LIBCPP_BEGIN_NAMESPACE_STD
27
28 // class error_category
29
30 #if defined(_LIBCPP_DEPRECATED_ABI_LEGACY_LIBRARY_DEFINITIONS_FOR_INLINE_FUNCTIONS)
error_category()31 error_category::error_category() _NOEXCEPT
32 {
33 }
34 #endif
35
~error_category()36 error_category::~error_category() _NOEXCEPT
37 {
38 }
39
40 error_condition
default_error_condition(int ev) const41 error_category::default_error_condition(int ev) const _NOEXCEPT
42 {
43 return error_condition(ev, *this);
44 }
45
46 bool
equivalent(int code,const error_condition & condition) const47 error_category::equivalent(int code, const error_condition& condition) const _NOEXCEPT
48 {
49 return default_error_condition(code) == condition;
50 }
51
52 bool
equivalent(const error_code & code,int condition) const53 error_category::equivalent(const error_code& code, int condition) const _NOEXCEPT
54 {
55 return *this == code.category() && code.value() == condition;
56 }
57
58 #if !defined(_LIBCPP_HAS_NO_THREADS)
59 namespace {
60
61 // GLIBC also uses 1024 as the maximum buffer size internally.
62 constexpr size_t strerror_buff_size = 1024;
63
64 string do_strerror_r(int ev);
65
66 #if defined(_LIBCPP_MSVCRT_LIKE)
do_strerror_r(int ev)67 string do_strerror_r(int ev) {
68 char buffer[strerror_buff_size];
69 if (::strerror_s(buffer, strerror_buff_size, ev) == 0)
70 return string(buffer);
71 std::snprintf(buffer, strerror_buff_size, "unknown error %d", ev);
72 return string(buffer);
73 }
74 #else
75
76 // Only one of the two following functions will be used, depending on
77 // the return type of strerror_r:
78
79 // For the GNU variant, a char* return value:
80 __attribute__((unused)) const char *
handle_strerror_r_return(char * strerror_return,char * buffer)81 handle_strerror_r_return(char *strerror_return, char *buffer) {
82 // GNU always returns a string pointer in its return value. The
83 // string might point to either the input buffer, or a static
84 // buffer, but we don't care which.
85 return strerror_return;
86 }
87
88 // For the POSIX variant: an int return value.
89 __attribute__((unused)) const char *
handle_strerror_r_return(int strerror_return,char * buffer)90 handle_strerror_r_return(int strerror_return, char *buffer) {
91 // The POSIX variant either:
92 // - fills in the provided buffer and returns 0
93 // - returns a positive error value, or
94 // - returns -1 and fills in errno with an error value.
95 if (strerror_return == 0)
96 return buffer;
97
98 // Only handle EINVAL. Other errors abort.
99 int new_errno = strerror_return == -1 ? errno : strerror_return;
100 if (new_errno == EINVAL)
101 return "";
102
103 _LIBCPP_ASSERT(new_errno == ERANGE, "unexpected error from ::strerror_r");
104 // FIXME maybe? 'strerror_buff_size' is likely to exceed the
105 // maximum error size so ERANGE shouldn't be returned.
106 std::abort();
107 }
108
109 // This function handles both GNU and POSIX variants, dispatching to
110 // one of the two above functions.
do_strerror_r(int ev)111 string do_strerror_r(int ev) {
112 char buffer[strerror_buff_size];
113 // Preserve errno around the call. (The C++ standard requires that
114 // system_error functions not modify errno).
115 const int old_errno = errno;
116 const char *error_message = handle_strerror_r_return(
117 ::strerror_r(ev, buffer, strerror_buff_size), buffer);
118 // If we didn't get any message, print one now.
119 if (!error_message[0]) {
120 std::snprintf(buffer, strerror_buff_size, "Unknown error %d", ev);
121 error_message = buffer;
122 }
123 errno = old_errno;
124 return string(error_message);
125 }
126 #endif
127 } // end namespace
128 #endif
129
130 string
message(int ev) const131 __do_message::message(int ev) const
132 {
133 #if defined(_LIBCPP_HAS_NO_THREADS)
134 return string(::strerror(ev));
135 #else
136 return do_strerror_r(ev);
137 #endif
138 }
139
140 class _LIBCPP_HIDDEN __generic_error_category
141 : public __do_message
142 {
143 public:
144 virtual const char* name() const _NOEXCEPT;
145 virtual string message(int ev) const;
146 };
147
148 const char*
name() const149 __generic_error_category::name() const _NOEXCEPT
150 {
151 return "generic";
152 }
153
154 string
message(int ev) const155 __generic_error_category::message(int ev) const
156 {
157 #ifdef _LIBCPP_ELAST
158 if (ev > _LIBCPP_ELAST)
159 return string("unspecified generic_category error");
160 #endif // _LIBCPP_ELAST
161 return __do_message::message(ev);
162 }
163
164 const error_category&
generic_category()165 generic_category() _NOEXCEPT
166 {
167 static __generic_error_category s;
168 return s;
169 }
170
171 class _LIBCPP_HIDDEN __system_error_category
172 : public __do_message
173 {
174 public:
175 virtual const char* name() const _NOEXCEPT;
176 virtual string message(int ev) const;
177 virtual error_condition default_error_condition(int ev) const _NOEXCEPT;
178 };
179
180 const char*
name() const181 __system_error_category::name() const _NOEXCEPT
182 {
183 return "system";
184 }
185
186 string
message(int ev) const187 __system_error_category::message(int ev) const
188 {
189 #ifdef _LIBCPP_ELAST
190 if (ev > _LIBCPP_ELAST)
191 return string("unspecified system_category error");
192 #endif // _LIBCPP_ELAST
193 return __do_message::message(ev);
194 }
195
196 error_condition
default_error_condition(int ev) const197 __system_error_category::default_error_condition(int ev) const _NOEXCEPT
198 {
199 #ifdef _LIBCPP_ELAST
200 if (ev > _LIBCPP_ELAST)
201 return error_condition(ev, system_category());
202 #endif // _LIBCPP_ELAST
203 return error_condition(ev, generic_category());
204 }
205
206 const error_category&
system_category()207 system_category() _NOEXCEPT
208 {
209 static __system_error_category s;
210 return s;
211 }
212
213 // error_condition
214
215 string
message() const216 error_condition::message() const
217 {
218 return __cat_->message(__val_);
219 }
220
221 // error_code
222
223 string
message() const224 error_code::message() const
225 {
226 return __cat_->message(__val_);
227 }
228
229 // system_error
230
231 string
__init(const error_code & ec,string what_arg)232 system_error::__init(const error_code& ec, string what_arg)
233 {
234 if (ec)
235 {
236 if (!what_arg.empty())
237 what_arg += ": ";
238 what_arg += ec.message();
239 }
240 return what_arg;
241 }
242
system_error(error_code ec,const string & what_arg)243 system_error::system_error(error_code ec, const string& what_arg)
244 : runtime_error(__init(ec, what_arg)),
245 __ec_(ec)
246 {
247 }
248
system_error(error_code ec,const char * what_arg)249 system_error::system_error(error_code ec, const char* what_arg)
250 : runtime_error(__init(ec, what_arg)),
251 __ec_(ec)
252 {
253 }
254
system_error(error_code ec)255 system_error::system_error(error_code ec)
256 : runtime_error(__init(ec, "")),
257 __ec_(ec)
258 {
259 }
260
system_error(int ev,const error_category & ecat,const string & what_arg)261 system_error::system_error(int ev, const error_category& ecat, const string& what_arg)
262 : runtime_error(__init(error_code(ev, ecat), what_arg)),
263 __ec_(error_code(ev, ecat))
264 {
265 }
266
system_error(int ev,const error_category & ecat,const char * what_arg)267 system_error::system_error(int ev, const error_category& ecat, const char* what_arg)
268 : runtime_error(__init(error_code(ev, ecat), what_arg)),
269 __ec_(error_code(ev, ecat))
270 {
271 }
272
system_error(int ev,const error_category & ecat)273 system_error::system_error(int ev, const error_category& ecat)
274 : runtime_error(__init(error_code(ev, ecat), "")),
275 __ec_(error_code(ev, ecat))
276 {
277 }
278
~system_error()279 system_error::~system_error() _NOEXCEPT
280 {
281 }
282
283 void
__throw_system_error(int ev,const char * what_arg)284 __throw_system_error(int ev, const char* what_arg)
285 {
286 #ifndef _LIBCPP_NO_EXCEPTIONS
287 throw system_error(error_code(ev, system_category()), what_arg);
288 #else
289 (void)ev;
290 (void)what_arg;
291 _VSTD::abort();
292 #endif
293 }
294
295 _LIBCPP_END_NAMESPACE_STD
296