1 //===---------------------- system_error.cpp ------------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is dual licensed under the MIT and the University of Illinois Open
6 // Source Licenses. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "__config"
11 
12 #define _LIBCPP_BUILDING_SYSTEM_ERROR
13 #include "system_error"
14 
15 #include "include/config_elast.h"
16 #include "cerrno"
17 #include "cstring"
18 #include "cstdio"
19 #include "cstdlib"
20 #include "cassert"
21 #include "string"
22 #include "string.h"
23 
24 _LIBCPP_BEGIN_NAMESPACE_STD
25 
26 // class error_category
27 
28 error_category::error_category() _NOEXCEPT
29 {
30 }
31 
32 error_category::~error_category() _NOEXCEPT
33 {
34 }
35 
36 error_condition
37 error_category::default_error_condition(int ev) const _NOEXCEPT
38 {
39     return error_condition(ev, *this);
40 }
41 
42 bool
43 error_category::equivalent(int code, const error_condition& condition) const _NOEXCEPT
44 {
45     return default_error_condition(code) == condition;
46 }
47 
48 bool
49 error_category::equivalent(const error_code& code, int condition) const _NOEXCEPT
50 {
51     return *this == code.category() && code.value() == condition;
52 }
53 
54 namespace {
55 
56 //  GLIBC also uses 1024 as the maximum buffer size internally.
57 constexpr size_t strerror_buff_size = 1024;
58 
59 string do_strerror_r(int ev);
60 
61 #if defined(__linux__) && !defined(_LIBCPP_HAS_MUSL_LIBC)
62 // GNU Extended version
63 string do_strerror_r(int ev) {
64     char buffer[strerror_buff_size];
65     char* ret = ::strerror_r(ev, buffer, strerror_buff_size);
66     return string(ret);
67 }
68 #else
69 // POSIX version
70 string do_strerror_r(int ev) {
71     char buffer[strerror_buff_size];
72     const int old_errno = errno;
73     int ret;
74     if ((ret = ::strerror_r(ev, buffer, strerror_buff_size)) != 0) {
75         // If `ret == -1` then the error is specified using `errno`, otherwise
76         // `ret` represents the error.
77         const int new_errno = ret == -1 ? errno : ret;
78         errno = old_errno;
79         if (new_errno == EINVAL) {
80             std::snprintf(buffer, strerror_buff_size, "Unknown error %d", ev);
81             return string(buffer);
82         } else {
83             assert(new_errno == ERANGE);
84             // FIXME maybe? 'strerror_buff_size' is likely to exceed the
85             // maximum error size so ERANGE shouldn't be returned.
86             std::abort();
87         }
88     }
89     return string(buffer);
90 }
91 #endif
92 
93 } // end namespace
94 
95 string
96 __do_message::message(int ev) const
97 {
98 #if defined(_LIBCPP_HAS_NO_THREADS)
99     return string(::strerror(ev));
100 #else
101     return do_strerror_r(ev);
102 #endif
103 }
104 
105 class _LIBCPP_HIDDEN __generic_error_category
106     : public __do_message
107 {
108 public:
109     virtual const char* name() const _NOEXCEPT;
110     virtual string message(int ev) const;
111 };
112 
113 const char*
114 __generic_error_category::name() const _NOEXCEPT
115 {
116     return "generic";
117 }
118 
119 string
120 __generic_error_category::message(int ev) const
121 {
122 #ifdef _LIBCPP_ELAST
123     if (ev > _LIBCPP_ELAST)
124       return string("unspecified generic_category error");
125 #endif  // _LIBCPP_ELAST
126     return __do_message::message(ev);
127 }
128 
129 const error_category&
130 generic_category() _NOEXCEPT
131 {
132     static __generic_error_category s;
133     return s;
134 }
135 
136 class _LIBCPP_HIDDEN __system_error_category
137     : public __do_message
138 {
139 public:
140     virtual const char* name() const _NOEXCEPT;
141     virtual string message(int ev) const;
142     virtual error_condition default_error_condition(int ev) const _NOEXCEPT;
143 };
144 
145 const char*
146 __system_error_category::name() const _NOEXCEPT
147 {
148     return "system";
149 }
150 
151 string
152 __system_error_category::message(int ev) const
153 {
154 #ifdef _LIBCPP_ELAST
155     if (ev > _LIBCPP_ELAST)
156       return string("unspecified system_category error");
157 #endif  // _LIBCPP_ELAST
158     return __do_message::message(ev);
159 }
160 
161 error_condition
162 __system_error_category::default_error_condition(int ev) const _NOEXCEPT
163 {
164 #ifdef _LIBCPP_ELAST
165     if (ev > _LIBCPP_ELAST)
166       return error_condition(ev, system_category());
167 #endif  // _LIBCPP_ELAST
168     return error_condition(ev, generic_category());
169 }
170 
171 const error_category&
172 system_category() _NOEXCEPT
173 {
174     static __system_error_category s;
175     return s;
176 }
177 
178 // error_condition
179 
180 string
181 error_condition::message() const
182 {
183     return __cat_->message(__val_);
184 }
185 
186 // error_code
187 
188 string
189 error_code::message() const
190 {
191     return __cat_->message(__val_);
192 }
193 
194 // system_error
195 
196 string
197 system_error::__init(const error_code& ec, string what_arg)
198 {
199     if (ec)
200     {
201         if (!what_arg.empty())
202             what_arg += ": ";
203         what_arg += ec.message();
204     }
205     return what_arg;
206 }
207 
208 system_error::system_error(error_code ec, const string& what_arg)
209     : runtime_error(__init(ec, what_arg)),
210       __ec_(ec)
211 {
212 }
213 
214 system_error::system_error(error_code ec, const char* what_arg)
215     : runtime_error(__init(ec, what_arg)),
216       __ec_(ec)
217 {
218 }
219 
220 system_error::system_error(error_code ec)
221     : runtime_error(__init(ec, "")),
222       __ec_(ec)
223 {
224 }
225 
226 system_error::system_error(int ev, const error_category& ecat, const string& what_arg)
227     : runtime_error(__init(error_code(ev, ecat), what_arg)),
228       __ec_(error_code(ev, ecat))
229 {
230 }
231 
232 system_error::system_error(int ev, const error_category& ecat, const char* what_arg)
233     : runtime_error(__init(error_code(ev, ecat), what_arg)),
234       __ec_(error_code(ev, ecat))
235 {
236 }
237 
238 system_error::system_error(int ev, const error_category& ecat)
239     : runtime_error(__init(error_code(ev, ecat), "")),
240       __ec_(error_code(ev, ecat))
241 {
242 }
243 
244 system_error::~system_error() _NOEXCEPT
245 {
246 }
247 
248 void
249 __throw_system_error(int ev, const char* what_arg)
250 {
251 #ifndef _LIBCPP_NO_EXCEPTIONS
252     throw system_error(error_code(ev, system_category()), what_arg);
253 #else
254     (void)ev;
255     (void)what_arg;
256 #endif
257 }
258 
259 _LIBCPP_END_NAMESPACE_STD
260