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     if ((int ret = ::strerror_r(ev, buffer, strerror_buff_size)) != 0) {
74         // If `ret == -1` then the error is specified using `errno`, otherwise
75         // `ret` represents the error.
76         const int new_errno = ret == -1 ? errno : ret;
77         errno = old_errno;
78         if (new_errno == EINVAL) {
79             std::snprintf(buffer, strerror_buff_size, "Unknown error %d", ev);
80             return string(buffer);
81         } else {
82             assert(new_errno == ERANGE);
83             // FIXME maybe? 'strerror_buff_size' is likely to exceed the
84             // maximum error size so ERANGE shouldn't be returned.
85             std::abort();
86         }
87     }
88     return string(buffer);
89 }
90 #endif
91 
92 } // end namespace
93 
94 string
95 __do_message::message(int ev) const
96 {
97 #if defined(_LIBCPP_HAS_NO_THREADS)
98     return string(::strerror(ev));
99 #else
100     return do_strerror_r(ev);
101 #endif
102 }
103 
104 class _LIBCPP_HIDDEN __generic_error_category
105     : public __do_message
106 {
107 public:
108     virtual const char* name() const _NOEXCEPT;
109     virtual string message(int ev) const;
110 };
111 
112 const char*
113 __generic_error_category::name() const _NOEXCEPT
114 {
115     return "generic";
116 }
117 
118 string
119 __generic_error_category::message(int ev) const
120 {
121 #ifdef _LIBCPP_ELAST
122     if (ev > _LIBCPP_ELAST)
123       return string("unspecified generic_category error");
124 #endif  // _LIBCPP_ELAST
125     return __do_message::message(ev);
126 }
127 
128 const error_category&
129 generic_category() _NOEXCEPT
130 {
131     static __generic_error_category s;
132     return s;
133 }
134 
135 class _LIBCPP_HIDDEN __system_error_category
136     : public __do_message
137 {
138 public:
139     virtual const char* name() const _NOEXCEPT;
140     virtual string message(int ev) const;
141     virtual error_condition default_error_condition(int ev) const _NOEXCEPT;
142 };
143 
144 const char*
145 __system_error_category::name() const _NOEXCEPT
146 {
147     return "system";
148 }
149 
150 string
151 __system_error_category::message(int ev) const
152 {
153 #ifdef _LIBCPP_ELAST
154     if (ev > _LIBCPP_ELAST)
155       return string("unspecified system_category error");
156 #endif  // _LIBCPP_ELAST
157     return __do_message::message(ev);
158 }
159 
160 error_condition
161 __system_error_category::default_error_condition(int ev) const _NOEXCEPT
162 {
163 #ifdef _LIBCPP_ELAST
164     if (ev > _LIBCPP_ELAST)
165       return error_condition(ev, system_category());
166 #endif  // _LIBCPP_ELAST
167     return error_condition(ev, generic_category());
168 }
169 
170 const error_category&
171 system_category() _NOEXCEPT
172 {
173     static __system_error_category s;
174     return s;
175 }
176 
177 // error_condition
178 
179 string
180 error_condition::message() const
181 {
182     return __cat_->message(__val_);
183 }
184 
185 // error_code
186 
187 string
188 error_code::message() const
189 {
190     return __cat_->message(__val_);
191 }
192 
193 // system_error
194 
195 string
196 system_error::__init(const error_code& ec, string what_arg)
197 {
198     if (ec)
199     {
200         if (!what_arg.empty())
201             what_arg += ": ";
202         what_arg += ec.message();
203     }
204     return what_arg;
205 }
206 
207 system_error::system_error(error_code ec, const string& what_arg)
208     : runtime_error(__init(ec, what_arg)),
209       __ec_(ec)
210 {
211 }
212 
213 system_error::system_error(error_code ec, const char* what_arg)
214     : runtime_error(__init(ec, what_arg)),
215       __ec_(ec)
216 {
217 }
218 
219 system_error::system_error(error_code ec)
220     : runtime_error(__init(ec, "")),
221       __ec_(ec)
222 {
223 }
224 
225 system_error::system_error(int ev, const error_category& ecat, const string& what_arg)
226     : runtime_error(__init(error_code(ev, ecat), what_arg)),
227       __ec_(error_code(ev, ecat))
228 {
229 }
230 
231 system_error::system_error(int ev, const error_category& ecat, const char* what_arg)
232     : runtime_error(__init(error_code(ev, ecat), what_arg)),
233       __ec_(error_code(ev, ecat))
234 {
235 }
236 
237 system_error::system_error(int ev, const error_category& ecat)
238     : runtime_error(__init(error_code(ev, ecat), "")),
239       __ec_(error_code(ev, ecat))
240 {
241 }
242 
243 system_error::~system_error() _NOEXCEPT
244 {
245 }
246 
247 void
248 __throw_system_error(int ev, const char* what_arg)
249 {
250 #ifndef _LIBCPP_NO_EXCEPTIONS
251     throw system_error(error_code(ev, system_category()), what_arg);
252 #else
253     (void)ev;
254     (void)what_arg;
255 #endif
256 }
257 
258 _LIBCPP_END_NAMESPACE_STD
259