From a9f95b769efe4fa4d4dc4a01b5bbfc4e3571a389 Mon Sep 17 00:00:00 2001 From: Michael Jones Date: Tue, 4 Oct 2022 16:47:24 -0700 Subject: [libc] add strerror_r function I've implemente the gnu variant of strerror_r since that seems to be the one more relevant to what we're trying to do. Differential Revision: https://reviews.llvm.org/D135227 --- libc/config/linux/x86_64/entrypoints.txt | 3 ++- libc/spec/gnu_ext.td | 5 +++++ libc/src/__support/error_to_string.cpp | 14 ++++++++++---- libc/src/__support/error_to_string.h | 2 ++ libc/src/string/CMakeLists.txt | 11 ++++++++++- libc/src/string/strerror.cpp | 1 - libc/src/string/strerror_r.cpp | 23 +++++++++++++++++++++++ libc/src/string/strerror_r.h | 20 ++++++++++++++++++++ libc/test/src/string/CMakeLists.txt | 11 +++++++++++ libc/test/src/string/strerror_r_test.cpp | 28 ++++++++++++++++++++++++++++ 10 files changed, 111 insertions(+), 7 deletions(-) create mode 100644 libc/src/string/strerror_r.cpp create mode 100644 libc/src/string/strerror_r.h create mode 100644 libc/test/src/string/strerror_r_test.cpp diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt index e30990946d43..5ed5f0cd9747 100644 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -44,6 +44,8 @@ set(TARGET_LIBC_ENTRYPOINTS libc.src.string.strcmp libc.src.string.strcpy libc.src.string.strcspn + libc.src.string.strerror + libc.src.string.strerror_r libc.src.string.strlcat libc.src.string.strlcpy libc.src.string.strlen @@ -61,7 +63,6 @@ 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/spec/gnu_ext.td b/libc/spec/gnu_ext.td index 5a7fb1fa1b3d..5c4c9e341233 100644 --- a/libc/spec/gnu_ext.td +++ b/libc/spec/gnu_ext.td @@ -63,6 +63,11 @@ def GnuExtensions : StandardSpec<"GNUExtensions"> { RetValSpec, [ArgSpec, ArgSpec, ArgSpec] >, + FunctionSpec< + "strerror_r", + RetValSpec, + [ArgSpec, ArgSpec, ArgSpec] + >, ] >; diff --git a/libc/src/__support/error_to_string.cpp b/libc/src/__support/error_to_string.cpp index dca6b8a968ba..f84819ccc7c2 100644 --- a/libc/src/__support/error_to_string.cpp +++ b/libc/src/__support/error_to_string.cpp @@ -223,18 +223,19 @@ public: } } - cpp::string_view get_str(int err_num) const { + cpp::string_view get_str(int err_num, cpp::string_view buffer) const { if (err_num >= 0 && static_cast(err_num) < ERR_ARRAY_SIZE && err_offsets[err_num] != -1) { return const_cast(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 < + if (buffer.size() < (sizeof("Unknown error") + 1 + IntegerToString::dec_bufsize())) return const_cast("Unknown error"); - cpp::StringStream buffer_stream({error_buffer, BUFFER_SIZE}); + cpp::StringStream buffer_stream( + {const_cast(buffer.data()), buffer.size()}); buffer_stream << "Unknown error" << ' ' << err_num << '\0'; return buffer_stream.str(); } @@ -246,6 +247,11 @@ static constexpr ErrorMapper error_mapper; } // namespace internal cpp::string_view get_error_string(int err_num) { - return internal::error_mapper.get_str(err_num); + return internal::error_mapper.get_str( + err_num, {internal::error_buffer, internal::BUFFER_SIZE}); +} + +cpp::string_view get_error_string(int err_num, cpp::string_view buffer) { + return internal::error_mapper.get_str(err_num, buffer); } } // namespace __llvm_libc diff --git a/libc/src/__support/error_to_string.h b/libc/src/__support/error_to_string.h index 72b2e9c93e65..afc5e39dab8a 100644 --- a/libc/src/__support/error_to_string.h +++ b/libc/src/__support/error_to_string.h @@ -16,6 +16,8 @@ namespace __llvm_libc { cpp::string_view get_error_string(int err_num); +cpp::string_view get_error_string(int err_num, cpp::string_view buffer); + } // namespace __llvm_libc #endif // LLVM_LIBC_SRC_SUPPORT_ERROR_TO_STRING diff --git a/libc/src/string/CMakeLists.txt b/libc/src/string/CMakeLists.txt index 1b11d888bdc4..1af5472c218d 100644 --- a/libc/src/string/CMakeLists.txt +++ b/libc/src/string/CMakeLists.txt @@ -136,7 +136,16 @@ add_entrypoint_object( strerror.h DEPENDS libc.src.__support.error_to_string - libc.src.__support.CPP.span +) + +add_entrypoint_object( + strerror_r + SRCS + strerror_r.cpp + HDRS + strerror_r.h + DEPENDS + libc.src.__support.error_to_string ) add_entrypoint_object( diff --git a/libc/src/string/strerror.cpp b/libc/src/string/strerror.cpp index 0297b86d20d4..e99793fb3591 100644 --- a/libc/src/string/strerror.cpp +++ b/libc/src/string/strerror.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// #include "src/string/strerror.h" -#include "src/__support/CPP/span.h" #include "src/__support/common.h" #include "src/__support/error_to_string.h" diff --git a/libc/src/string/strerror_r.cpp b/libc/src/string/strerror_r.cpp new file mode 100644 index 000000000000..30147152c448 --- /dev/null +++ b/libc/src/string/strerror_r.cpp @@ -0,0 +1,23 @@ +//===-- Implementation of strerror_r --------------------------------------===// +// +// 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_r.h" +#include "src/__support/common.h" +#include "src/__support/error_to_string.h" + +#include + +namespace __llvm_libc { + +// This is the gnu version of strerror_r. The XSI version may be added later. +LLVM_LIBC_FUNCTION(char *, strerror_r, + (int err_num, char *buf, size_t buflen)) { + return const_cast(get_error_string(err_num, {buf, buflen}).data()); +} + +} // namespace __llvm_libc diff --git a/libc/src/string/strerror_r.h b/libc/src/string/strerror_r.h new file mode 100644 index 000000000000..18b361773be4 --- /dev/null +++ b/libc/src/string/strerror_r.h @@ -0,0 +1,20 @@ +//===-- Implementation header for strerror_r --------------------*- 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_R_H +#define LLVM_LIBC_SRC_STRING_STRERROR_R_H + +#include + +namespace __llvm_libc { + +char *strerror_r(int err_num, char *buf, size_t buflen); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_STRING_STRERROR_R_H diff --git a/libc/test/src/string/CMakeLists.txt b/libc/test/src/string/CMakeLists.txt index fe12c0d436b8..723fbd502ba4 100644 --- a/libc/test/src/string/CMakeLists.txt +++ b/libc/test/src/string/CMakeLists.txt @@ -133,6 +133,17 @@ add_libc_unittest( libc.src.string.strerror ) + +add_libc_unittest( + strerror_r_test + SUITE + libc_string_unittests + SRCS + strerror_r_test.cpp + DEPENDS + libc.src.string.strerror_r +) + add_libc_unittest( strlcat_test SUITE diff --git a/libc/test/src/string/strerror_r_test.cpp b/libc/test/src/string/strerror_r_test.cpp new file mode 100644 index 000000000000..ed1fb58824fe --- /dev/null +++ b/libc/test/src/string/strerror_r_test.cpp @@ -0,0 +1,28 @@ +//===-- 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_r.h" +#include "utils/UnitTest/Test.h" + +#include + +// This tests the gnu variant of strerror_r (which returns a char*). +TEST(LlvmLibcStrErrorRTest, GnuVariantTests) { + const size_t BUFF_SIZE = 128; + char buffer[BUFF_SIZE]; + buffer[0] = '\0'; + // If strerror_r returns a constant string, then it shouldn't affect the + // buffer. + ASSERT_STREQ(__llvm_libc::strerror_r(0, buffer, BUFF_SIZE), "Success"); + ASSERT_EQ(buffer[0], '\0'); + + // Else it should write the result to the provided buffer. + ASSERT_STREQ(__llvm_libc::strerror_r(-1, buffer, BUFF_SIZE), + "Unknown error -1"); + ASSERT_STREQ(buffer, "Unknown error -1"); +} -- cgit v1.2.3