[libc-commits] [libc] 42bcb35 - [libc] add strerror
Michael Jones via libc-commits
libc-commits at lists.llvm.org
Tue Sep 20 16:23:49 PDT 2022
Author: Michael Jones
Date: 2022-09-20T16:23:36-07:00
New Revision: 42bcb35c0f2946b66ae397515823a3792f14b067
URL: https://github.com/llvm/llvm-project/commit/42bcb35c0f2946b66ae397515823a3792f14b067
DIFF: https://github.com/llvm/llvm-project/commit/42bcb35c0f2946b66ae397515823a3792f14b067.diff
LOG: [libc] add strerror
Strerror maps error numbers to strings. Additionally, a utility for
mapping errors to strings was added so that it could be reused for
perror and similar.
Reviewed By: sivachandra
Differential Revision: https://reviews.llvm.org/D134074
Added:
libc/src/__support/error_to_string.cpp
libc/src/__support/error_to_string.h
libc/src/string/strerror.cpp
libc/src/string/strerror.h
libc/test/src/string/strerror_test.cpp
Modified:
libc/config/linux/x86_64/entrypoints.txt
libc/src/__support/CMakeLists.txt
libc/src/__support/integer_to_string.h
libc/src/string/CMakeLists.txt
libc/test/ErrnoSetterMatcher.h
libc/test/src/string/CMakeLists.txt
Removed:
################################################################################
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index a0313d30c1921..fe39ad8a9872a 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -57,6 +57,7 @@ set(TARGET_LIBC_ENTRYPOINTS
# string.h entrypoints that depend on malloc
libc.src.string.strdup
libc.src.string.strndup
+ libc.src.string.strerror
# inttypes.h entrypoints
libc.src.inttypes.imaxabs
diff --git a/libc/src/__support/CMakeLists.txt b/libc/src/__support/CMakeLists.txt
index b92872da94922..78d5df553946f 100644
--- a/libc/src/__support/CMakeLists.txt
+++ b/libc/src/__support/CMakeLists.txt
@@ -72,6 +72,19 @@ add_header_library(
libc.src.errno.errno
)
+
+add_object_library(
+ error_to_string
+ HDRS
+ error_to_string.h
+ SRCS
+ error_to_string.cpp
+ DEPENDS
+ libc.include.errno
+ libc.src.__support.CPP.string_view
+ libc.src.__support.CPP.stringstream
+)
+
add_header_library(
integer_operations
HDRS
diff --git a/libc/src/__support/error_to_string.cpp b/libc/src/__support/error_to_string.cpp
new file mode 100644
index 0000000000000..dca6b8a968ba2
--- /dev/null
+++ b/libc/src/__support/error_to_string.cpp
@@ -0,0 +1,251 @@
+//===-- Implementation of a class for mapping errors to strings -----------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/__support/error_to_string.h"
+#include "src/__support/CPP/string_view.h"
+#include "src/__support/CPP/stringstream.h"
+#include <errno.h>
+#include <stddef.h>
+
+namespace __llvm_libc {
+namespace internal {
+
+constexpr size_t max_buff_size() {
+ constexpr size_t unknown_str_len = sizeof("Unknown error");
+ constexpr size_t max_num_len =
+ __llvm_libc::IntegerToString::dec_bufsize<int>();
+ // the buffer should be able to hold "Unknown error" + ' ' + num_str
+ return (unknown_str_len + 1 + max_num_len) * sizeof(char);
+}
+
+// This is to hold error strings that have to be custom built. It may be
+// rewritten on every call to strerror (or other error to string function).
+constexpr size_t BUFFER_SIZE = max_buff_size();
+thread_local char error_buffer[BUFFER_SIZE];
+
+struct ErrMsgMapping {
+ int err_num;
+ cpp::string_view err_msg;
+
+public:
+ constexpr ErrMsgMapping(int num, const char *msg)
+ : err_num(num), err_msg(msg) {
+ ;
+ }
+};
+
+constexpr ErrMsgMapping raw_err_array[] = {
+ ErrMsgMapping(0, "Success"),
+ ErrMsgMapping(EPERM, "Operation not permitted"),
+ ErrMsgMapping(ENOENT, "No such file or directory"),
+ ErrMsgMapping(ESRCH, "No such process"),
+ ErrMsgMapping(EINTR, "Interrupted system call"),
+ ErrMsgMapping(EIO, "Input/output error"),
+ ErrMsgMapping(ENXIO, "No such device or address"),
+ ErrMsgMapping(E2BIG, "Argument list too long"),
+ ErrMsgMapping(ENOEXEC, "Exec format error"),
+ ErrMsgMapping(EBADF, "Bad file descriptor"),
+ ErrMsgMapping(ECHILD, "No child processes"),
+ ErrMsgMapping(EAGAIN, "Resource temporarily unavailable"),
+ ErrMsgMapping(ENOMEM, "Cannot allocate memory"),
+ ErrMsgMapping(EACCES, "Permission denied"),
+ ErrMsgMapping(EFAULT, "Bad address"),
+ ErrMsgMapping(ENOTBLK, "Block device required"),
+ ErrMsgMapping(EBUSY, "Device or resource busy"),
+ ErrMsgMapping(EEXIST, "File exists"),
+ ErrMsgMapping(EXDEV, "Invalid cross-device link"),
+ ErrMsgMapping(ENODEV, "No such device"),
+ ErrMsgMapping(ENOTDIR, "Not a directory"),
+ ErrMsgMapping(EISDIR, "Is a directory"),
+ ErrMsgMapping(EINVAL, "Invalid argument"),
+ ErrMsgMapping(ENFILE, "Too many open files in system"),
+ ErrMsgMapping(EMFILE, "Too many open files"),
+ ErrMsgMapping(ENOTTY, "Inappropriate ioctl for device"),
+ ErrMsgMapping(ETXTBSY, "Text file busy"),
+ ErrMsgMapping(EFBIG, "File too large"),
+ ErrMsgMapping(ENOSPC, "No space left on device"),
+ ErrMsgMapping(ESPIPE, "Illegal seek"),
+ ErrMsgMapping(EROFS, "Read-only file system"),
+ ErrMsgMapping(EMLINK, "Too many links"),
+ ErrMsgMapping(EPIPE, "Broken pipe"),
+ ErrMsgMapping(EDOM, "Numerical argument out of domain"),
+ ErrMsgMapping(ERANGE, "Numerical result out of range"),
+ ErrMsgMapping(EDEADLK, "Resource deadlock avoided"),
+ ErrMsgMapping(ENAMETOOLONG, "File name too long"),
+ ErrMsgMapping(ENOLCK, "No locks available"),
+ ErrMsgMapping(ENOSYS, "Function not implemented"),
+ ErrMsgMapping(ENOTEMPTY, "Directory not empty"),
+ ErrMsgMapping(ELOOP, "Too many levels of symbolic links"),
+ // No error for 41. Would be EWOULDBLOCK
+ ErrMsgMapping(ENOMSG, "No message of desired type"),
+ ErrMsgMapping(EIDRM, "Identifier removed"),
+ ErrMsgMapping(ECHRNG, "Channel number out of range"),
+ ErrMsgMapping(EL2NSYNC, "Level 2 not synchronized"),
+ ErrMsgMapping(EL3HLT, "Level 3 halted"),
+ ErrMsgMapping(EL3RST, "Level 3 reset"),
+ ErrMsgMapping(ELNRNG, "Link number out of range"),
+ ErrMsgMapping(EUNATCH, "Protocol driver not attached"),
+ ErrMsgMapping(ENOCSI, "No CSI structure available"),
+ ErrMsgMapping(EL2HLT, "Level 2 halted"),
+ ErrMsgMapping(EBADE, "Invalid exchange"),
+ ErrMsgMapping(EBADR, "Invalid request descriptor"),
+ ErrMsgMapping(EXFULL, "Exchange full"),
+ ErrMsgMapping(ENOANO, "No anode"),
+ ErrMsgMapping(EBADRQC, "Invalid request code"),
+ ErrMsgMapping(EBADSLT, "Invalid slot"),
+ // No error for 58. Would be EDEADLOCK.
+ ErrMsgMapping(EBFONT, "Bad font file format"),
+ ErrMsgMapping(ENOSTR, "Device not a stream"),
+ ErrMsgMapping(ENODATA, "No data available"),
+ ErrMsgMapping(ETIME, "Timer expired"),
+ ErrMsgMapping(ENOSR, "Out of streams resources"),
+ ErrMsgMapping(ENONET, "Machine is not on the network"),
+ ErrMsgMapping(ENOPKG, "Package not installed"),
+ ErrMsgMapping(EREMOTE, "Object is remote"),
+ ErrMsgMapping(ENOLINK, "Link has been severed"),
+ ErrMsgMapping(EADV, "Advertise error"),
+ ErrMsgMapping(ESRMNT, "Srmount error"),
+ ErrMsgMapping(ECOMM, "Communication error on send"),
+ ErrMsgMapping(EPROTO, "Protocol error"),
+ ErrMsgMapping(EMULTIHOP, "Multihop attempted"),
+ ErrMsgMapping(EDOTDOT, "RFS specific error"),
+ ErrMsgMapping(EBADMSG, "Bad message"),
+ ErrMsgMapping(EOVERFLOW, "Value too large for defined data type"),
+ ErrMsgMapping(ENOTUNIQ, "Name not unique on network"),
+ ErrMsgMapping(EBADFD, "File descriptor in bad state"),
+ ErrMsgMapping(EREMCHG, "Remote address changed"),
+ ErrMsgMapping(ELIBACC, "Can not access a needed shared library"),
+ ErrMsgMapping(ELIBBAD, "Accessing a corrupted shared library"),
+ ErrMsgMapping(ELIBSCN, ".lib section in a.out corrupted"),
+ ErrMsgMapping(ELIBMAX, "Attempting to link in too many shared libraries"),
+ ErrMsgMapping(ELIBEXEC, "Cannot exec a shared library directly"),
+ ErrMsgMapping(EILSEQ, "Invalid or incomplete multibyte or wide character"),
+ ErrMsgMapping(ERESTART, "Interrupted system call should be restarted"),
+ ErrMsgMapping(ESTRPIPE, "Streams pipe error"),
+ ErrMsgMapping(EUSERS, "Too many users"),
+ ErrMsgMapping(ENOTSOCK, "Socket operation on non-socket"),
+ ErrMsgMapping(EDESTADDRREQ, "Destination address required"),
+ ErrMsgMapping(EMSGSIZE, "Message too long"),
+ ErrMsgMapping(EPROTOTYPE, "Protocol wrong type for socket"),
+ ErrMsgMapping(ENOPROTOOPT, "Protocol not available"),
+ ErrMsgMapping(EPROTONOSUPPORT, "Protocol not supported"),
+ ErrMsgMapping(ESOCKTNOSUPPORT, "Socket type not supported"),
+ ErrMsgMapping(ENOTSUP, "Operation not supported"),
+ ErrMsgMapping(EPFNOSUPPORT, "Protocol family not supported"),
+ ErrMsgMapping(EAFNOSUPPORT, "Address family not supported by protocol"),
+ ErrMsgMapping(EADDRINUSE, "Address already in use"),
+ ErrMsgMapping(EADDRNOTAVAIL, "Cannot assign requested address"),
+ ErrMsgMapping(ENETDOWN, "Network is down"),
+ ErrMsgMapping(ENETUNREACH, "Network is unreachable"),
+ ErrMsgMapping(ENETRESET, "Network dropped connection on reset"),
+ ErrMsgMapping(ECONNABORTED, "Software caused connection abort"),
+ ErrMsgMapping(ECONNRESET, "Connection reset by peer"),
+ ErrMsgMapping(ENOBUFS, "No buffer space available"),
+ ErrMsgMapping(EISCONN, "Transport endpoint is already connected"),
+ ErrMsgMapping(ENOTCONN, "Transport endpoint is not connected"),
+ ErrMsgMapping(ESHUTDOWN, "Cannot send after transport endpoint shutdown"),
+ ErrMsgMapping(ETOOMANYREFS, "Too many references: cannot splice"),
+ ErrMsgMapping(ETIMEDOUT, "Connection timed out"),
+ ErrMsgMapping(ECONNREFUSED, "Connection refused"),
+ ErrMsgMapping(EHOSTDOWN, "Host is down"),
+ ErrMsgMapping(EHOSTUNREACH, "No route to host"),
+ ErrMsgMapping(EALREADY, "Operation already in progress"),
+ ErrMsgMapping(EINPROGRESS, "Operation now in progress"),
+ ErrMsgMapping(ESTALE, "Stale file handle"),
+ ErrMsgMapping(EUCLEAN, "Structure needs cleaning"),
+ ErrMsgMapping(ENOTNAM, "Not a XENIX named type file"),
+ ErrMsgMapping(ENAVAIL, "No XENIX semaphores available"),
+ ErrMsgMapping(EISNAM, "Is a named type file"),
+ ErrMsgMapping(EREMOTEIO, "Remote I/O error"),
+ ErrMsgMapping(EDQUOT, "Disk quota exceeded"),
+ ErrMsgMapping(ENOMEDIUM, "No medium found"),
+ ErrMsgMapping(EMEDIUMTYPE, "Wrong medium type"),
+ ErrMsgMapping(ECANCELED, "Operation canceled"),
+ ErrMsgMapping(ENOKEY, "Required key not available"),
+ ErrMsgMapping(EKEYEXPIRED, "Key has expired"),
+ ErrMsgMapping(EKEYREVOKED, "Key has been revoked"),
+ ErrMsgMapping(EKEYREJECTED, "Key was rejected by service"),
+ ErrMsgMapping(EOWNERDEAD, "Owner died"),
+ ErrMsgMapping(ENOTRECOVERABLE, "State not recoverable"),
+ ErrMsgMapping(ERFKILL, "Operation not possible due to RF-kill"),
+ ErrMsgMapping(EHWPOISON, "Memory page has hardware error"),
+};
+
+constexpr size_t total_str_len(const ErrMsgMapping *array, size_t len) {
+ size_t total = 0;
+ for (size_t i = 0; i < len; ++i) {
+ // add 1 for the null terminator.
+ total += array[i].err_msg.size() + 1;
+ }
+ return total;
+}
+
+// Since the StringMappings array is a map from error numbers to their
+// corresponding strings, we have to have an array large enough we can use the
+// error numbers as indexes. Thankfully there are 132 errors in the above list
+// (41 and 58 are skipped) and the highest number is 133. If other platforms use
+//
diff erent error numbers, then this number may need to be adjusted.
+// Also if negative numbers or particularly large numbers are used, then the
+// array should be turned into a proper hashmap.
+constexpr size_t ERR_ARRAY_SIZE = 134;
+
+class ErrorMapper {
+
+ // const char *StringMappings[ERR_ARRAY_SIZE] = {""};
+ int err_offsets[ERR_ARRAY_SIZE] = {-1};
+ char string_array[total_str_len(
+ raw_err_array, sizeof(raw_err_array) / sizeof(ErrMsgMapping))] = {'\0'};
+
+public:
+ constexpr ErrorMapper() {
+ cpp::string_view string_mappings[ERR_ARRAY_SIZE] = {""};
+ for (size_t i = 0; i < (sizeof(raw_err_array) / sizeof(ErrMsgMapping)); ++i)
+ string_mappings[raw_err_array[i].err_num] = raw_err_array[i].err_msg;
+
+ size_t string_array_index = 0;
+ for (size_t cur_err = 0; cur_err < ERR_ARRAY_SIZE; ++cur_err) {
+ if (string_mappings[cur_err].size() != 0) {
+ err_offsets[cur_err] = string_array_index;
+ // No need to replace with proper strcpy, this is evaluated at compile
+ // time.
+ for (size_t i = 0; i < string_mappings[cur_err].size() + 1;
+ ++i, ++string_array_index) {
+ string_array[string_array_index] = string_mappings[cur_err][i];
+ }
+ } else {
+ err_offsets[cur_err] = -1;
+ }
+ }
+ }
+
+ cpp::string_view get_str(int err_num) const {
+ if (err_num >= 0 && static_cast<size_t>(err_num) < ERR_ARRAY_SIZE &&
+ err_offsets[err_num] != -1) {
+ return const_cast<char *>(string_array + err_offsets[err_num]);
+ } else {
+ // if the buffer can't hold "Unknown error" + ' ' + num_str, then just
+ // return "Unknown error".
+ if (BUFFER_SIZE <
+ (sizeof("Unknown error") + 1 + IntegerToString::dec_bufsize<int>()))
+ return const_cast<char *>("Unknown error");
+
+ cpp::StringStream buffer_stream({error_buffer, BUFFER_SIZE});
+ buffer_stream << "Unknown error" << ' ' << err_num << '\0';
+ return buffer_stream.str();
+ }
+ }
+};
+
+static constexpr ErrorMapper error_mapper;
+
+} // namespace internal
+
+cpp::string_view get_error_string(int err_num) {
+ return internal::error_mapper.get_str(err_num);
+}
+} // namespace __llvm_libc
diff --git a/libc/src/__support/error_to_string.h b/libc/src/__support/error_to_string.h
new file mode 100644
index 0000000000000..72b2e9c93e65c
--- /dev/null
+++ b/libc/src/__support/error_to_string.h
@@ -0,0 +1,21 @@
+//===-- Definition of a class for mapping errors to strings -----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/__support/CPP/string_view.h"
+#include "src/__support/integer_to_string.h"
+
+#ifndef LLVM_LIBC_SRC_SUPPORT_ERROR_TO_STRING
+#define LLVM_LIBC_SRC_SUPPORT_ERROR_TO_STRING
+
+namespace __llvm_libc {
+
+cpp::string_view get_error_string(int err_num);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_SUPPORT_ERROR_TO_STRING
diff --git a/libc/src/__support/integer_to_string.h b/libc/src/__support/integer_to_string.h
index 74272f18b361c..2888ab3dd12a7 100644
--- a/libc/src/__support/integer_to_string.h
+++ b/libc/src/__support/integer_to_string.h
@@ -11,9 +11,9 @@
#include <stdint.h>
-#include "src/__support/CPP/string_view.h"
#include "src/__support/CPP/optional.h"
#include "src/__support/CPP/span.h"
+#include "src/__support/CPP/string_view.h"
#include "src/__support/CPP/type_traits.h"
namespace __llvm_libc {
@@ -45,9 +45,9 @@ namespace __llvm_libc {
// auto str = IntegerToString::convert<30>(a, b30buf);
class IntegerToString {
static cpp::string_view convert_uintmax(uintmax_t uval,
- cpp::span<char> &buffer,
- bool lowercase,
- const uint8_t conv_base) {
+ cpp::span<char> &buffer,
+ bool lowercase,
+ const uint8_t conv_base) {
const char a = lowercase ? 'a' : 'A';
size_t len = 0;
@@ -68,8 +68,8 @@ class IntegerToString {
}
static cpp::string_view convert_intmax(intmax_t val, cpp::span<char> &buffer,
- bool lowercase,
- const uint8_t conv_base) {
+ bool lowercase,
+ const uint8_t conv_base) {
if (val >= 0)
return convert_uintmax(uintmax_t(val), buffer, lowercase, conv_base);
uintmax_t uval = uintmax_t(-val);
@@ -139,7 +139,7 @@ class IntegerToString {
cpp::enable_if_t<2 <= BASE && BASE <= 36 && cpp::is_integral_v<T>,
int> = 0>
static cpp::optional<cpp::string_view> convert(T val, cpp::span<char> buffer,
- bool lowercase = true) {
+ bool lowercase = true) {
if (buffer.size() < bufsize<BASE, T>())
return cpp::optional<cpp::string_view>();
if (cpp::is_signed_v<T>)
@@ -155,7 +155,7 @@ class IntegerToString {
template <typename T, cpp::enable_if_t<cpp::is_integral_v<T>, int> = 0>
static cpp::optional<cpp::string_view> hex(T val, cpp::span<char> buffer,
- bool lowercase = true) {
+ bool lowercase = true) {
return convert<16>(val, buffer, lowercase);
}
diff --git a/libc/src/string/CMakeLists.txt b/libc/src/string/CMakeLists.txt
index 68962e21c15d1..4740c761d1114 100644
--- a/libc/src/string/CMakeLists.txt
+++ b/libc/src/string/CMakeLists.txt
@@ -128,6 +128,17 @@ add_entrypoint_object(
libc.include.stdlib
)
+add_entrypoint_object(
+ strerror
+ SRCS
+ strerror.cpp
+ HDRS
+ strerror.h
+ DEPENDS
+ libc.src.__support.error_to_string
+ libc.src.__support.CPP.span
+)
+
add_entrypoint_object(
strlcat
SRCS
diff --git a/libc/src/string/strerror.cpp b/libc/src/string/strerror.cpp
new file mode 100644
index 0000000000000..0297b86d20d46
--- /dev/null
+++ b/libc/src/string/strerror.cpp
@@ -0,0 +1,20 @@
+//===-- Implementation of strerror ----------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/string/strerror.h"
+#include "src/__support/CPP/span.h"
+#include "src/__support/common.h"
+#include "src/__support/error_to_string.h"
+
+namespace __llvm_libc {
+
+LLVM_LIBC_FUNCTION(char *, strerror, (int err_num)) {
+ return const_cast<char *>(get_error_string(err_num).data());
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/string/strerror.h b/libc/src/string/strerror.h
new file mode 100644
index 0000000000000..b9ddd71d62850
--- /dev/null
+++ b/libc/src/string/strerror.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for strerror ----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STRING_STRERROR_H
+#define LLVM_LIBC_SRC_STRING_STRERROR_H
+
+namespace __llvm_libc {
+
+char *strerror(int errnum);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_STRING_STRERROR_H
diff --git a/libc/test/ErrnoSetterMatcher.h b/libc/test/ErrnoSetterMatcher.h
index 007b2e6c0ae17..3d8c914b0491c 100644
--- a/libc/test/ErrnoSetterMatcher.h
+++ b/libc/test/ErrnoSetterMatcher.h
@@ -18,7 +18,7 @@ namespace testing {
namespace internal {
-extern "C" const char *strerror(int);
+extern "C" char *strerror(int);
template <typename T> class ErrnoSetterMatcher : public Matcher<T> {
T ExpectedReturn;
diff --git a/libc/test/src/string/CMakeLists.txt b/libc/test/src/string/CMakeLists.txt
index 6e4c227ce374e..fe12c0d436b8e 100644
--- a/libc/test/src/string/CMakeLists.txt
+++ b/libc/test/src/string/CMakeLists.txt
@@ -123,6 +123,16 @@ add_libc_unittest(
libc.src.string.strdup
)
+add_libc_unittest(
+ strerror_test
+ SUITE
+ libc_string_unittests
+ SRCS
+ strerror_test.cpp
+ DEPENDS
+ libc.src.string.strerror
+)
+
add_libc_unittest(
strlcat_test
SUITE
diff --git a/libc/test/src/string/strerror_test.cpp b/libc/test/src/string/strerror_test.cpp
new file mode 100644
index 0000000000000..dfe77223e3c0f
--- /dev/null
+++ b/libc/test/src/string/strerror_test.cpp
@@ -0,0 +1,162 @@
+//===-- Unittests for strerror --------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/string/strerror.h"
+#include "utils/UnitTest/Test.h"
+
+TEST(LlvmLibcStrErrorTest, KnownErrors) {
+ ASSERT_STREQ(__llvm_libc::strerror(0), "Success");
+
+ const char *message_array[] = {
+ "Success",
+ "Operation not permitted",
+ "No such file or directory",
+ "No such process",
+ "Interrupted system call",
+ "Input/output error",
+ "No such device or address",
+ "Argument list too long",
+ "Exec format error",
+ "Bad file descriptor",
+ "No child processes",
+ "Resource temporarily unavailable",
+ "Cannot allocate memory",
+ "Permission denied",
+ "Bad address",
+ "Block device required",
+ "Device or resource busy",
+ "File exists",
+ "Invalid cross-device link",
+ "No such device",
+ "Not a directory",
+ "Is a directory",
+ "Invalid argument",
+ "Too many open files in system",
+ "Too many open files",
+ "Inappropriate ioctl for device",
+ "Text file busy",
+ "File too large",
+ "No space left on device",
+ "Illegal seek",
+ "Read-only file system",
+ "Too many links",
+ "Broken pipe",
+ "Numerical argument out of domain",
+ "Numerical result out of range",
+ "Resource deadlock avoided",
+ "File name too long",
+ "No locks available",
+ "Function not implemented",
+ "Directory not empty",
+ "Too many levels of symbolic links",
+ "Unknown error 41", // Unknown
+ "No message of desired type",
+ "Identifier removed",
+ "Channel number out of range",
+ "Level 2 not synchronized",
+ "Level 3 halted",
+ "Level 3 reset",
+ "Link number out of range",
+ "Protocol driver not attached",
+ "No CSI structure available",
+ "Level 2 halted",
+ "Invalid exchange",
+ "Invalid request descriptor",
+ "Exchange full",
+ "No anode",
+ "Invalid request code",
+ "Invalid slot",
+ "Unknown error 58", // Unknown
+ "Bad font file format",
+ "Device not a stream",
+ "No data available",
+ "Timer expired",
+ "Out of streams resources",
+ "Machine is not on the network",
+ "Package not installed",
+ "Object is remote",
+ "Link has been severed",
+ "Advertise error",
+ "Srmount error",
+ "Communication error on send",
+ "Protocol error",
+ "Multihop attempted",
+ "RFS specific error",
+ "Bad message",
+ "Value too large for defined data type",
+ "Name not unique on network",
+ "File descriptor in bad state",
+ "Remote address changed",
+ "Can not access a needed shared library",
+ "Accessing a corrupted shared library",
+ ".lib section in a.out corrupted",
+ "Attempting to link in too many shared libraries",
+ "Cannot exec a shared library directly",
+ "Invalid or incomplete multibyte or wide character",
+ "Interrupted system call should be restarted",
+ "Streams pipe error",
+ "Too many users",
+ "Socket operation on non-socket",
+ "Destination address required",
+ "Message too long",
+ "Protocol wrong type for socket",
+ "Protocol not available",
+ "Protocol not supported",
+ "Socket type not supported",
+ "Operation not supported",
+ "Protocol family not supported",
+ "Address family not supported by protocol",
+ "Address already in use",
+ "Cannot assign requested address",
+ "Network is down",
+ "Network is unreachable",
+ "Network dropped connection on reset",
+ "Software caused connection abort",
+ "Connection reset by peer",
+ "No buffer space available",
+ "Transport endpoint is already connected",
+ "Transport endpoint is not connected",
+ "Cannot send after transport endpoint shutdown",
+ "Too many references: cannot splice",
+ "Connection timed out",
+ "Connection refused",
+ "Host is down",
+ "No route to host",
+ "Operation already in progress",
+ "Operation now in progress",
+ "Stale file handle",
+ "Structure needs cleaning",
+ "Not a XENIX named type file",
+ "No XENIX semaphores available",
+ "Is a named type file",
+ "Remote I/O error",
+ "Disk quota exceeded",
+ "No medium found",
+ "Wrong medium type",
+ "Operation canceled",
+ "Required key not available",
+ "Key has expired",
+ "Key has been revoked",
+ "Key was rejected by service",
+ "Owner died",
+ "State not recoverable",
+ "Operation not possible due to RF-kill",
+ "Memory page has hardware error",
+ };
+
+ for (size_t i = 0; i < (sizeof(message_array) / sizeof(char *)); ++i) {
+ EXPECT_STREQ(__llvm_libc::strerror(i), message_array[i]);
+ }
+}
+
+TEST(LlvmLibcStrErrorTest, UnknownErrors) {
+ ASSERT_STREQ(__llvm_libc::strerror(-1), "Unknown error -1");
+ ASSERT_STREQ(__llvm_libc::strerror(134), "Unknown error 134");
+ ASSERT_STREQ(__llvm_libc::strerror(2147483647), "Unknown error 2147483647");
+ ASSERT_STREQ(__llvm_libc::strerror(-2147483648), "Unknown error -2147483648");
+}
More information about the libc-commits
mailing list