xref: /freebsd/contrib/llvm-project/libcxx/src/system_error.cpp (revision 833a452e9f082a7982a31c21f0da437dbbe0a39d)
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