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