[llvm] [orc-rt] Add sys::strError, replacing strerror. (PR #219666)
Lang Hames via llvm-commits
llvm-commits at lists.llvm.org
Sat Aug 29 03:46:54 PDT 2026
https://github.com/lhames created https://github.com/llvm/llvm-project/pull/219666
strerror may return a pointer to a static buffer, so it isn't safe to call from more than one thread, and the memory operations using it are exactly those that run concurrently.
>From 372793fcb0bab89b75e0dccd4bbb16666197d231 Mon Sep 17 00:00:00 2001
From: Lang Hames <lhames at gmail.com>
Date: Sat, 29 Aug 2026 20:44:41 +1000
Subject: [PATCH] [orc-rt] Add sys::strError, replacing strerror.
strerror may return a pointer to a static buffer, so it isn't safe to
call from more than one thread, and the memory operations using it are
exactly those that run concurrently.
---
.../orc-rt-internal/support/sys/Errno.h | 29 ++++++++++
orc-rt/lib/bedrock/CMakeLists.txt | 1 +
orc-rt/lib/bedrock/ExecutorProcessInfo.cpp | 3 +-
orc-rt/lib/bedrock/posix/Errno.cpp | 55 +++++++++++++++++++
orc-rt/lib/bedrock/posix/Memory.cpp | 8 +--
orc-rt/test/unit/CMakeLists.txt | 2 +
orc-rt/test/unit/support/sys/ErrnoTest.cpp | 44 +++++++++++++++
7 files changed, 137 insertions(+), 5 deletions(-)
create mode 100644 orc-rt/include/orc-rt-internal/support/sys/Errno.h
create mode 100644 orc-rt/lib/bedrock/posix/Errno.cpp
create mode 100644 orc-rt/test/unit/support/sys/ErrnoTest.cpp
diff --git a/orc-rt/include/orc-rt-internal/support/sys/Errno.h b/orc-rt/include/orc-rt-internal/support/sys/Errno.h
new file mode 100644
index 0000000000000..3f3f6b010771f
--- /dev/null
+++ b/orc-rt/include/orc-rt-internal/support/sys/Errno.h
@@ -0,0 +1,29 @@
+//===- Errno.h - errno support ---------------------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Helpers for working with errno values.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ORC_RT_INTERNAL_SUPPORT_SYS_ERRNO_H
+#define ORC_RT_INTERNAL_SUPPORT_SYS_ERRNO_H
+
+#include <string>
+
+namespace orc_rt::sys {
+
+/// Returns a human-readable description of the given errno value.
+///
+/// Prefer this to strerror, which is not guaranteed to be thread-safe. If no
+/// description is available the value itself is reported, so the result is
+/// always non-empty.
+std::string strError(int ErrNum);
+
+} // namespace orc_rt::sys
+
+#endif // ORC_RT_INTERNAL_SUPPORT_SYS_ERRNO_H
diff --git a/orc-rt/lib/bedrock/CMakeLists.txt b/orc-rt/lib/bedrock/CMakeLists.txt
index e27ef29276f63..ee82301e4bd0d 100644
--- a/orc-rt/lib/bedrock/CMakeLists.txt
+++ b/orc-rt/lib/bedrock/CMakeLists.txt
@@ -46,6 +46,7 @@ endif()
set(ORC_RT_POSIX_SOURCES
posix/DynamicLibrary.cpp
+ posix/Errno.cpp
posix/Memory.cpp
)
diff --git a/orc-rt/lib/bedrock/ExecutorProcessInfo.cpp b/orc-rt/lib/bedrock/ExecutorProcessInfo.cpp
index bff9d93953968..dd59e2fd8795e 100644
--- a/orc-rt/lib/bedrock/ExecutorProcessInfo.cpp
+++ b/orc-rt/lib/bedrock/ExecutorProcessInfo.cpp
@@ -13,6 +13,7 @@
#include "orc-rt/bedrock/ExecutorProcessInfo.h"
#include "orc-rt-internal/support/StringExtras.h"
+#include "orc-rt-internal/support/sys/Errno.h"
#include "orc-rt/support/bit.h"
#include <cassert>
@@ -74,7 +75,7 @@ std::string ExecutorProcessInfo::makeTargetTriple(
Expected<size_t> ExecutorProcessInfo::detectPageSize() noexcept {
long PageSize = sysconf(_SC_PAGESIZE);
if (PageSize == -1)
- return make_error<StringError>(strerror(errno));
+ return make_error<StringError>(sys::strError(errno));
if (PageSize <= 0 || !has_single_bit(static_cast<size_t>(PageSize)))
return make_error<StringError>((StringOutputStream()
<< "reported page size " << PageSize
diff --git a/orc-rt/lib/bedrock/posix/Errno.cpp b/orc-rt/lib/bedrock/posix/Errno.cpp
new file mode 100644
index 0000000000000..d47711631bded
--- /dev/null
+++ b/orc-rt/lib/bedrock/posix/Errno.cpp
@@ -0,0 +1,55 @@
+//===- Errno.cpp - POSIX errno support -------------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Implementation of orc-rt-internal/support/sys/Errno.h on POSIX systems, in
+// terms of strerror_r.
+//
+//===----------------------------------------------------------------------===//
+
+#include "orc-rt-internal/support/sys/Errno.h"
+
+#include <string.h>
+#include <type_traits>
+
+namespace orc_rt::sys {
+
+namespace {
+
+/// Interpret strerror_r's result.
+///
+/// strerror_r comes in two incompatible forms:
+///
+/// POSIX: int strerror_r(int errnum, char *buf, size_t buflen);
+/// GNU: char *strerror_r(int errnum, char *buf, size_t buflen);
+///
+/// POSIX returns zero on success, whereas GNU returns a char* that may point
+/// somewhere other than buf. Use return type to distinguish them below.
+template <typename RetT>
+std::string fromStrerrorR(RetT Ret, int ErrNum, const char *Buf) {
+ if constexpr (std::is_pointer_v<RetT>)
+ return Ret;
+ else {
+ // Some systems (Darwin among them) fill Buf even while reporting EINVAL for
+ // an unrecognised value, so prefer whatever was written and synthesise a
+ // description only if nothing was.
+ if (Ret == 0 || Buf[0] != '\0')
+ return Buf;
+ return "unknown error " + std::to_string(ErrNum);
+ }
+}
+
+} // namespace
+
+std::string strError(int ErrNum) {
+ char Buf[256] = {};
+ // Leave the final byte NUL: on ERANGE the buffer contents are unspecified
+ // and are not required to be terminated.
+ return fromStrerrorR(strerror_r(ErrNum, Buf, sizeof(Buf) - 1), ErrNum, Buf);
+}
+
+} // namespace orc_rt::sys
diff --git a/orc-rt/lib/bedrock/posix/Memory.cpp b/orc-rt/lib/bedrock/posix/Memory.cpp
index b96b0805eddb4..f881e5f39bc11 100644
--- a/orc-rt/lib/bedrock/posix/Memory.cpp
+++ b/orc-rt/lib/bedrock/posix/Memory.cpp
@@ -14,9 +14,9 @@
#include "orc-rt-internal/support/sys/Memory.h"
#include "orc-rt-internal/support/sys/CacheControl.h"
+#include "orc-rt-internal/support/sys/Errno.h"
#include <errno.h>
-#include <string.h>
#include <sys/mman.h>
namespace orc_rt::sys {
@@ -53,7 +53,7 @@ Expected<void *> reserveMemory(size_t Size) {
if (Addr == MAP_FAILED) {
auto ErrNum = errno;
return make_error<StringError>(
- std::string("mmap for memory reserve failed: ") + strerror(ErrNum));
+ std::string("mmap for memory reserve failed: ") + strError(ErrNum));
}
return Addr;
@@ -63,7 +63,7 @@ Error releaseMemory(void *Base, size_t Size) {
if (munmap(Base, Size) != 0) {
auto ErrNum = errno;
return make_error<StringError>(
- std::string("munmap for memory release failed: ") + strerror(ErrNum));
+ std::string("munmap for memory release failed: ") + strError(ErrNum));
}
return Error::success();
}
@@ -73,7 +73,7 @@ Error protectMemory(void *Base, size_t Size, MemProt MP) {
auto ErrNum = errno;
return make_error<StringError>(
std::string("mprotect for memory finalize failed: ") +
- strerror(ErrNum));
+ strError(ErrNum));
}
if ((MP & MemProt::Exec) != MemProt::None)
diff --git a/orc-rt/test/unit/CMakeLists.txt b/orc-rt/test/unit/CMakeLists.txt
index 5c2787fc3dfec..5d7c98c14197d 100644
--- a/orc-rt/test/unit/CMakeLists.txt
+++ b/orc-rt/test/unit/CMakeLists.txt
@@ -46,6 +46,8 @@ add_orc_rt_unittest(CoreTests
support/sps/SPSWrapperFunctionTest.cpp
support/sps/SimplePackedSerializationTest.cpp
+ support/sys/ErrnoTest.cpp
+
bedrock/BootstrapInfoTest.cpp
bedrock/ExecutorProcessInfoTest.cpp
bedrock/InProcessControllerAccessTest.cpp
diff --git a/orc-rt/test/unit/support/sys/ErrnoTest.cpp b/orc-rt/test/unit/support/sys/ErrnoTest.cpp
new file mode 100644
index 0000000000000..729538ea4f111
--- /dev/null
+++ b/orc-rt/test/unit/support/sys/ErrnoTest.cpp
@@ -0,0 +1,44 @@
+//===- ErrnoTest.cpp ------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Tests for orc-rt's sys/Errno.h APIs.
+//
+// The exact wording of a description is the system's business, so these only
+// check the properties strError promises.
+//
+//===----------------------------------------------------------------------===//
+
+#include "orc-rt-internal/support/sys/Errno.h"
+#include "gtest/gtest.h"
+
+#include <errno.h>
+
+using namespace orc_rt;
+
+TEST(ErrnoTest, KnownValuesDescribed) {
+ EXPECT_FALSE(sys::strError(EINVAL).empty());
+ EXPECT_FALSE(sys::strError(ENOENT).empty());
+
+ // Distinct values should not share a description, or callers can't tell what
+ // went wrong.
+ EXPECT_NE(sys::strError(EINVAL), sys::strError(ENOENT));
+}
+
+TEST(ErrnoTest, UnknownValueStillDescribed) {
+ // strError promises a non-empty result even where the system has no
+ // description, so that an error message never comes out blank.
+ EXPECT_FALSE(sys::strError(999999).empty());
+}
+
+TEST(ErrnoTest, ResultIsNulFree) {
+ // The result is built from a fixed-size buffer; it must be trimmed to the
+ // description rather than padded out to the buffer length.
+ auto S = sys::strError(EINVAL);
+ EXPECT_EQ(S.find('\0'), std::string::npos);
+ EXPECT_EQ(S.size(), strlen(S.c_str()));
+}
More information about the llvm-commits
mailing list