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