blob: 5707e6b61d693265f01d7ee7c40d426a9e49c7e0 [file] [log] [blame]
// <system_error> implementation file
// Copyright (C) 2007-2022 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the
// terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3, or (at your option)
// any later version.
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.
// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
// <http://www.gnu.org/licenses/>.
#define _GLIBCXX_USE_CXX11_ABI 1
#define __sso_string __sso_stringxxx
#include <cstring>
#include <system_error>
#include <bits/functexcept.h>
#include <limits>
#include <errno.h>
#undef __sso_string
#if defined(_WIN32) && !defined(__CYGWIN__)
#include <memory>
#include <windows.h>
#endif
#if __has_cpp_attribute(clang::require_constant_initialization)
# define __constinit [[clang::require_constant_initialization]]
#endif
namespace
{
using std::string;
template<typename T>
struct constant_init
{
union {
T obj;
};
constexpr constant_init() : obj() { }
~constant_init() { /* do nothing, union member is not destroyed */ }
};
struct generic_error_category final : public std::error_category
{
const char*
name() const noexcept final
{ return "generic"; }
_GLIBCXX_DEFAULT_ABI_TAG
string
message(int i) const final
{
// XXX locale issues: how does one get or set loc.
// _GLIBCXX_HAVE_STRERROR_L, strerror_l(i, cloc)
return string(strerror(i));
}
// Override this to avoid a virtual call to default_error_condition(i).
bool
equivalent(int i, const std::error_condition& cond) const noexcept final
{ return i == cond.value() && *this == cond.category(); }
};
__constinit constant_init<generic_error_category> generic_category_instance{};
struct system_error_category final : public std::error_category
{
const char*
name() const noexcept final
{ return "system"; }
_GLIBCXX_DEFAULT_ABI_TAG
string
message(int i) const final
{
#if defined(_WIN32) && !defined(__CYGWIN__)
char* buf = nullptr;
auto len
= FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_ALLOCATE_BUFFER,
nullptr,
i,
LANG_USER_DEFAULT,
reinterpret_cast<LPTSTR>(&buf),
0,
nullptr);
if (len > 0)
{
struct deleter {
void operator()(void* p) const { ::LocalFree(p); }
};
std::unique_ptr<char[], deleter> guard(buf);
if (len > 3 && !__builtin_memcmp(buf + len - 3, ".\r\n", 3)) [[likely]]
len -= 3;
return string(buf, len);
}
return string("Unknown error code");
#else
// XXX locale issues: how does one get or set loc.
// _GLIBCXX_HAVE_STRERROR_L, strerror_l(i, cloc)
return string(strerror(i));
#endif
}
std::error_condition
default_error_condition(int ev) const noexcept final
{
// Use generic category for all known POSIX errno values (including zero)
// and system category otherwise.
switch (ev)
{
#if defined(_WIN32) && !defined(__CYGWIN__)
case 0:
return {0, generic_category_instance.obj};
// Convert Windows error code into a corresponding POSIX errno value.
#define X(w, e) case ERROR_##w: return {e, generic_category_instance.obj};
// This list is based on Cygwin's winsup/cygwin/errno.cc
X (ACCESS_DENIED, EACCES);
X (ACTIVE_CONNECTIONS, EAGAIN);
X (ALREADY_EXISTS, EEXIST);
X (BAD_DEVICE, ENODEV);
X (BAD_EXE_FORMAT, ENOEXEC);
X (BAD_NETPATH, ENOENT);
X (BAD_NET_NAME, ENOENT);
X (BAD_NET_RESP, ENOSYS);
X (BAD_PATHNAME, ENOENT);
X (BAD_PIPE, EINVAL);
X (BAD_UNIT, ENODEV);
X (BAD_USERNAME, EINVAL);
X (BEGINNING_OF_MEDIA, EIO);
X (BROKEN_PIPE, EPIPE);
X (BUSY, EBUSY);
X (BUS_RESET, EIO);
X (CALL_NOT_IMPLEMENTED, ENOSYS);
X (CANCELLED, EINTR);
X (CANNOT_MAKE, EPERM);
X (CHILD_NOT_COMPLETE, EBUSY);
X (COMMITMENT_LIMIT, EAGAIN);
X (CONNECTION_REFUSED, ECONNREFUSED);
X (CRC, EIO);
X (DEVICE_DOOR_OPEN, EIO);
X (DEVICE_IN_USE, EAGAIN);
X (DEVICE_REQUIRES_CLEANING, EIO);
X (DEV_NOT_EXIST, ENOENT);
X (DIRECTORY, ENOTDIR);
X (DIR_NOT_EMPTY, ENOTEMPTY);
X (DISK_CORRUPT, EIO);
#ifdef ENOSPC
X (DISK_FULL, ENOSPC);
#endif
X (DS_GENERIC_ERROR, EIO);
#ifdef ENOSPC
X (END_OF_MEDIA, ENOSPC);
#endif
X (EOM_OVERFLOW, EIO);
X (EXE_MACHINE_TYPE_MISMATCH, ENOEXEC);
X (EXE_MARKED_INVALID, ENOEXEC);
X (FILEMARK_DETECTED, EIO);
X (FILENAME_EXCED_RANGE, ENAMETOOLONG);
X (FILE_CORRUPT, EEXIST);
X (FILE_EXISTS, EEXIST);
X (FILE_INVALID, ENXIO);
X (FILE_NOT_FOUND, ENOENT);
#ifdef ENOSPC
X (HANDLE_DISK_FULL, ENOSPC);
#endif
X (INVALID_ADDRESS, EINVAL);
X (INVALID_AT_INTERRUPT_TIME, EINTR);
X (INVALID_BLOCK_LENGTH, EIO);
X (INVALID_DATA, EINVAL);
X (INVALID_DRIVE, ENODEV);
X (INVALID_EA_NAME, EINVAL);
X (INVALID_EXE_SIGNATURE, ENOEXEC);
X (INVALID_HANDLE, EBADF);
X (INVALID_NAME, ENOENT);
X (INVALID_PARAMETER, EINVAL);
X (INVALID_SIGNAL_NUMBER, EINVAL);
X (IOPL_NOT_ENABLED, ENOEXEC);
X (IO_DEVICE, EIO);
X (IO_INCOMPLETE, EAGAIN);
X (IO_PENDING, EAGAIN);
X (LOCK_VIOLATION, EBUSY);
X (MAX_THRDS_REACHED, EAGAIN);
X (META_EXPANSION_TOO_LONG, EINVAL);
X (MOD_NOT_FOUND, ENOENT);
X (MORE_DATA, EMSGSIZE);
X (NEGATIVE_SEEK, EINVAL);
X (NETNAME_DELETED, ENOENT);
X (NOACCESS, EFAULT);
X (NONE_MAPPED, EINVAL);
X (NONPAGED_SYSTEM_RESOURCES, EAGAIN);
X (NOT_ENOUGH_MEMORY, ENOMEM);
X (NOT_ENOUGH_QUOTA, EIO);
#ifdef EPERM
X (NOT_OWNER, EPERM);
#else
X (NOT_OWNER, EACCES);
#endif
X (NOT_SAME_DEVICE, EXDEV);
X (NOT_SUPPORTED, ENOSYS);
X (NO_DATA, EPIPE);
X (NO_DATA_DETECTED, EIO);
X (NO_MORE_SEARCH_HANDLES, ENFILE);
X (NO_PROC_SLOTS, EAGAIN);
X (NO_SIGNAL_SENT, EIO);
X (NO_SYSTEM_RESOURCES, EFBIG);
X (NO_TOKEN, EINVAL);
X (OPEN_FAILED, EIO);
X (OPEN_FILES, EAGAIN);
X (OUTOFMEMORY, ENOMEM);
X (PAGED_SYSTEM_RESOURCES, EAGAIN);
X (PAGEFILE_QUOTA, EAGAIN);
X (PATH_NOT_FOUND, ENOENT);
X (PIPE_BUSY, EBUSY);
X (PIPE_CONNECTED, EBUSY);
X (POSSIBLE_DEADLOCK, EDEADLK);
X (PRIVILEGE_NOT_HELD, EPERM);
X (PROCESS_ABORTED, EFAULT);
X (PROC_NOT_FOUND, ESRCH);
X (SECTOR_NOT_FOUND, EINVAL);
X (SEEK, EINVAL);
X (SERVICE_REQUEST_TIMEOUT, EBUSY);
X (SETMARK_DETECTED, EIO);
X (SHARING_BUFFER_EXCEEDED, ENOLCK);
X (SHARING_VIOLATION, EBUSY);
X (SIGNAL_PENDING, EBUSY);
X (SIGNAL_REFUSED, EIO);
X (THREAD_1_INACTIVE, EINVAL);
X (TIMEOUT, EBUSY);
X (TOO_MANY_LINKS, EMLINK);
X (TOO_MANY_OPEN_FILES, EMFILE);
X (UNEXP_NET_ERR, EIO);
X (WORKING_SET_QUOTA, EAGAIN);
X (WRITE_PROTECT, EROFS);
#undef X
#else
// List of errno macros from [cerrno.syn].
// C11 only defines EDOM, EILSEQ and ERANGE, the rest are from POSIX.
// They expand to integer constant expressions with type int,
// and distinct positive values, suitable for use in #if directives.
// POSIX adds more macros (but they're not defined on all targets,
// see config/os/.../error_constants.h), and POSIX allows
// EAGAIN == EWOULDBLOCK and ENOTSUP == EOPNOTSUPP.
#ifdef E2BIG
case E2BIG:
#endif
#ifdef EACCES
case EACCES:
#endif
#ifdef EADDRINUSE
case EADDRINUSE:
#endif
#ifdef EADDRNOTAVAIL
case EADDRNOTAVAIL:
#endif
#ifdef EAFNOSUPPORT
case EAFNOSUPPORT:
#endif
#ifdef EAGAIN
case EAGAIN:
#endif
#ifdef EALREADY
case EALREADY:
#endif
#ifdef EBADF
case EBADF:
#endif
#ifdef EBADMSG
case EBADMSG:
#endif
#ifdef EBUSY
case EBUSY:
#endif
#ifdef ECANCELED
case ECANCELED:
#endif
#ifdef ECHILD
case ECHILD:
#endif
#ifdef ECONNABORTED
case ECONNABORTED:
#endif
#ifdef ECONNREFUSED
case ECONNREFUSED:
#endif
#ifdef ECONNRESET
case ECONNRESET:
#endif
#ifdef EDEADLK
case EDEADLK:
#endif
#ifdef EDESTADDRREQ
case EDESTADDRREQ:
#endif
case EDOM:
#ifdef EEXIST
case EEXIST:
#endif
#ifdef EFAULT
case EFAULT:
#endif
#ifdef EFBIG
case EFBIG:
#endif
#ifdef EHOSTUNREACH
case EHOSTUNREACH:
#endif
#ifdef EIDRM
case EIDRM:
#endif
case EILSEQ:
#ifdef EINPROGRESS
case EINPROGRESS:
#endif
#ifdef EINTR
case EINTR:
#endif
#ifdef EINVAL
case EINVAL:
#endif
#ifdef EIO
case EIO:
#endif
#ifdef EISCONN
case EISCONN:
#endif
#ifdef EISDIR
case EISDIR:
#endif
#ifdef ELOOP
case ELOOP:
#endif
#ifdef EMFILE
case EMFILE:
#endif
#ifdef EMLINK
case EMLINK:
#endif
#ifdef EMSGSIZE
case EMSGSIZE:
#endif
#ifdef ENAMETOOLONG
case ENAMETOOLONG:
#endif
#ifdef ENETDOWN
case ENETDOWN:
#endif
#ifdef ENETRESET
case ENETRESET:
#endif
#ifdef ENETUNREACH
case ENETUNREACH:
#endif
#ifdef ENFILE
case ENFILE:
#endif
#ifdef ENOBUFS
case ENOBUFS:
#endif
#ifdef ENODATA
case ENODATA:
#endif
#ifdef ENODEV
case ENODEV:
#endif
#ifdef ENOENT
case ENOENT:
#endif
#ifdef ENOEXEC
case ENOEXEC:
#endif
#ifdef ENOLCK
case ENOLCK:
#endif
#ifdef ENOLINK
case ENOLINK:
#endif
#ifdef ENOMEM
case ENOMEM:
#endif
#ifdef ENOMSG
case ENOMSG:
#endif
#ifdef ENOPROTOOPT
case ENOPROTOOPT:
#endif
#ifdef ENOSPC
case ENOSPC:
#endif
#ifdef ENOSR
case ENOSR:
#endif
#ifdef ENOSTR
case ENOSTR:
#endif
#ifdef ENOSYS
case ENOSYS:
#endif
#ifdef ENOTCONN
case ENOTCONN:
#endif
#ifdef ENOTDIR
case ENOTDIR:
#endif
#if defined ENOTEMPTY && (!defined EEXIST || ENOTEMPTY != EEXIST)
// AIX sometimes uses the same value for EEXIST and ENOTEMPTY
case ENOTEMPTY:
#endif
#ifdef ENOTRECOVERABLE
case ENOTRECOVERABLE:
#endif
#ifdef ENOTSOCK
case ENOTSOCK:
#endif
#if defined ENOTSUP && (!defined ENOSYS || ENOTSUP != ENOSYS)
// zTPF uses the same value for ENOSYS and ENOTSUP
case ENOTSUP:
#endif
#ifdef ENOTTY
case ENOTTY:
#endif
#ifdef ENXIO
case ENXIO:
#endif
#if defined EOPNOTSUPP && (!defined ENOTSUP || EOPNOTSUPP != ENOTSUP)
case EOPNOTSUPP:
#endif
#ifdef EOVERFLOW
case EOVERFLOW:
#endif
#ifdef EOWNERDEAD
case EOWNERDEAD:
#endif
#ifdef EPERM
case EPERM:
#endif
#ifdef EPIPE
case EPIPE:
#endif
#ifdef EPROTO
case EPROTO:
#endif
#ifdef EPROTONOSUPPORT
case EPROTONOSUPPORT:
#endif
#ifdef EPROTOTYPE
case EPROTOTYPE:
#endif
case ERANGE:
#ifdef EROFS
case EROFS:
#endif
#ifdef ESPIPE
case ESPIPE:
#endif
#ifdef ESRCH
case ESRCH:
#endif
#ifdef ETIME
case ETIME:
#endif
#ifdef ETIMEDOUT
case ETIMEDOUT:
#endif
#ifdef ETXTBSY
case ETXTBSY:
#endif
#if defined EWOULDBLOCK && (!defined EAGAIN || EWOULDBLOCK != EAGAIN)
case EWOULDBLOCK:
#endif
#ifdef EXDEV
case EXDEV:
#endif
case 0:
return std::error_condition(ev, generic_category_instance.obj);
/* Additional system-dependent mappings from non-standard error codes
* to one of the POSIX values above would go here, e.g.
case EBLAH:
return std::error_condition(EINVAL, std::generic_category());
*/
#endif
default:
return std::error_condition(ev, *this);
}
}
// Override this to avoid a virtual call to default_error_condition(i).
bool
equivalent(int i, const std::error_condition& cond) const noexcept final
{ return system_error_category::default_error_condition(i) == cond; }
};
__constinit constant_init<system_error_category> system_category_instance{};
}
namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
void
__throw_system_error(int __i __attribute__((unused)))
{
_GLIBCXX_THROW_OR_ABORT(system_error(__i, generic_category_instance.obj));
}
error_category::~error_category() = default;
_GLIBCXX_BEGIN_INLINE_ABI_NAMESPACE(_V2)
const error_category&
system_category() noexcept { return system_category_instance.obj; }
const error_category&
generic_category() noexcept { return generic_category_instance.obj; }
_GLIBCXX_END_INLINE_ABI_NAMESPACE(_V2)
system_error::~system_error() = default;
error_condition
error_category::default_error_condition(int __i) const noexcept
{ return error_condition(__i, *this); }
bool
error_category::equivalent(int __i,
const error_condition& __cond) const noexcept
{ return default_error_condition(__i) == __cond; }
bool
error_category::equivalent(const error_code& __code, int __i) const noexcept
{ return *this == __code.category() && __code.value() == __i; }
error_condition
error_code::default_error_condition() const noexcept
{ return category().default_error_condition(value()); }
#if _GLIBCXX_USE_CXX11_ABI
// Return error_category::message() as a COW string
__cow_string
error_category::_M_message(int i) const
{
string msg = this->message(i);
return {msg.c_str(), msg.length()};
}
#endif
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace