Sfoglia il codice sorgente

LibC: Implement strerror_r()

This implements the XSI-compliant version of strerror_r() - as opposed
to the GNU-specific variant.

The function explicitly saves errno so as to not accidentally change it
with one of the calls to other functions.
Gunnar Beutner 4 anni fa
parent
commit
c81b3e1ee3

+ 1 - 0
Tests/LibC/CMakeLists.txt

@@ -6,6 +6,7 @@ set(TEST_SOURCES
     ${CMAKE_CURRENT_SOURCE_DIR}/TestLibCExec.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/TestLibCDirEnt.cpp
     ${CMAKE_CURRENT_SOURCE_DIR}/TestLibCInodeWatcher.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/TestLibCString.cpp
 )
 
 file(GLOB CMD_SOURCES  CONFIGURE_DEPENDS "*.cpp")

+ 18 - 0
Tests/LibC/TestLibCString.cpp

@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2021, Gunnar Beutner <gbeutner@serenityos.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <LibTest/TestCase.h>
+#include <errno.h>
+#include <string.h>
+
+TEST_CASE(strerror_r_basic)
+{
+    EXPECT_EQ(strerror_r(1000, nullptr, 0), EINVAL);
+    EXPECT_EQ(strerror_r(EFAULT, nullptr, 0), ERANGE);
+    char buf[64];
+    EXPECT_EQ(strerror_r(EFAULT, buf, sizeof(buf)), 0);
+    EXPECT_EQ(strcmp(buf, "Bad address"), 0);
+}

+ 20 - 0
Userland/Libraries/LibC/string.cpp

@@ -354,6 +354,26 @@ const char* const sys_errlist[] = {
 
 int sys_nerr = EMAXERRNO;
 
+int strerror_r(int errnum, char* buf, size_t buflen)
+{
+    auto saved_errno = errno;
+    if (errnum >= EMAXERRNO) {
+        auto rc = strlcpy(buf, "unknown error", buflen);
+        if (rc >= buflen)
+            dbgln("strerror_r(): Invalid error number '{}' specified and the output buffer is too small.", errnum);
+        errno = saved_errno;
+        return EINVAL;
+    }
+    auto text = strerror(errnum);
+    auto rc = strlcpy(buf, text, buflen);
+    if (rc >= buflen) {
+        errno = saved_errno;
+        return ERANGE;
+    }
+    errno = saved_errno;
+    return 0;
+}
+
 char* strerror(int errnum)
 {
     if (errnum < 0 || errnum >= EMAXERRNO) {

+ 1 - 0
Userland/Libraries/LibC/string.h

@@ -43,6 +43,7 @@ char* strncat(char* dest, const char* src, size_t);
 
 size_t strspn(const char*, const char* accept);
 size_t strcspn(const char*, const char* reject);
+int strerror_r(int, char*, size_t);
 char* strerror(int errnum);
 char* strsignal(int signum);
 char* strpbrk(const char*, const char* accept);