[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