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