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