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) |
31 | error_category::error_category() _NOEXCEPT |
32 | { |
33 | } |
34 | #endif |
35 | |
36 | error_category::~error_category() _NOEXCEPT |
37 | { |
38 | } |
39 | |
40 | error_condition |
41 | error_category::default_error_condition(int ev) const _NOEXCEPT |
42 | { |
43 | return error_condition(ev, *this); |
44 | } |
45 | |
46 | bool |
47 | error_category::equivalent(int code, const error_condition& condition) const _NOEXCEPT |
48 | { |
49 | return default_error_condition(code) == condition; |
50 | } |
51 | |
52 | bool |
53 | 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) |
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 * |
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 * |
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. |
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 |
131 | __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* |
149 | __generic_error_category::name() const _NOEXCEPT |
150 | { |
151 | return "generic" ; |
152 | } |
153 | |
154 | string |
155 | __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& |
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* |
181 | __system_error_category::name() const _NOEXCEPT |
182 | { |
183 | return "system" ; |
184 | } |
185 | |
186 | string |
187 | __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 |
197 | __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& |
207 | system_category() _NOEXCEPT |
208 | { |
209 | static __system_error_category s; |
210 | return s; |
211 | } |
212 | |
213 | // error_condition |
214 | |
215 | string |
216 | error_condition::message() const |
217 | { |
218 | return __cat_->message(__val_); |
219 | } |
220 | |
221 | // error_code |
222 | |
223 | string |
224 | error_code::message() const |
225 | { |
226 | return __cat_->message(__val_); |
227 | } |
228 | |
229 | // system_error |
230 | |
231 | string |
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 | |
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 | |
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 | |
255 | system_error::system_error(error_code ec) |
256 | : runtime_error(__init(ec, "" )), |
257 | __ec_(ec) |
258 | { |
259 | } |
260 | |
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 | |
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 | |
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 | |
279 | system_error::~system_error() _NOEXCEPT |
280 | { |
281 | } |
282 | |
283 | void |
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 | |