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