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.
This commit is contained in:
Gunnar Beutner 2021-05-24 16:43:12 +02:00 committed by Andreas Kling
parent 3526fbbc5f
commit c81b3e1ee3
Notes: sideshowbarker 2024-07-18 17:25:18 +09:00
4 changed files with 40 additions and 0 deletions

View file

@ -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")

View file

@ -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);
}

View file

@ -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) {

View file

@ -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);