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