From c81b3e1ee3c005f1703f8a9e47b53b3ed836fc32 Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Mon, 24 May 2021 16:43:12 +0200 Subject: [PATCH] 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. --- Tests/LibC/CMakeLists.txt | 1 + Tests/LibC/TestLibCString.cpp | 18 ++++++++++++++++++ Userland/Libraries/LibC/string.cpp | 20 ++++++++++++++++++++ Userland/Libraries/LibC/string.h | 1 + 4 files changed, 40 insertions(+) create mode 100644 Tests/LibC/TestLibCString.cpp diff --git a/Tests/LibC/CMakeLists.txt b/Tests/LibC/CMakeLists.txt index d18144aff4..a4f8a4ce0b 100644 --- a/Tests/LibC/CMakeLists.txt +++ b/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") diff --git a/Tests/LibC/TestLibCString.cpp b/Tests/LibC/TestLibCString.cpp new file mode 100644 index 0000000000..57ff705657 --- /dev/null +++ b/Tests/LibC/TestLibCString.cpp @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2021, Gunnar Beutner + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include + +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); +} diff --git a/Userland/Libraries/LibC/string.cpp b/Userland/Libraries/LibC/string.cpp index db74946ae8..3847afb6dc 100644 --- a/Userland/Libraries/LibC/string.cpp +++ b/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) { diff --git a/Userland/Libraries/LibC/string.h b/Userland/Libraries/LibC/string.h index beaf594a33..d7010ef6ac 100644 --- a/Userland/Libraries/LibC/string.h +++ b/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);