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