[libc-commits] [libc] [llvm] [libc] Don't touch str_end in strto* and wcsto* functions when base is incorrect (PR #200073)
Alexey Samsonov via libc-commits
libc-commits at lists.llvm.org
Wed May 27 23:03:53 PDT 2026
https://github.com/vonosmas updated https://github.com/llvm/llvm-project/pull/200073
>From 1ea407ed95e338da52546b7d59139d92e41217cc Mon Sep 17 00:00:00 2001
From: Alexey Samsonov <vonosmas at gmail.com>
Date: Wed, 27 May 2026 21:54:29 +0000
Subject: [PATCH 1/6] Fix EINVAL handling in strto*/wcsto* functions.
---
libc/src/inttypes/CMakeLists.txt | 6 ++--
libc/src/inttypes/strtoimax.cpp | 13 ++-----
libc/src/inttypes/strtoumax.cpp | 13 ++-----
libc/src/stdlib/CMakeLists.txt | 43 ++++++++++++------------
libc/src/stdlib/atoi.cpp | 11 ++----
libc/src/stdlib/atol.cpp | 10 ++----
libc/src/stdlib/atoll.cpp | 10 ++----
libc/src/stdlib/str_to_util.h | 41 ++++++++++++++++++++++
libc/src/stdlib/strtol.cpp | 13 ++-----
libc/src/stdlib/strtol_l.cpp | 13 ++-----
libc/src/stdlib/strtoll.cpp | 13 ++-----
libc/src/stdlib/strtoll_l.cpp | 13 ++-----
libc/src/stdlib/strtoul.cpp | 13 ++-----
libc/src/stdlib/strtoul_l.cpp | 13 ++-----
libc/src/stdlib/strtoull.cpp | 13 ++-----
libc/src/stdlib/strtoull_l.cpp | 13 ++-----
libc/src/wchar/CMakeLists.txt | 12 +++----
libc/src/wchar/wcstol.cpp | 13 ++-----
libc/src/wchar/wcstoll.cpp | 13 ++-----
libc/src/wchar/wcstoul.cpp | 13 ++-----
libc/src/wchar/wcstoull.cpp | 13 ++-----
libc/test/src/stdlib/CMakeLists.txt | 6 ++--
libc/test/src/stdlib/StrtolTest.h | 5 ++-
libc/test/src/stdlib/strtoint32_test.cpp | 21 ++----------
libc/test/src/stdlib/strtoint64_test.cpp | 21 ++----------
libc/test/src/wchar/WcstolTest.h | 5 ++-
26 files changed, 119 insertions(+), 254 deletions(-)
create mode 100644 libc/src/stdlib/str_to_util.h
diff --git a/libc/src/inttypes/CMakeLists.txt b/libc/src/inttypes/CMakeLists.txt
index 3a48c9a1a8b97..eb9f2f3375eab 100644
--- a/libc/src/inttypes/CMakeLists.txt
+++ b/libc/src/inttypes/CMakeLists.txt
@@ -6,8 +6,7 @@ add_entrypoint_object(
strtoimax.h
DEPENDS
libc.hdr.stdint_proxy
- libc.src.__support.str_to_integer
- libc.src.errno.errno
+ libc.src.stdlib.str_to_util
)
add_entrypoint_object(
@@ -18,8 +17,7 @@ add_entrypoint_object(
strtoumax.h
DEPENDS
libc.hdr.stdint_proxy
- libc.src.__support.str_to_integer
- libc.src.errno.errno
+ libc.src.stdlib.str_to_util
)
add_entrypoint_object(
diff --git a/libc/src/inttypes/strtoimax.cpp b/libc/src/inttypes/strtoimax.cpp
index 6e55a4b56aac7..213d8800aab80 100644
--- a/libc/src/inttypes/strtoimax.cpp
+++ b/libc/src/inttypes/strtoimax.cpp
@@ -7,24 +7,15 @@
//===----------------------------------------------------------------------===//
#include "src/inttypes/strtoimax.h"
-#include "src/__support/common.h"
-#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
-#include "src/__support/str_to_integer.h"
+#include "src/stdlib/str_to_util.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(intmax_t, strtoimax,
(const char *__restrict str, char **__restrict str_end,
int base)) {
- auto result = internal::strtointeger<intmax_t>(str, base);
- if (result.has_error())
- libc_errno = result.error;
-
- if (str_end != nullptr)
- *str_end = const_cast<char *>(str + result.parsed_len);
-
- return result;
+ return internal::str_to_helper<intmax_t>(str, str_end, base);
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/inttypes/strtoumax.cpp b/libc/src/inttypes/strtoumax.cpp
index ce5a0a782d979..6191ad0491bf2 100644
--- a/libc/src/inttypes/strtoumax.cpp
+++ b/libc/src/inttypes/strtoumax.cpp
@@ -7,24 +7,15 @@
//===----------------------------------------------------------------------===//
#include "src/inttypes/strtoumax.h"
-#include "src/__support/common.h"
-#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
-#include "src/__support/str_to_integer.h"
+#include "src/stdlib/str_to_util.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(uintmax_t, strtoumax,
(const char *__restrict str, char **__restrict str_end,
int base)) {
- auto result = internal::strtointeger<uintmax_t>(str, base);
- if (result.has_error())
- libc_errno = result.error;
-
- if (str_end != nullptr)
- *str_end = const_cast<char *>(str + result.parsed_len);
-
- return result;
+ return internal::str_to_helper<uintmax_t>(str, str_end, base);
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/CMakeLists.txt b/libc/src/stdlib/CMakeLists.txt
index 7e542e56a983d..2299bc1f0b0c5 100644
--- a/libc/src/stdlib/CMakeLists.txt
+++ b/libc/src/stdlib/CMakeLists.txt
@@ -5,8 +5,7 @@ add_entrypoint_object(
HDRS
atoi.h
DEPENDS
- libc.src.errno.errno
- libc.src.__support.str_to_integer
+ .str_to_util
)
add_entrypoint_object(
@@ -27,8 +26,7 @@ add_entrypoint_object(
HDRS
atol.h
DEPENDS
- libc.src.errno.errno
- libc.src.__support.str_to_integer
+ .str_to_util
)
add_entrypoint_object(
@@ -38,8 +36,7 @@ add_entrypoint_object(
HDRS
atoll.h
DEPENDS
- libc.src.errno.errno
- libc.src.__support.str_to_integer
+ .str_to_util
)
add_entrypoint_object(
@@ -144,6 +141,16 @@ add_header_library(
libc.src.__support.CPP.type_traits
)
+add_header_library(
+ str_to_util
+ HDRS
+ str_to_util.h
+ DEPENDS
+ libc.src.__support.common
+ libc.src.__support.libc_errno
+ libc.src.__support.str_to_integer
+)
+
add_entrypoint_object(
strtof
SRCS
@@ -184,8 +191,7 @@ add_entrypoint_object(
HDRS
strtol.h
DEPENDS
- libc.src.errno.errno
- libc.src.__support.str_to_integer
+ .str_to_util
)
add_entrypoint_object(
@@ -195,8 +201,7 @@ add_entrypoint_object(
HDRS
strtoll.h
DEPENDS
- libc.src.errno.errno
- libc.src.__support.str_to_integer
+ .str_to_util
)
add_entrypoint_object(
@@ -206,8 +211,7 @@ add_entrypoint_object(
HDRS
strtoul.h
DEPENDS
- libc.src.errno.errno
- libc.src.__support.str_to_integer
+ .str_to_util
)
add_entrypoint_object(
@@ -217,8 +221,7 @@ add_entrypoint_object(
HDRS
strtoull.h
DEPENDS
- libc.src.errno.errno
- libc.src.__support.str_to_integer
+ .str_to_util
)
add_entrypoint_object(
@@ -612,8 +615,7 @@ add_entrypoint_object(
HDRS
strtol_l.h
DEPENDS
- libc.src.errno.errno
- libc.src.__support.str_to_integer
+ .str_to_util
)
add_entrypoint_object(
@@ -623,8 +625,7 @@ add_entrypoint_object(
HDRS
strtoll_l.h
DEPENDS
- libc.src.errno.errno
- libc.src.__support.str_to_integer
+ .str_to_util
)
add_entrypoint_object(
@@ -634,8 +635,7 @@ add_entrypoint_object(
HDRS
strtoul_l.h
DEPENDS
- libc.src.errno.errno
- libc.src.__support.str_to_integer
+ .str_to_util
)
add_entrypoint_object(
@@ -645,8 +645,7 @@ add_entrypoint_object(
HDRS
strtoull_l.h
DEPENDS
- libc.src.errno.errno
- libc.src.__support.str_to_integer
+ .str_to_util
)
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
diff --git a/libc/src/stdlib/atoi.cpp b/libc/src/stdlib/atoi.cpp
index 420bbc8143d55..9b030685a603b 100644
--- a/libc/src/stdlib/atoi.cpp
+++ b/libc/src/stdlib/atoi.cpp
@@ -7,21 +7,16 @@
//===----------------------------------------------------------------------===//
#include "src/stdlib/atoi.h"
-#include "src/__support/common.h"
-#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
-#include "src/__support/str_to_integer.h"
+#include "src/stdlib/str_to_util.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, atoi, (const char *str)) {
// This is done because the standard specifies that atoi is identical to
// (int)(strtol).
- auto result = internal::strtointeger<long>(str, 10);
- if (result.has_error())
- libc_errno = result.error;
-
- return static_cast<int>(result);
+ return static_cast<int>(
+ internal::str_to_helper<long, char>(str, nullptr, 10));
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/atol.cpp b/libc/src/stdlib/atol.cpp
index e1110ffa449b0..6b7d15fc6c955 100644
--- a/libc/src/stdlib/atol.cpp
+++ b/libc/src/stdlib/atol.cpp
@@ -7,19 +7,13 @@
//===----------------------------------------------------------------------===//
#include "src/stdlib/atol.h"
-#include "src/__support/common.h"
-#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
-#include "src/__support/str_to_integer.h"
+#include "src/stdlib/str_to_util.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(long, atol, (const char *str)) {
- auto result = internal::strtointeger<long>(str, 10);
- if (result.has_error())
- libc_errno = result.error;
-
- return result;
+ return internal::str_to_helper<long, char>(str, nullptr, 10);
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/atoll.cpp b/libc/src/stdlib/atoll.cpp
index 063e817f9b790..2945e2dd716d5 100644
--- a/libc/src/stdlib/atoll.cpp
+++ b/libc/src/stdlib/atoll.cpp
@@ -7,19 +7,13 @@
//===----------------------------------------------------------------------===//
#include "src/stdlib/atoll.h"
-#include "src/__support/common.h"
-#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
-#include "src/__support/str_to_integer.h"
+#include "src/stdlib/str_to_util.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(long long, atoll, (const char *str)) {
- auto result = internal::strtointeger<long long>(str, 10);
- if (result.has_error())
- libc_errno = result.error;
-
- return result;
+ return internal::str_to_helper<long long, char>(str, nullptr, 10);
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/str_to_util.h b/libc/src/stdlib/str_to_util.h
new file mode 100644
index 0000000000000..f6c3efd25ab3c
--- /dev/null
+++ b/libc/src/stdlib/str_to_util.h
@@ -0,0 +1,41 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Shared implementation of strto* and wcsto* endpoints.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
+#include "src/__support/str_to_integer.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace internal {
+
+// Shared implementation of strto* and wcsto* endpoints. Invokes
+// strtointeger shared API and sets errno and str_end pointer according to the
+// standard.
+template <typename T, typename CharType>
+LIBC_INLINE constexpr T str_to_helper(const CharType *__restrict str,
+ CharType **__restrict str_end, int base) {
+ auto result = strtointeger<T>(str, base);
+ if (result.has_error())
+ libc_errno = result.error;
+
+ // It is unspecified whether str_end should be set to "str" if the base
+ // is invalid, we explicitly avoid setting it for consistency with
+ // other implementations.
+ if (str_end != nullptr && result.error != EINVAL)
+ *str_end = const_cast<CharType *>(str + result.parsed_len);
+
+ return result.value;
+}
+
+} // namespace internal
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/strtol.cpp b/libc/src/stdlib/strtol.cpp
index 42db36b2052b4..e524fbd8c5213 100644
--- a/libc/src/stdlib/strtol.cpp
+++ b/libc/src/stdlib/strtol.cpp
@@ -7,24 +7,15 @@
//===----------------------------------------------------------------------===//
#include "src/stdlib/strtol.h"
-#include "src/__support/common.h"
-#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
-#include "src/__support/str_to_integer.h"
+#include "src/stdlib/str_to_util.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(long, strtol,
(const char *__restrict str, char **__restrict str_end,
int base)) {
- auto result = internal::strtointeger<long>(str, base);
- if (result.has_error())
- libc_errno = result.error;
-
- if (str_end != nullptr)
- *str_end = const_cast<char *>(str + result.parsed_len);
-
- return result;
+ return internal::str_to_helper<long>(str, str_end, base);
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/strtol_l.cpp b/libc/src/stdlib/strtol_l.cpp
index 497a4403eff4b..2fff7d220b830 100644
--- a/libc/src/stdlib/strtol_l.cpp
+++ b/libc/src/stdlib/strtol_l.cpp
@@ -7,24 +7,15 @@
//===----------------------------------------------------------------------===//
#include "src/stdlib/strtol_l.h"
-#include "src/__support/common.h"
-#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
-#include "src/__support/str_to_integer.h"
+#include "src/stdlib/str_to_util.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(long, strtol_l,
(const char *__restrict str, char **__restrict str_end,
int base, locale_t)) {
- auto result = internal::strtointeger<long>(str, base);
- if (result.has_error())
- libc_errno = result.error;
-
- if (str_end != nullptr)
- *str_end = const_cast<char *>(str + result.parsed_len);
-
- return result;
+ return internal::str_to_helper<long>(str, str_end, base);
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/strtoll.cpp b/libc/src/stdlib/strtoll.cpp
index c1dca13112e0f..a446755ecc4b1 100644
--- a/libc/src/stdlib/strtoll.cpp
+++ b/libc/src/stdlib/strtoll.cpp
@@ -7,24 +7,15 @@
//===----------------------------------------------------------------------===//
#include "src/stdlib/strtoll.h"
-#include "src/__support/common.h"
-#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
-#include "src/__support/str_to_integer.h"
+#include "src/stdlib/str_to_util.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(long long, strtoll,
(const char *__restrict str, char **__restrict str_end,
int base)) {
- auto result = internal::strtointeger<long long>(str, base);
- if (result.has_error())
- libc_errno = result.error;
-
- if (str_end != nullptr)
- *str_end = const_cast<char *>(str + result.parsed_len);
-
- return result;
+ return internal::str_to_helper<long long>(str, str_end, base);
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/strtoll_l.cpp b/libc/src/stdlib/strtoll_l.cpp
index 6f30d7794c5ca..1de15a6dc17a9 100644
--- a/libc/src/stdlib/strtoll_l.cpp
+++ b/libc/src/stdlib/strtoll_l.cpp
@@ -7,24 +7,15 @@
//===----------------------------------------------------------------------===//
#include "src/stdlib/strtoll_l.h"
-#include "src/__support/common.h"
-#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
-#include "src/__support/str_to_integer.h"
+#include "src/stdlib/str_to_util.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(long long, strtoll_l,
(const char *__restrict str, char **__restrict str_end,
int base, locale_t)) {
- auto result = internal::strtointeger<long long>(str, base);
- if (result.has_error())
- libc_errno = result.error;
-
- if (str_end != nullptr)
- *str_end = const_cast<char *>(str + result.parsed_len);
-
- return result;
+ return internal::str_to_helper<long long>(str, str_end, base);
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/strtoul.cpp b/libc/src/stdlib/strtoul.cpp
index d26ca5e5a10a1..d213c5e6edc52 100644
--- a/libc/src/stdlib/strtoul.cpp
+++ b/libc/src/stdlib/strtoul.cpp
@@ -7,24 +7,15 @@
//===----------------------------------------------------------------------===//
#include "src/stdlib/strtoul.h"
-#include "src/__support/common.h"
-#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
-#include "src/__support/str_to_integer.h"
+#include "src/stdlib/str_to_util.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(unsigned long, strtoul,
(const char *__restrict str, char **__restrict str_end,
int base)) {
- auto result = internal::strtointeger<unsigned long>(str, base);
- if (result.has_error())
- libc_errno = result.error;
-
- if (str_end != nullptr)
- *str_end = const_cast<char *>(str + result.parsed_len);
-
- return result;
+ return internal::str_to_helper<unsigned long>(str, str_end, base);
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/strtoul_l.cpp b/libc/src/stdlib/strtoul_l.cpp
index 9a875ddee9029..38e8ff93a9174 100644
--- a/libc/src/stdlib/strtoul_l.cpp
+++ b/libc/src/stdlib/strtoul_l.cpp
@@ -7,24 +7,15 @@
//===----------------------------------------------------------------------===//
#include "src/stdlib/strtoul_l.h"
-#include "src/__support/common.h"
-#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
-#include "src/__support/str_to_integer.h"
+#include "src/stdlib/str_to_util.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(unsigned long, strtoul_l,
(const char *__restrict str, char **__restrict str_end,
int base, locale_t)) {
- auto result = internal::strtointeger<unsigned long>(str, base);
- if (result.has_error())
- libc_errno = result.error;
-
- if (str_end != nullptr)
- *str_end = const_cast<char *>(str + result.parsed_len);
-
- return result;
+ return internal::str_to_helper<unsigned long>(str, str_end, base);
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/strtoull.cpp b/libc/src/stdlib/strtoull.cpp
index 8f929f577311e..87ca67f5396f3 100644
--- a/libc/src/stdlib/strtoull.cpp
+++ b/libc/src/stdlib/strtoull.cpp
@@ -7,24 +7,15 @@
//===----------------------------------------------------------------------===//
#include "src/stdlib/strtoull.h"
-#include "src/__support/common.h"
-#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
-#include "src/__support/str_to_integer.h"
+#include "src/stdlib/str_to_util.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(unsigned long long, strtoull,
(const char *__restrict str, char **__restrict str_end,
int base)) {
- auto result = internal::strtointeger<unsigned long long>(str, base);
- if (result.has_error())
- libc_errno = result.error;
-
- if (str_end != nullptr)
- *str_end = const_cast<char *>(str + result.parsed_len);
-
- return result;
+ return internal::str_to_helper<unsigned long long>(str, str_end, base);
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/strtoull_l.cpp b/libc/src/stdlib/strtoull_l.cpp
index 9eb056b0e59b4..4651b66d90b2b 100644
--- a/libc/src/stdlib/strtoull_l.cpp
+++ b/libc/src/stdlib/strtoull_l.cpp
@@ -7,24 +7,15 @@
//===----------------------------------------------------------------------===//
#include "src/stdlib/strtoull_l.h"
-#include "src/__support/common.h"
-#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
-#include "src/__support/str_to_integer.h"
+#include "src/stdlib/str_to_util.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(unsigned long long, strtoull_l,
(const char *__restrict str, char **__restrict str_end,
int base, locale_t)) {
- auto result = internal::strtointeger<unsigned long long>(str, base);
- if (result.has_error())
- libc_errno = result.error;
-
- if (str_end != nullptr)
- *str_end = const_cast<char *>(str + result.parsed_len);
-
- return result;
+ return internal::str_to_helper<unsigned long long>(str, str_end, base);
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/wchar/CMakeLists.txt b/libc/src/wchar/CMakeLists.txt
index eb340a80e5741..18c70703f1ef1 100644
--- a/libc/src/wchar/CMakeLists.txt
+++ b/libc/src/wchar/CMakeLists.txt
@@ -60,8 +60,7 @@ add_entrypoint_object(
HDRS
wcstol.h
DEPENDS
- libc.src.errno.errno
- libc.src.__support.str_to_integer
+ libc.src.stdlib.str_to_util
)
add_entrypoint_object(
@@ -71,8 +70,7 @@ add_entrypoint_object(
HDRS
wcstoll.h
DEPENDS
- libc.src.errno.errno
- libc.src.__support.str_to_integer
+ libc.src.stdlib.str_to_util
)
add_entrypoint_object(
@@ -82,8 +80,7 @@ add_entrypoint_object(
HDRS
wcstoul.h
DEPENDS
- libc.src.errno.errno
- libc.src.__support.str_to_integer
+ libc.src.stdlib.str_to_util
)
add_entrypoint_object(
@@ -93,8 +90,7 @@ add_entrypoint_object(
HDRS
wcstoull.h
DEPENDS
- libc.src.errno.errno
- libc.src.__support.str_to_integer
+ libc.src.stdlib.str_to_util
)
add_entrypoint_object(
diff --git a/libc/src/wchar/wcstol.cpp b/libc/src/wchar/wcstol.cpp
index a56b5f91272cd..d3131445a4816 100644
--- a/libc/src/wchar/wcstol.cpp
+++ b/libc/src/wchar/wcstol.cpp
@@ -7,24 +7,15 @@
//===----------------------------------------------------------------------===//
#include "src/wchar/wcstol.h"
-#include "src/__support/common.h"
-#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
-#include "src/__support/str_to_integer.h"
+#include "src/stdlib/str_to_util.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(long, wcstol,
(const wchar_t *__restrict str, wchar_t **__restrict str_end,
int base)) {
- auto result = internal::strtointeger<long>(str, base);
- if (result.has_error())
- libc_errno = result.error;
-
- if (str_end != nullptr)
- *str_end = const_cast<wchar_t *>(str + result.parsed_len);
-
- return result;
+ return internal::str_to_helper<long>(str, str_end, base);
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/wchar/wcstoll.cpp b/libc/src/wchar/wcstoll.cpp
index 6229d24172b51..54c8520e4d5e7 100644
--- a/libc/src/wchar/wcstoll.cpp
+++ b/libc/src/wchar/wcstoll.cpp
@@ -7,24 +7,15 @@
//===----------------------------------------------------------------------===//
#include "src/wchar/wcstoll.h"
-#include "src/__support/common.h"
-#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
-#include "src/__support/str_to_integer.h"
+#include "src/stdlib/str_to_util.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(long long, wcstoll,
(const wchar_t *__restrict str, wchar_t **__restrict str_end,
int base)) {
- auto result = internal::strtointeger<long long>(str, base);
- if (result.has_error())
- libc_errno = result.error;
-
- if (str_end != nullptr)
- *str_end = const_cast<wchar_t *>(str + result.parsed_len);
-
- return result;
+ return internal::str_to_helper<long long>(str, str_end, base);
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/wchar/wcstoul.cpp b/libc/src/wchar/wcstoul.cpp
index c5639bee1d649..28976b8ece350 100644
--- a/libc/src/wchar/wcstoul.cpp
+++ b/libc/src/wchar/wcstoul.cpp
@@ -7,24 +7,15 @@
//===----------------------------------------------------------------------===//
#include "src/wchar/wcstoul.h"
-#include "src/__support/common.h"
-#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
-#include "src/__support/str_to_integer.h"
+#include "src/stdlib/str_to_util.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(unsigned long, wcstoul,
(const wchar_t *__restrict str, wchar_t **__restrict str_end,
int base)) {
- auto result = internal::strtointeger<unsigned long>(str, base);
- if (result.has_error())
- libc_errno = result.error;
-
- if (str_end != nullptr)
- *str_end = const_cast<wchar_t *>(str + result.parsed_len);
-
- return result;
+ return internal::str_to_helper<unsigned long>(str, str_end, base);
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/wchar/wcstoull.cpp b/libc/src/wchar/wcstoull.cpp
index 2ab24e9b2b2a1..98599cfb6ee3f 100644
--- a/libc/src/wchar/wcstoull.cpp
+++ b/libc/src/wchar/wcstoull.cpp
@@ -7,24 +7,15 @@
//===----------------------------------------------------------------------===//
#include "src/wchar/wcstoull.h"
-#include "src/__support/common.h"
-#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
-#include "src/__support/str_to_integer.h"
+#include "src/stdlib/str_to_util.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(unsigned long long, wcstoull,
(const wchar_t *__restrict str, wchar_t **__restrict str_end,
int base)) {
- auto result = internal::strtointeger<unsigned long long>(str, base);
- if (result.has_error())
- libc_errno = result.error;
-
- if (str_end != nullptr)
- *str_end = const_cast<wchar_t *>(str + result.parsed_len);
-
- return result;
+ return internal::str_to_helper<unsigned long long>(str, str_end, base);
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/src/stdlib/CMakeLists.txt b/libc/test/src/stdlib/CMakeLists.txt
index a7941ead78bb9..9a3926655ff6b 100644
--- a/libc/test/src/stdlib/CMakeLists.txt
+++ b/libc/test/src/stdlib/CMakeLists.txt
@@ -100,8 +100,7 @@ add_libc_test(
strtoint32_test.cpp
DEPENDS
libc.hdr.stdint_proxy
- libc.src.__support.str_to_integer
- libc.src.errno.errno
+ libc.src.stdlib.str_to_util
.strtol_test_support
)
@@ -113,8 +112,7 @@ add_libc_test(
strtoint64_test.cpp
DEPENDS
libc.hdr.stdint_proxy
- libc.src.__support.str_to_integer
- libc.src.errno.errno
+ libc.src.stdlib.str_to_util
.strtol_test_support
)
diff --git a/libc/test/src/stdlib/StrtolTest.h b/libc/test/src/stdlib/StrtolTest.h
index 3a7da1fa85ac7..423e90c5b1ab6 100644
--- a/libc/test/src/stdlib/StrtolTest.h
+++ b/libc/test/src/stdlib/StrtolTest.h
@@ -28,8 +28,11 @@ struct StrtoTest : public LIBC_NAMESPACE::testing::ErrnoCheckingTest {
void InvalidBase(FunctionT func) {
const char *ten = "10";
- ASSERT_EQ(func(ten, nullptr, -1), ReturnT(0));
+ char *str_end = nullptr;
+ ASSERT_EQ(func(ten, &str_end, -1), ReturnT(0));
ASSERT_ERRNO_EQ(EINVAL);
+ // Verify that str_end isn't touched for EINVAL errors.
+ ASSERT_EQ(str_end, nullptr);
}
void CleanBaseTenDecode(FunctionT func) {
diff --git a/libc/test/src/stdlib/strtoint32_test.cpp b/libc/test/src/stdlib/strtoint32_test.cpp
index 1bf199412e58c..d142fc4f76704 100644
--- a/libc/test/src/stdlib/strtoint32_test.cpp
+++ b/libc/test/src/stdlib/strtoint32_test.cpp
@@ -7,9 +7,8 @@
//===----------------------------------------------------------------------===//
#include "hdr/stdint_proxy.h"
-#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
-#include "src/__support/str_to_integer.h"
+#include "src/stdlib/str_to_util.h"
#include "StrtolTest.h"
#include "test/UnitTest/Test.h"
@@ -18,26 +17,12 @@ namespace LIBC_NAMESPACE_DECL {
int32_t strtoint32(const char *__restrict str, char **__restrict str_end,
int base) {
- auto result = internal::strtointeger<int32_t>(str, base);
- if (result.has_error())
- libc_errno = result.error;
-
- if (str_end != nullptr)
- *str_end = const_cast<char *>(str + result.parsed_len);
-
- return result;
+ return internal::str_to_helper<int32_t>(str, str_end, base);
}
uint32_t strtouint32(const char *__restrict str, char **__restrict str_end,
int base) {
- auto result = internal::strtointeger<uint32_t>(str, base);
- if (result.has_error())
- libc_errno = result.error;
-
- if (str_end != nullptr)
- *str_end = const_cast<char *>(str + result.parsed_len);
-
- return result;
+ return internal::str_to_helper<uint32_t>(str, str_end, base);
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/src/stdlib/strtoint64_test.cpp b/libc/test/src/stdlib/strtoint64_test.cpp
index 2b009d7cea690..0abbad041fa5d 100644
--- a/libc/test/src/stdlib/strtoint64_test.cpp
+++ b/libc/test/src/stdlib/strtoint64_test.cpp
@@ -7,9 +7,8 @@
//===----------------------------------------------------------------------===//
#include "hdr/stdint_proxy.h"
-#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
-#include "src/__support/str_to_integer.h"
+#include "src/stdlib/str_to_util.h"
#include "StrtolTest.h"
#include "test/UnitTest/Test.h"
@@ -18,26 +17,12 @@ namespace LIBC_NAMESPACE_DECL {
int64_t strtoint64(const char *__restrict str, char **__restrict str_end,
int base) {
- auto result = internal::strtointeger<int64_t>(str, base);
- if (result.has_error())
- libc_errno = result.error;
-
- if (str_end != nullptr)
- *str_end = const_cast<char *>(str + result.parsed_len);
-
- return result;
+ return internal::str_to_helper<int64_t>(str, str_end, base);
}
uint64_t strtouint64(const char *__restrict str, char **__restrict str_end,
int base) {
- auto result = internal::strtointeger<uint64_t>(str, base);
- if (result.has_error())
- libc_errno = result.error;
-
- if (str_end != nullptr)
- *str_end = const_cast<char *>(str + result.parsed_len);
-
- return result;
+ return internal::str_to_helper<uint64_t>(str, str_end, base);
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/src/wchar/WcstolTest.h b/libc/test/src/wchar/WcstolTest.h
index cadf9e0c42b90..ef1c5ec0ecafe 100644
--- a/libc/test/src/wchar/WcstolTest.h
+++ b/libc/test/src/wchar/WcstolTest.h
@@ -29,8 +29,11 @@ struct WcstoTest : public LIBC_NAMESPACE::testing::ErrnoCheckingTest {
void InvalidBase(FunctionT func) {
const wchar_t *ten = L"10";
- ASSERT_EQ(func(ten, nullptr, -1), ReturnT(0));
+ wchar_t *str_end = nullptr;
+ ASSERT_EQ(func(ten, &str_end, -1), ReturnT(0));
ASSERT_ERRNO_EQ(EINVAL);
+ // Verify that str_end isn't touched for EINVAL errors.
+ ASSERT_EQ(str_end, nullptr);
}
void CleanBaseTenDecode(FunctionT func) {
>From f4992bbfde7610da259ad90cf04e1d8f22e5ac57 Mon Sep 17 00:00:00 2001
From: Alexey Samsonov <vonosmas at gmail.com>
Date: Wed, 27 May 2026 22:05:39 +0000
Subject: [PATCH 2/6] Fix bazel build
---
.../llvm-project-overlay/libc/BUILD.bazel | 47 ++++++++-----------
1 file changed, 20 insertions(+), 27 deletions(-)
diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
index 186f77b030f3a..479aa3c917d8a 100644
--- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
@@ -3105,6 +3105,7 @@ cc_library(
":__support_macros_properties_compiler",
":__support_macros_properties_cpu_features",
":__support_macros_properties_types",
+ ":__support_math_extras",
":__support_number_pair",
":__support_range_reduction",
":__support_range_reduction_double",
@@ -12915,11 +12916,9 @@ libc_function(
hdrs = ["src/inttypes/strtoimax.h"],
deps = [
":__support_common",
- ":__support_libc_errno",
":__support_macros_config",
- ":__support_str_to_integer",
- ":errno",
":hdr_stdint_proxy",
+ ":str_to_util",
],
)
@@ -12929,11 +12928,9 @@ libc_function(
hdrs = ["src/inttypes/strtoumax.h"],
deps = [
":__support_common",
- ":__support_libc_errno",
":__support_macros_config",
- ":__support_str_to_integer",
- ":errno",
":hdr_stdint_proxy",
+ ":str_to_util",
],
)
@@ -13096,10 +13093,8 @@ libc_function(
hdrs = ["src/stdlib/atoi.h"],
deps = [
":__support_common",
- ":__support_libc_errno",
":__support_macros_config",
- ":__support_str_to_integer",
- ":errno",
+ ":str_to_util",
],
)
@@ -13109,10 +13104,8 @@ libc_function(
hdrs = ["src/stdlib/atol.h"],
deps = [
":__support_common",
- ":__support_libc_errno",
":__support_macros_config",
- ":__support_str_to_integer",
- ":errno",
+ ":str_to_util",
],
)
@@ -13122,10 +13115,8 @@ libc_function(
hdrs = ["src/stdlib/atoll.h"],
deps = [
":__support_common",
- ":__support_libc_errno",
":__support_macros_config",
- ":__support_str_to_integer",
- ":errno",
+ ":str_to_util",
],
)
@@ -13234,6 +13225,16 @@ libc_function(
],
)
+libc_support_library(
+ name = "str_to_util",
+ hdrs = ["src/stdlib/str_to_util.h"],
+ deps = [
+ ":__support_common",
+ ":__support_libc_errno",
+ ":__support_str_to_integer",
+ ],
+)
+
libc_support_library(
name = "str_from_util",
hdrs = ["src/stdlib/str_from_util.h"],
@@ -13296,10 +13297,8 @@ libc_function(
hdrs = ["src/stdlib/strtol.h"],
deps = [
":__support_common",
- ":__support_libc_errno",
":__support_macros_config",
- ":__support_str_to_integer",
- ":errno",
+ ":str_to_util",
],
)
@@ -13309,10 +13308,8 @@ libc_function(
hdrs = ["src/stdlib/strtoll.h"],
deps = [
":__support_common",
- ":__support_libc_errno",
":__support_macros_config",
- ":__support_str_to_integer",
- ":errno",
+ ":str_to_util",
],
)
@@ -13322,10 +13319,8 @@ libc_function(
hdrs = ["src/stdlib/strtoul.h"],
deps = [
":__support_common",
- ":__support_libc_errno",
":__support_macros_config",
- ":__support_str_to_integer",
- ":errno",
+ ":str_to_util",
],
)
@@ -13335,10 +13330,8 @@ libc_function(
hdrs = ["src/stdlib/strtoull.h"],
deps = [
":__support_common",
- ":__support_libc_errno",
":__support_macros_config",
- ":__support_str_to_integer",
- ":errno",
+ ":str_to_util",
],
)
>From 3e03668d8a8d0ba3598a66fa3cd2d7cce30b55b1 Mon Sep 17 00:00:00 2001
From: Alexey Samsonov <vonosmas at gmail.com>
Date: Wed, 27 May 2026 23:44:28 +0000
Subject: [PATCH 3/6] Update CMake dependency
---
libc/src/stdlib/CMakeLists.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libc/src/stdlib/CMakeLists.txt b/libc/src/stdlib/CMakeLists.txt
index 2299bc1f0b0c5..e84b90988c6fa 100644
--- a/libc/src/stdlib/CMakeLists.txt
+++ b/libc/src/stdlib/CMakeLists.txt
@@ -147,8 +147,8 @@ add_header_library(
str_to_util.h
DEPENDS
libc.src.__support.common
- libc.src.__support.libc_errno
libc.src.__support.str_to_integer
+ libc.src.errno.errno
)
add_entrypoint_object(
>From 338f344fe97157baec241da4462769cb878992e5 Mon Sep 17 00:00:00 2001
From: Alexey Samsonov <vonosmas at gmail.com>
Date: Thu, 28 May 2026 04:51:22 +0000
Subject: [PATCH 4/6] Revert past 3 commits except for StrtolTest.h and
WcstolTest.h
---
libc/src/inttypes/CMakeLists.txt | 6 ++-
libc/src/inttypes/strtoimax.cpp | 13 ++++-
libc/src/inttypes/strtoumax.cpp | 13 ++++-
libc/src/stdlib/CMakeLists.txt | 43 ++++++++---------
libc/src/stdlib/atoi.cpp | 11 +++--
libc/src/stdlib/atol.cpp | 10 +++-
libc/src/stdlib/atoll.cpp | 10 +++-
libc/src/stdlib/str_to_util.h | 41 ----------------
libc/src/stdlib/strtol.cpp | 13 ++++-
libc/src/stdlib/strtol_l.cpp | 13 ++++-
libc/src/stdlib/strtoll.cpp | 13 ++++-
libc/src/stdlib/strtoll_l.cpp | 13 ++++-
libc/src/stdlib/strtoul.cpp | 13 ++++-
libc/src/stdlib/strtoul_l.cpp | 13 ++++-
libc/src/stdlib/strtoull.cpp | 13 ++++-
libc/src/stdlib/strtoull_l.cpp | 13 ++++-
libc/src/wchar/CMakeLists.txt | 12 +++--
libc/src/wchar/wcstol.cpp | 13 ++++-
libc/src/wchar/wcstoll.cpp | 13 ++++-
libc/src/wchar/wcstoul.cpp | 13 ++++-
libc/src/wchar/wcstoull.cpp | 13 ++++-
libc/test/src/stdlib/CMakeLists.txt | 6 ++-
libc/test/src/stdlib/strtoint32_test.cpp | 21 +++++++--
libc/test/src/stdlib/strtoint64_test.cpp | 21 +++++++--
.../llvm-project-overlay/libc/BUILD.bazel | 47 +++++++++++--------
25 files changed, 279 insertions(+), 131 deletions(-)
delete mode 100644 libc/src/stdlib/str_to_util.h
diff --git a/libc/src/inttypes/CMakeLists.txt b/libc/src/inttypes/CMakeLists.txt
index eb9f2f3375eab..3a48c9a1a8b97 100644
--- a/libc/src/inttypes/CMakeLists.txt
+++ b/libc/src/inttypes/CMakeLists.txt
@@ -6,7 +6,8 @@ add_entrypoint_object(
strtoimax.h
DEPENDS
libc.hdr.stdint_proxy
- libc.src.stdlib.str_to_util
+ libc.src.__support.str_to_integer
+ libc.src.errno.errno
)
add_entrypoint_object(
@@ -17,7 +18,8 @@ add_entrypoint_object(
strtoumax.h
DEPENDS
libc.hdr.stdint_proxy
- libc.src.stdlib.str_to_util
+ libc.src.__support.str_to_integer
+ libc.src.errno.errno
)
add_entrypoint_object(
diff --git a/libc/src/inttypes/strtoimax.cpp b/libc/src/inttypes/strtoimax.cpp
index 213d8800aab80..6e55a4b56aac7 100644
--- a/libc/src/inttypes/strtoimax.cpp
+++ b/libc/src/inttypes/strtoimax.cpp
@@ -7,15 +7,24 @@
//===----------------------------------------------------------------------===//
#include "src/inttypes/strtoimax.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
-#include "src/stdlib/str_to_util.h"
+#include "src/__support/str_to_integer.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(intmax_t, strtoimax,
(const char *__restrict str, char **__restrict str_end,
int base)) {
- return internal::str_to_helper<intmax_t>(str, str_end, base);
+ auto result = internal::strtointeger<intmax_t>(str, base);
+ if (result.has_error())
+ libc_errno = result.error;
+
+ if (str_end != nullptr)
+ *str_end = const_cast<char *>(str + result.parsed_len);
+
+ return result;
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/inttypes/strtoumax.cpp b/libc/src/inttypes/strtoumax.cpp
index 6191ad0491bf2..ce5a0a782d979 100644
--- a/libc/src/inttypes/strtoumax.cpp
+++ b/libc/src/inttypes/strtoumax.cpp
@@ -7,15 +7,24 @@
//===----------------------------------------------------------------------===//
#include "src/inttypes/strtoumax.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
-#include "src/stdlib/str_to_util.h"
+#include "src/__support/str_to_integer.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(uintmax_t, strtoumax,
(const char *__restrict str, char **__restrict str_end,
int base)) {
- return internal::str_to_helper<uintmax_t>(str, str_end, base);
+ auto result = internal::strtointeger<uintmax_t>(str, base);
+ if (result.has_error())
+ libc_errno = result.error;
+
+ if (str_end != nullptr)
+ *str_end = const_cast<char *>(str + result.parsed_len);
+
+ return result;
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/CMakeLists.txt b/libc/src/stdlib/CMakeLists.txt
index e84b90988c6fa..7e542e56a983d 100644
--- a/libc/src/stdlib/CMakeLists.txt
+++ b/libc/src/stdlib/CMakeLists.txt
@@ -5,7 +5,8 @@ add_entrypoint_object(
HDRS
atoi.h
DEPENDS
- .str_to_util
+ libc.src.errno.errno
+ libc.src.__support.str_to_integer
)
add_entrypoint_object(
@@ -26,7 +27,8 @@ add_entrypoint_object(
HDRS
atol.h
DEPENDS
- .str_to_util
+ libc.src.errno.errno
+ libc.src.__support.str_to_integer
)
add_entrypoint_object(
@@ -36,7 +38,8 @@ add_entrypoint_object(
HDRS
atoll.h
DEPENDS
- .str_to_util
+ libc.src.errno.errno
+ libc.src.__support.str_to_integer
)
add_entrypoint_object(
@@ -141,16 +144,6 @@ add_header_library(
libc.src.__support.CPP.type_traits
)
-add_header_library(
- str_to_util
- HDRS
- str_to_util.h
- DEPENDS
- libc.src.__support.common
- libc.src.__support.str_to_integer
- libc.src.errno.errno
-)
-
add_entrypoint_object(
strtof
SRCS
@@ -191,7 +184,8 @@ add_entrypoint_object(
HDRS
strtol.h
DEPENDS
- .str_to_util
+ libc.src.errno.errno
+ libc.src.__support.str_to_integer
)
add_entrypoint_object(
@@ -201,7 +195,8 @@ add_entrypoint_object(
HDRS
strtoll.h
DEPENDS
- .str_to_util
+ libc.src.errno.errno
+ libc.src.__support.str_to_integer
)
add_entrypoint_object(
@@ -211,7 +206,8 @@ add_entrypoint_object(
HDRS
strtoul.h
DEPENDS
- .str_to_util
+ libc.src.errno.errno
+ libc.src.__support.str_to_integer
)
add_entrypoint_object(
@@ -221,7 +217,8 @@ add_entrypoint_object(
HDRS
strtoull.h
DEPENDS
- .str_to_util
+ libc.src.errno.errno
+ libc.src.__support.str_to_integer
)
add_entrypoint_object(
@@ -615,7 +612,8 @@ add_entrypoint_object(
HDRS
strtol_l.h
DEPENDS
- .str_to_util
+ libc.src.errno.errno
+ libc.src.__support.str_to_integer
)
add_entrypoint_object(
@@ -625,7 +623,8 @@ add_entrypoint_object(
HDRS
strtoll_l.h
DEPENDS
- .str_to_util
+ libc.src.errno.errno
+ libc.src.__support.str_to_integer
)
add_entrypoint_object(
@@ -635,7 +634,8 @@ add_entrypoint_object(
HDRS
strtoul_l.h
DEPENDS
- .str_to_util
+ libc.src.errno.errno
+ libc.src.__support.str_to_integer
)
add_entrypoint_object(
@@ -645,7 +645,8 @@ add_entrypoint_object(
HDRS
strtoull_l.h
DEPENDS
- .str_to_util
+ libc.src.errno.errno
+ libc.src.__support.str_to_integer
)
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
diff --git a/libc/src/stdlib/atoi.cpp b/libc/src/stdlib/atoi.cpp
index 9b030685a603b..420bbc8143d55 100644
--- a/libc/src/stdlib/atoi.cpp
+++ b/libc/src/stdlib/atoi.cpp
@@ -7,16 +7,21 @@
//===----------------------------------------------------------------------===//
#include "src/stdlib/atoi.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
-#include "src/stdlib/str_to_util.h"
+#include "src/__support/str_to_integer.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, atoi, (const char *str)) {
// This is done because the standard specifies that atoi is identical to
// (int)(strtol).
- return static_cast<int>(
- internal::str_to_helper<long, char>(str, nullptr, 10));
+ auto result = internal::strtointeger<long>(str, 10);
+ if (result.has_error())
+ libc_errno = result.error;
+
+ return static_cast<int>(result);
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/atol.cpp b/libc/src/stdlib/atol.cpp
index 6b7d15fc6c955..e1110ffa449b0 100644
--- a/libc/src/stdlib/atol.cpp
+++ b/libc/src/stdlib/atol.cpp
@@ -7,13 +7,19 @@
//===----------------------------------------------------------------------===//
#include "src/stdlib/atol.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
-#include "src/stdlib/str_to_util.h"
+#include "src/__support/str_to_integer.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(long, atol, (const char *str)) {
- return internal::str_to_helper<long, char>(str, nullptr, 10);
+ auto result = internal::strtointeger<long>(str, 10);
+ if (result.has_error())
+ libc_errno = result.error;
+
+ return result;
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/atoll.cpp b/libc/src/stdlib/atoll.cpp
index 2945e2dd716d5..063e817f9b790 100644
--- a/libc/src/stdlib/atoll.cpp
+++ b/libc/src/stdlib/atoll.cpp
@@ -7,13 +7,19 @@
//===----------------------------------------------------------------------===//
#include "src/stdlib/atoll.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
-#include "src/stdlib/str_to_util.h"
+#include "src/__support/str_to_integer.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(long long, atoll, (const char *str)) {
- return internal::str_to_helper<long long, char>(str, nullptr, 10);
+ auto result = internal::strtointeger<long long>(str, 10);
+ if (result.has_error())
+ libc_errno = result.error;
+
+ return result;
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/str_to_util.h b/libc/src/stdlib/str_to_util.h
deleted file mode 100644
index f6c3efd25ab3c..0000000000000
--- a/libc/src/stdlib/str_to_util.h
+++ /dev/null
@@ -1,41 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file
-/// Shared implementation of strto* and wcsto* endpoints.
-///
-//===----------------------------------------------------------------------===//
-
-#include "src/__support/common.h"
-#include "src/__support/libc_errno.h"
-#include "src/__support/str_to_integer.h"
-
-namespace LIBC_NAMESPACE_DECL {
-namespace internal {
-
-// Shared implementation of strto* and wcsto* endpoints. Invokes
-// strtointeger shared API and sets errno and str_end pointer according to the
-// standard.
-template <typename T, typename CharType>
-LIBC_INLINE constexpr T str_to_helper(const CharType *__restrict str,
- CharType **__restrict str_end, int base) {
- auto result = strtointeger<T>(str, base);
- if (result.has_error())
- libc_errno = result.error;
-
- // It is unspecified whether str_end should be set to "str" if the base
- // is invalid, we explicitly avoid setting it for consistency with
- // other implementations.
- if (str_end != nullptr && result.error != EINVAL)
- *str_end = const_cast<CharType *>(str + result.parsed_len);
-
- return result.value;
-}
-
-} // namespace internal
-} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/strtol.cpp b/libc/src/stdlib/strtol.cpp
index e524fbd8c5213..42db36b2052b4 100644
--- a/libc/src/stdlib/strtol.cpp
+++ b/libc/src/stdlib/strtol.cpp
@@ -7,15 +7,24 @@
//===----------------------------------------------------------------------===//
#include "src/stdlib/strtol.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
-#include "src/stdlib/str_to_util.h"
+#include "src/__support/str_to_integer.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(long, strtol,
(const char *__restrict str, char **__restrict str_end,
int base)) {
- return internal::str_to_helper<long>(str, str_end, base);
+ auto result = internal::strtointeger<long>(str, base);
+ if (result.has_error())
+ libc_errno = result.error;
+
+ if (str_end != nullptr)
+ *str_end = const_cast<char *>(str + result.parsed_len);
+
+ return result;
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/strtol_l.cpp b/libc/src/stdlib/strtol_l.cpp
index 2fff7d220b830..497a4403eff4b 100644
--- a/libc/src/stdlib/strtol_l.cpp
+++ b/libc/src/stdlib/strtol_l.cpp
@@ -7,15 +7,24 @@
//===----------------------------------------------------------------------===//
#include "src/stdlib/strtol_l.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
-#include "src/stdlib/str_to_util.h"
+#include "src/__support/str_to_integer.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(long, strtol_l,
(const char *__restrict str, char **__restrict str_end,
int base, locale_t)) {
- return internal::str_to_helper<long>(str, str_end, base);
+ auto result = internal::strtointeger<long>(str, base);
+ if (result.has_error())
+ libc_errno = result.error;
+
+ if (str_end != nullptr)
+ *str_end = const_cast<char *>(str + result.parsed_len);
+
+ return result;
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/strtoll.cpp b/libc/src/stdlib/strtoll.cpp
index a446755ecc4b1..c1dca13112e0f 100644
--- a/libc/src/stdlib/strtoll.cpp
+++ b/libc/src/stdlib/strtoll.cpp
@@ -7,15 +7,24 @@
//===----------------------------------------------------------------------===//
#include "src/stdlib/strtoll.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
-#include "src/stdlib/str_to_util.h"
+#include "src/__support/str_to_integer.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(long long, strtoll,
(const char *__restrict str, char **__restrict str_end,
int base)) {
- return internal::str_to_helper<long long>(str, str_end, base);
+ auto result = internal::strtointeger<long long>(str, base);
+ if (result.has_error())
+ libc_errno = result.error;
+
+ if (str_end != nullptr)
+ *str_end = const_cast<char *>(str + result.parsed_len);
+
+ return result;
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/strtoll_l.cpp b/libc/src/stdlib/strtoll_l.cpp
index 1de15a6dc17a9..6f30d7794c5ca 100644
--- a/libc/src/stdlib/strtoll_l.cpp
+++ b/libc/src/stdlib/strtoll_l.cpp
@@ -7,15 +7,24 @@
//===----------------------------------------------------------------------===//
#include "src/stdlib/strtoll_l.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
-#include "src/stdlib/str_to_util.h"
+#include "src/__support/str_to_integer.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(long long, strtoll_l,
(const char *__restrict str, char **__restrict str_end,
int base, locale_t)) {
- return internal::str_to_helper<long long>(str, str_end, base);
+ auto result = internal::strtointeger<long long>(str, base);
+ if (result.has_error())
+ libc_errno = result.error;
+
+ if (str_end != nullptr)
+ *str_end = const_cast<char *>(str + result.parsed_len);
+
+ return result;
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/strtoul.cpp b/libc/src/stdlib/strtoul.cpp
index d213c5e6edc52..d26ca5e5a10a1 100644
--- a/libc/src/stdlib/strtoul.cpp
+++ b/libc/src/stdlib/strtoul.cpp
@@ -7,15 +7,24 @@
//===----------------------------------------------------------------------===//
#include "src/stdlib/strtoul.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
-#include "src/stdlib/str_to_util.h"
+#include "src/__support/str_to_integer.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(unsigned long, strtoul,
(const char *__restrict str, char **__restrict str_end,
int base)) {
- return internal::str_to_helper<unsigned long>(str, str_end, base);
+ auto result = internal::strtointeger<unsigned long>(str, base);
+ if (result.has_error())
+ libc_errno = result.error;
+
+ if (str_end != nullptr)
+ *str_end = const_cast<char *>(str + result.parsed_len);
+
+ return result;
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/strtoul_l.cpp b/libc/src/stdlib/strtoul_l.cpp
index 38e8ff93a9174..9a875ddee9029 100644
--- a/libc/src/stdlib/strtoul_l.cpp
+++ b/libc/src/stdlib/strtoul_l.cpp
@@ -7,15 +7,24 @@
//===----------------------------------------------------------------------===//
#include "src/stdlib/strtoul_l.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
-#include "src/stdlib/str_to_util.h"
+#include "src/__support/str_to_integer.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(unsigned long, strtoul_l,
(const char *__restrict str, char **__restrict str_end,
int base, locale_t)) {
- return internal::str_to_helper<unsigned long>(str, str_end, base);
+ auto result = internal::strtointeger<unsigned long>(str, base);
+ if (result.has_error())
+ libc_errno = result.error;
+
+ if (str_end != nullptr)
+ *str_end = const_cast<char *>(str + result.parsed_len);
+
+ return result;
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/strtoull.cpp b/libc/src/stdlib/strtoull.cpp
index 87ca67f5396f3..8f929f577311e 100644
--- a/libc/src/stdlib/strtoull.cpp
+++ b/libc/src/stdlib/strtoull.cpp
@@ -7,15 +7,24 @@
//===----------------------------------------------------------------------===//
#include "src/stdlib/strtoull.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
-#include "src/stdlib/str_to_util.h"
+#include "src/__support/str_to_integer.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(unsigned long long, strtoull,
(const char *__restrict str, char **__restrict str_end,
int base)) {
- return internal::str_to_helper<unsigned long long>(str, str_end, base);
+ auto result = internal::strtointeger<unsigned long long>(str, base);
+ if (result.has_error())
+ libc_errno = result.error;
+
+ if (str_end != nullptr)
+ *str_end = const_cast<char *>(str + result.parsed_len);
+
+ return result;
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdlib/strtoull_l.cpp b/libc/src/stdlib/strtoull_l.cpp
index 4651b66d90b2b..9eb056b0e59b4 100644
--- a/libc/src/stdlib/strtoull_l.cpp
+++ b/libc/src/stdlib/strtoull_l.cpp
@@ -7,15 +7,24 @@
//===----------------------------------------------------------------------===//
#include "src/stdlib/strtoull_l.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
-#include "src/stdlib/str_to_util.h"
+#include "src/__support/str_to_integer.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(unsigned long long, strtoull_l,
(const char *__restrict str, char **__restrict str_end,
int base, locale_t)) {
- return internal::str_to_helper<unsigned long long>(str, str_end, base);
+ auto result = internal::strtointeger<unsigned long long>(str, base);
+ if (result.has_error())
+ libc_errno = result.error;
+
+ if (str_end != nullptr)
+ *str_end = const_cast<char *>(str + result.parsed_len);
+
+ return result;
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/wchar/CMakeLists.txt b/libc/src/wchar/CMakeLists.txt
index 18c70703f1ef1..eb340a80e5741 100644
--- a/libc/src/wchar/CMakeLists.txt
+++ b/libc/src/wchar/CMakeLists.txt
@@ -60,7 +60,8 @@ add_entrypoint_object(
HDRS
wcstol.h
DEPENDS
- libc.src.stdlib.str_to_util
+ libc.src.errno.errno
+ libc.src.__support.str_to_integer
)
add_entrypoint_object(
@@ -70,7 +71,8 @@ add_entrypoint_object(
HDRS
wcstoll.h
DEPENDS
- libc.src.stdlib.str_to_util
+ libc.src.errno.errno
+ libc.src.__support.str_to_integer
)
add_entrypoint_object(
@@ -80,7 +82,8 @@ add_entrypoint_object(
HDRS
wcstoul.h
DEPENDS
- libc.src.stdlib.str_to_util
+ libc.src.errno.errno
+ libc.src.__support.str_to_integer
)
add_entrypoint_object(
@@ -90,7 +93,8 @@ add_entrypoint_object(
HDRS
wcstoull.h
DEPENDS
- libc.src.stdlib.str_to_util
+ libc.src.errno.errno
+ libc.src.__support.str_to_integer
)
add_entrypoint_object(
diff --git a/libc/src/wchar/wcstol.cpp b/libc/src/wchar/wcstol.cpp
index d3131445a4816..a56b5f91272cd 100644
--- a/libc/src/wchar/wcstol.cpp
+++ b/libc/src/wchar/wcstol.cpp
@@ -7,15 +7,24 @@
//===----------------------------------------------------------------------===//
#include "src/wchar/wcstol.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
-#include "src/stdlib/str_to_util.h"
+#include "src/__support/str_to_integer.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(long, wcstol,
(const wchar_t *__restrict str, wchar_t **__restrict str_end,
int base)) {
- return internal::str_to_helper<long>(str, str_end, base);
+ auto result = internal::strtointeger<long>(str, base);
+ if (result.has_error())
+ libc_errno = result.error;
+
+ if (str_end != nullptr)
+ *str_end = const_cast<wchar_t *>(str + result.parsed_len);
+
+ return result;
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/wchar/wcstoll.cpp b/libc/src/wchar/wcstoll.cpp
index 54c8520e4d5e7..6229d24172b51 100644
--- a/libc/src/wchar/wcstoll.cpp
+++ b/libc/src/wchar/wcstoll.cpp
@@ -7,15 +7,24 @@
//===----------------------------------------------------------------------===//
#include "src/wchar/wcstoll.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
-#include "src/stdlib/str_to_util.h"
+#include "src/__support/str_to_integer.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(long long, wcstoll,
(const wchar_t *__restrict str, wchar_t **__restrict str_end,
int base)) {
- return internal::str_to_helper<long long>(str, str_end, base);
+ auto result = internal::strtointeger<long long>(str, base);
+ if (result.has_error())
+ libc_errno = result.error;
+
+ if (str_end != nullptr)
+ *str_end = const_cast<wchar_t *>(str + result.parsed_len);
+
+ return result;
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/wchar/wcstoul.cpp b/libc/src/wchar/wcstoul.cpp
index 28976b8ece350..c5639bee1d649 100644
--- a/libc/src/wchar/wcstoul.cpp
+++ b/libc/src/wchar/wcstoul.cpp
@@ -7,15 +7,24 @@
//===----------------------------------------------------------------------===//
#include "src/wchar/wcstoul.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
-#include "src/stdlib/str_to_util.h"
+#include "src/__support/str_to_integer.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(unsigned long, wcstoul,
(const wchar_t *__restrict str, wchar_t **__restrict str_end,
int base)) {
- return internal::str_to_helper<unsigned long>(str, str_end, base);
+ auto result = internal::strtointeger<unsigned long>(str, base);
+ if (result.has_error())
+ libc_errno = result.error;
+
+ if (str_end != nullptr)
+ *str_end = const_cast<wchar_t *>(str + result.parsed_len);
+
+ return result;
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/wchar/wcstoull.cpp b/libc/src/wchar/wcstoull.cpp
index 98599cfb6ee3f..2ab24e9b2b2a1 100644
--- a/libc/src/wchar/wcstoull.cpp
+++ b/libc/src/wchar/wcstoull.cpp
@@ -7,15 +7,24 @@
//===----------------------------------------------------------------------===//
#include "src/wchar/wcstoull.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
-#include "src/stdlib/str_to_util.h"
+#include "src/__support/str_to_integer.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(unsigned long long, wcstoull,
(const wchar_t *__restrict str, wchar_t **__restrict str_end,
int base)) {
- return internal::str_to_helper<unsigned long long>(str, str_end, base);
+ auto result = internal::strtointeger<unsigned long long>(str, base);
+ if (result.has_error())
+ libc_errno = result.error;
+
+ if (str_end != nullptr)
+ *str_end = const_cast<wchar_t *>(str + result.parsed_len);
+
+ return result;
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/src/stdlib/CMakeLists.txt b/libc/test/src/stdlib/CMakeLists.txt
index 9a3926655ff6b..a7941ead78bb9 100644
--- a/libc/test/src/stdlib/CMakeLists.txt
+++ b/libc/test/src/stdlib/CMakeLists.txt
@@ -100,7 +100,8 @@ add_libc_test(
strtoint32_test.cpp
DEPENDS
libc.hdr.stdint_proxy
- libc.src.stdlib.str_to_util
+ libc.src.__support.str_to_integer
+ libc.src.errno.errno
.strtol_test_support
)
@@ -112,7 +113,8 @@ add_libc_test(
strtoint64_test.cpp
DEPENDS
libc.hdr.stdint_proxy
- libc.src.stdlib.str_to_util
+ libc.src.__support.str_to_integer
+ libc.src.errno.errno
.strtol_test_support
)
diff --git a/libc/test/src/stdlib/strtoint32_test.cpp b/libc/test/src/stdlib/strtoint32_test.cpp
index d142fc4f76704..1bf199412e58c 100644
--- a/libc/test/src/stdlib/strtoint32_test.cpp
+++ b/libc/test/src/stdlib/strtoint32_test.cpp
@@ -7,8 +7,9 @@
//===----------------------------------------------------------------------===//
#include "hdr/stdint_proxy.h"
+#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
-#include "src/stdlib/str_to_util.h"
+#include "src/__support/str_to_integer.h"
#include "StrtolTest.h"
#include "test/UnitTest/Test.h"
@@ -17,12 +18,26 @@ namespace LIBC_NAMESPACE_DECL {
int32_t strtoint32(const char *__restrict str, char **__restrict str_end,
int base) {
- return internal::str_to_helper<int32_t>(str, str_end, base);
+ auto result = internal::strtointeger<int32_t>(str, base);
+ if (result.has_error())
+ libc_errno = result.error;
+
+ if (str_end != nullptr)
+ *str_end = const_cast<char *>(str + result.parsed_len);
+
+ return result;
}
uint32_t strtouint32(const char *__restrict str, char **__restrict str_end,
int base) {
- return internal::str_to_helper<uint32_t>(str, str_end, base);
+ auto result = internal::strtointeger<uint32_t>(str, base);
+ if (result.has_error())
+ libc_errno = result.error;
+
+ if (str_end != nullptr)
+ *str_end = const_cast<char *>(str + result.parsed_len);
+
+ return result;
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/src/stdlib/strtoint64_test.cpp b/libc/test/src/stdlib/strtoint64_test.cpp
index 0abbad041fa5d..2b009d7cea690 100644
--- a/libc/test/src/stdlib/strtoint64_test.cpp
+++ b/libc/test/src/stdlib/strtoint64_test.cpp
@@ -7,8 +7,9 @@
//===----------------------------------------------------------------------===//
#include "hdr/stdint_proxy.h"
+#include "src/__support/libc_errno.h"
#include "src/__support/macros/config.h"
-#include "src/stdlib/str_to_util.h"
+#include "src/__support/str_to_integer.h"
#include "StrtolTest.h"
#include "test/UnitTest/Test.h"
@@ -17,12 +18,26 @@ namespace LIBC_NAMESPACE_DECL {
int64_t strtoint64(const char *__restrict str, char **__restrict str_end,
int base) {
- return internal::str_to_helper<int64_t>(str, str_end, base);
+ auto result = internal::strtointeger<int64_t>(str, base);
+ if (result.has_error())
+ libc_errno = result.error;
+
+ if (str_end != nullptr)
+ *str_end = const_cast<char *>(str + result.parsed_len);
+
+ return result;
}
uint64_t strtouint64(const char *__restrict str, char **__restrict str_end,
int base) {
- return internal::str_to_helper<uint64_t>(str, str_end, base);
+ auto result = internal::strtointeger<uint64_t>(str, base);
+ if (result.has_error())
+ libc_errno = result.error;
+
+ if (str_end != nullptr)
+ *str_end = const_cast<char *>(str + result.parsed_len);
+
+ return result;
}
} // namespace LIBC_NAMESPACE_DECL
diff --git a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
index 479aa3c917d8a..186f77b030f3a 100644
--- a/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/BUILD.bazel
@@ -3105,7 +3105,6 @@ cc_library(
":__support_macros_properties_compiler",
":__support_macros_properties_cpu_features",
":__support_macros_properties_types",
- ":__support_math_extras",
":__support_number_pair",
":__support_range_reduction",
":__support_range_reduction_double",
@@ -12916,9 +12915,11 @@ libc_function(
hdrs = ["src/inttypes/strtoimax.h"],
deps = [
":__support_common",
+ ":__support_libc_errno",
":__support_macros_config",
+ ":__support_str_to_integer",
+ ":errno",
":hdr_stdint_proxy",
- ":str_to_util",
],
)
@@ -12928,9 +12929,11 @@ libc_function(
hdrs = ["src/inttypes/strtoumax.h"],
deps = [
":__support_common",
+ ":__support_libc_errno",
":__support_macros_config",
+ ":__support_str_to_integer",
+ ":errno",
":hdr_stdint_proxy",
- ":str_to_util",
],
)
@@ -13093,8 +13096,10 @@ libc_function(
hdrs = ["src/stdlib/atoi.h"],
deps = [
":__support_common",
+ ":__support_libc_errno",
":__support_macros_config",
- ":str_to_util",
+ ":__support_str_to_integer",
+ ":errno",
],
)
@@ -13104,8 +13109,10 @@ libc_function(
hdrs = ["src/stdlib/atol.h"],
deps = [
":__support_common",
+ ":__support_libc_errno",
":__support_macros_config",
- ":str_to_util",
+ ":__support_str_to_integer",
+ ":errno",
],
)
@@ -13115,8 +13122,10 @@ libc_function(
hdrs = ["src/stdlib/atoll.h"],
deps = [
":__support_common",
+ ":__support_libc_errno",
":__support_macros_config",
- ":str_to_util",
+ ":__support_str_to_integer",
+ ":errno",
],
)
@@ -13225,16 +13234,6 @@ libc_function(
],
)
-libc_support_library(
- name = "str_to_util",
- hdrs = ["src/stdlib/str_to_util.h"],
- deps = [
- ":__support_common",
- ":__support_libc_errno",
- ":__support_str_to_integer",
- ],
-)
-
libc_support_library(
name = "str_from_util",
hdrs = ["src/stdlib/str_from_util.h"],
@@ -13297,8 +13296,10 @@ libc_function(
hdrs = ["src/stdlib/strtol.h"],
deps = [
":__support_common",
+ ":__support_libc_errno",
":__support_macros_config",
- ":str_to_util",
+ ":__support_str_to_integer",
+ ":errno",
],
)
@@ -13308,8 +13309,10 @@ libc_function(
hdrs = ["src/stdlib/strtoll.h"],
deps = [
":__support_common",
+ ":__support_libc_errno",
":__support_macros_config",
- ":str_to_util",
+ ":__support_str_to_integer",
+ ":errno",
],
)
@@ -13319,8 +13322,10 @@ libc_function(
hdrs = ["src/stdlib/strtoul.h"],
deps = [
":__support_common",
+ ":__support_libc_errno",
":__support_macros_config",
- ":str_to_util",
+ ":__support_str_to_integer",
+ ":errno",
],
)
@@ -13330,8 +13335,10 @@ libc_function(
hdrs = ["src/stdlib/strtoull.h"],
deps = [
":__support_common",
+ ":__support_libc_errno",
":__support_macros_config",
- ":str_to_util",
+ ":__support_str_to_integer",
+ ":errno",
],
)
>From 9e64f26ae9af447deca043be70e33adaac9519c2 Mon Sep 17 00:00:00 2001
From: Alexey Samsonov <vonosmas at gmail.com>
Date: Thu, 28 May 2026 04:57:52 +0000
Subject: [PATCH 5/6] Explicitly add EINVAL checks in all strto/wcsto
functions.
---
libc/src/inttypes/strtoimax.cpp | 2 +-
libc/src/inttypes/strtoumax.cpp | 2 +-
libc/src/stdlib/strtol.cpp | 2 +-
libc/src/stdlib/strtol_l.cpp | 2 +-
libc/src/stdlib/strtoll.cpp | 2 +-
libc/src/stdlib/strtoll_l.cpp | 2 +-
libc/src/stdlib/strtoul.cpp | 2 +-
libc/src/stdlib/strtoul_l.cpp | 2 +-
libc/src/stdlib/strtoull.cpp | 2 +-
libc/src/wchar/wcstol.cpp | 2 +-
libc/src/wchar/wcstoll.cpp | 2 +-
libc/src/wchar/wcstoul.cpp | 2 +-
libc/src/wchar/wcstoull.cpp | 2 +-
libc/test/src/stdlib/strtoint32_test.cpp | 4 ++--
libc/test/src/stdlib/strtoint64_test.cpp | 4 ++--
15 files changed, 17 insertions(+), 17 deletions(-)
diff --git a/libc/src/inttypes/strtoimax.cpp b/libc/src/inttypes/strtoimax.cpp
index 6e55a4b56aac7..4e9265534b6d3 100644
--- a/libc/src/inttypes/strtoimax.cpp
+++ b/libc/src/inttypes/strtoimax.cpp
@@ -21,7 +21,7 @@ LLVM_LIBC_FUNCTION(intmax_t, strtoimax,
if (result.has_error())
libc_errno = result.error;
- if (str_end != nullptr)
+ if (str_end != nullptr && result.error != EINVAL)
*str_end = const_cast<char *>(str + result.parsed_len);
return result;
diff --git a/libc/src/inttypes/strtoumax.cpp b/libc/src/inttypes/strtoumax.cpp
index ce5a0a782d979..93888d936d828 100644
--- a/libc/src/inttypes/strtoumax.cpp
+++ b/libc/src/inttypes/strtoumax.cpp
@@ -21,7 +21,7 @@ LLVM_LIBC_FUNCTION(uintmax_t, strtoumax,
if (result.has_error())
libc_errno = result.error;
- if (str_end != nullptr)
+ if (str_end != nullptr && result.error != EINVAL)
*str_end = const_cast<char *>(str + result.parsed_len);
return result;
diff --git a/libc/src/stdlib/strtol.cpp b/libc/src/stdlib/strtol.cpp
index 42db36b2052b4..54c680acaf3d5 100644
--- a/libc/src/stdlib/strtol.cpp
+++ b/libc/src/stdlib/strtol.cpp
@@ -21,7 +21,7 @@ LLVM_LIBC_FUNCTION(long, strtol,
if (result.has_error())
libc_errno = result.error;
- if (str_end != nullptr)
+ if (str_end != nullptr && result.error != EINVAL)
*str_end = const_cast<char *>(str + result.parsed_len);
return result;
diff --git a/libc/src/stdlib/strtol_l.cpp b/libc/src/stdlib/strtol_l.cpp
index 497a4403eff4b..8ec5fb76fdf47 100644
--- a/libc/src/stdlib/strtol_l.cpp
+++ b/libc/src/stdlib/strtol_l.cpp
@@ -21,7 +21,7 @@ LLVM_LIBC_FUNCTION(long, strtol_l,
if (result.has_error())
libc_errno = result.error;
- if (str_end != nullptr)
+ if (str_end != nullptr && result.error != EINVAL)
*str_end = const_cast<char *>(str + result.parsed_len);
return result;
diff --git a/libc/src/stdlib/strtoll.cpp b/libc/src/stdlib/strtoll.cpp
index c1dca13112e0f..5557c6f393cd3 100644
--- a/libc/src/stdlib/strtoll.cpp
+++ b/libc/src/stdlib/strtoll.cpp
@@ -21,7 +21,7 @@ LLVM_LIBC_FUNCTION(long long, strtoll,
if (result.has_error())
libc_errno = result.error;
- if (str_end != nullptr)
+ if (str_end != nullptr && result.error != EINVAL)
*str_end = const_cast<char *>(str + result.parsed_len);
return result;
diff --git a/libc/src/stdlib/strtoll_l.cpp b/libc/src/stdlib/strtoll_l.cpp
index 6f30d7794c5ca..32bdf4babb748 100644
--- a/libc/src/stdlib/strtoll_l.cpp
+++ b/libc/src/stdlib/strtoll_l.cpp
@@ -21,7 +21,7 @@ LLVM_LIBC_FUNCTION(long long, strtoll_l,
if (result.has_error())
libc_errno = result.error;
- if (str_end != nullptr)
+ if (str_end != nullptr && result.error != EINVAL)
*str_end = const_cast<char *>(str + result.parsed_len);
return result;
diff --git a/libc/src/stdlib/strtoul.cpp b/libc/src/stdlib/strtoul.cpp
index d26ca5e5a10a1..1184c13c175e5 100644
--- a/libc/src/stdlib/strtoul.cpp
+++ b/libc/src/stdlib/strtoul.cpp
@@ -21,7 +21,7 @@ LLVM_LIBC_FUNCTION(unsigned long, strtoul,
if (result.has_error())
libc_errno = result.error;
- if (str_end != nullptr)
+ if (str_end != nullptr && result.error != EINVAL)
*str_end = const_cast<char *>(str + result.parsed_len);
return result;
diff --git a/libc/src/stdlib/strtoul_l.cpp b/libc/src/stdlib/strtoul_l.cpp
index 9a875ddee9029..d90d2e856f24d 100644
--- a/libc/src/stdlib/strtoul_l.cpp
+++ b/libc/src/stdlib/strtoul_l.cpp
@@ -21,7 +21,7 @@ LLVM_LIBC_FUNCTION(unsigned long, strtoul_l,
if (result.has_error())
libc_errno = result.error;
- if (str_end != nullptr)
+ if (str_end != nullptr && result.error != EINVAL)
*str_end = const_cast<char *>(str + result.parsed_len);
return result;
diff --git a/libc/src/stdlib/strtoull.cpp b/libc/src/stdlib/strtoull.cpp
index 8f929f577311e..571821097cb47 100644
--- a/libc/src/stdlib/strtoull.cpp
+++ b/libc/src/stdlib/strtoull.cpp
@@ -21,7 +21,7 @@ LLVM_LIBC_FUNCTION(unsigned long long, strtoull,
if (result.has_error())
libc_errno = result.error;
- if (str_end != nullptr)
+ if (str_end != nullptr && result.error != EINVAL)
*str_end = const_cast<char *>(str + result.parsed_len);
return result;
diff --git a/libc/src/wchar/wcstol.cpp b/libc/src/wchar/wcstol.cpp
index a56b5f91272cd..f381f558128d2 100644
--- a/libc/src/wchar/wcstol.cpp
+++ b/libc/src/wchar/wcstol.cpp
@@ -21,7 +21,7 @@ LLVM_LIBC_FUNCTION(long, wcstol,
if (result.has_error())
libc_errno = result.error;
- if (str_end != nullptr)
+ if (str_end != nullptr && result.error != EINVAL)
*str_end = const_cast<wchar_t *>(str + result.parsed_len);
return result;
diff --git a/libc/src/wchar/wcstoll.cpp b/libc/src/wchar/wcstoll.cpp
index 6229d24172b51..5d89eb679b3db 100644
--- a/libc/src/wchar/wcstoll.cpp
+++ b/libc/src/wchar/wcstoll.cpp
@@ -21,7 +21,7 @@ LLVM_LIBC_FUNCTION(long long, wcstoll,
if (result.has_error())
libc_errno = result.error;
- if (str_end != nullptr)
+ if (str_end != nullptr && result.error != EINVAL)
*str_end = const_cast<wchar_t *>(str + result.parsed_len);
return result;
diff --git a/libc/src/wchar/wcstoul.cpp b/libc/src/wchar/wcstoul.cpp
index c5639bee1d649..ee7516652dbb9 100644
--- a/libc/src/wchar/wcstoul.cpp
+++ b/libc/src/wchar/wcstoul.cpp
@@ -21,7 +21,7 @@ LLVM_LIBC_FUNCTION(unsigned long, wcstoul,
if (result.has_error())
libc_errno = result.error;
- if (str_end != nullptr)
+ if (str_end != nullptr && result.error != EINVAL)
*str_end = const_cast<wchar_t *>(str + result.parsed_len);
return result;
diff --git a/libc/src/wchar/wcstoull.cpp b/libc/src/wchar/wcstoull.cpp
index 2ab24e9b2b2a1..301cb66f003b8 100644
--- a/libc/src/wchar/wcstoull.cpp
+++ b/libc/src/wchar/wcstoull.cpp
@@ -21,7 +21,7 @@ LLVM_LIBC_FUNCTION(unsigned long long, wcstoull,
if (result.has_error())
libc_errno = result.error;
- if (str_end != nullptr)
+ if (str_end != nullptr && result.error != EINVAL)
*str_end = const_cast<wchar_t *>(str + result.parsed_len);
return result;
diff --git a/libc/test/src/stdlib/strtoint32_test.cpp b/libc/test/src/stdlib/strtoint32_test.cpp
index 1bf199412e58c..77a3cb30ba06c 100644
--- a/libc/test/src/stdlib/strtoint32_test.cpp
+++ b/libc/test/src/stdlib/strtoint32_test.cpp
@@ -22,7 +22,7 @@ int32_t strtoint32(const char *__restrict str, char **__restrict str_end,
if (result.has_error())
libc_errno = result.error;
- if (str_end != nullptr)
+ if (str_end != nullptr && result.error != EINVAL)
*str_end = const_cast<char *>(str + result.parsed_len);
return result;
@@ -34,7 +34,7 @@ uint32_t strtouint32(const char *__restrict str, char **__restrict str_end,
if (result.has_error())
libc_errno = result.error;
- if (str_end != nullptr)
+ if (str_end != nullptr && result.error != EINVAL)
*str_end = const_cast<char *>(str + result.parsed_len);
return result;
diff --git a/libc/test/src/stdlib/strtoint64_test.cpp b/libc/test/src/stdlib/strtoint64_test.cpp
index 2b009d7cea690..b8f5bfd74f0c4 100644
--- a/libc/test/src/stdlib/strtoint64_test.cpp
+++ b/libc/test/src/stdlib/strtoint64_test.cpp
@@ -22,7 +22,7 @@ int64_t strtoint64(const char *__restrict str, char **__restrict str_end,
if (result.has_error())
libc_errno = result.error;
- if (str_end != nullptr)
+ if (str_end != nullptr && result.error != EINVAL)
*str_end = const_cast<char *>(str + result.parsed_len);
return result;
@@ -34,7 +34,7 @@ uint64_t strtouint64(const char *__restrict str, char **__restrict str_end,
if (result.has_error())
libc_errno = result.error;
- if (str_end != nullptr)
+ if (str_end != nullptr && result.error != EINVAL)
*str_end = const_cast<char *>(str + result.parsed_len);
return result;
>From b33951bf840d2ad7ec79125213a66a1e3298f5d5 Mon Sep 17 00:00:00 2001
From: Alexey Samsonov <vonosmas at gmail.com>
Date: Thu, 28 May 2026 06:03:37 +0000
Subject: [PATCH 6/6] fix strtoull_l as well
---
libc/src/stdlib/strtoull_l.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libc/src/stdlib/strtoull_l.cpp b/libc/src/stdlib/strtoull_l.cpp
index 9eb056b0e59b4..b82b5bb50b82d 100644
--- a/libc/src/stdlib/strtoull_l.cpp
+++ b/libc/src/stdlib/strtoull_l.cpp
@@ -21,7 +21,7 @@ LLVM_LIBC_FUNCTION(unsigned long long, strtoull_l,
if (result.has_error())
libc_errno = result.error;
- if (str_end != nullptr)
+ if (str_end != nullptr && result.error != EINVAL)
*str_end = const_cast<char *>(str + result.parsed_len);
return result;
More information about the libc-commits
mailing list