[libc-commits] [libc] 0a0e0fa - Implement inet_pton (#224644)
via libc-commits
libc-commits at lists.llvm.org
Fri Sep 25 01:50:16 PDT 2026
Author: yahia
Date: 2026-09-25T10:50:07+02:00
New Revision: 0a0e0fa181cf162bcc93be85abf2b1b911027e73
URL: https://github.com/llvm/llvm-project/commit/0a0e0fa181cf162bcc93be85abf2b1b911027e73
DIFF: https://github.com/llvm/llvm-project/commit/0a0e0fa181cf162bcc93be85abf2b1b911027e73.diff
LOG: Implement inet_pton (#224644)
Implement the `inet_pton` function for `IPV4` and its unit tests.
Assisted-by: gemini
Added:
libc/src/arpa/inet/inet_pton.cpp
libc/src/arpa/inet/inet_pton.h
libc/test/src/arpa/inet/inet_pton_test.cpp
Modified:
libc/config/linux/aarch64/entrypoints.txt
libc/config/linux/riscv/entrypoints.txt
libc/config/linux/x86_64/entrypoints.txt
libc/include/arpa/inet.yaml
libc/src/__support/net/CMakeLists.txt
libc/src/__support/net/address.cpp
libc/src/__support/net/address.h
libc/src/arpa/inet/CMakeLists.txt
libc/test/src/arpa/inet/CMakeLists.txt
Removed:
################################################################################
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index fbc1f34dca0dec..15a5367f5fc95d 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -1458,6 +1458,9 @@ endif()
if(LLVM_LIBC_ENABLE_EXPERIMENTAL_ENTRYPOINTS)
if(LLVM_LIBC_FULL_BUILD)
list(APPEND TARGET_LIBC_ENTRYPOINTS
+ # arpa/inet.h entrypoints
+ libc.src.arpa.inet.inet_pton
+
# fnmatch.h entrypoints
libc.src.fnmatch.fnmatch
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index c045833ad1d145..8f4dded27de68c 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -1670,6 +1670,9 @@ endif()
if(LLVM_LIBC_ENABLE_EXPERIMENTAL_ENTRYPOINTS)
if(LLVM_LIBC_FULL_BUILD)
list(APPEND TARGET_LIBC_ENTRYPOINTS
+ # arpa/inet.h entrypoints
+ libc.src.arpa.inet.inet_pton
+
# fnmatch.h entrypoints
libc.src.fnmatch.fnmatch
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 672dd1ad96833f..8ca73cc82cc2db 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -1696,6 +1696,9 @@ endif()
if(LLVM_LIBC_ENABLE_EXPERIMENTAL_ENTRYPOINTS)
if(LLVM_LIBC_FULL_BUILD)
list(APPEND TARGET_LIBC_ENTRYPOINTS
+ # arpa/inet.h entrypoints
+ libc.src.arpa.inet.inet_pton
+
# fnmatch.h entrypoints
libc.src.fnmatch.fnmatch
diff --git a/libc/include/arpa/inet.yaml b/libc/include/arpa/inet.yaml
index 66299748441868..b533382fedf4b4 100644
--- a/libc/include/arpa/inet.yaml
+++ b/libc/include/arpa/inet.yaml
@@ -53,3 +53,11 @@ functions:
- type: const void *__restrict
- type: char *__restrict
- type: socklen_t
+ - name: inet_pton
+ standards:
+ - posix
+ return_type: int
+ arguments:
+ - type: int
+ - type: const char *__restrict
+ - type: void *__restrict
diff --git a/libc/src/__support/net/CMakeLists.txt b/libc/src/__support/net/CMakeLists.txt
index 80b141d06cddc1..effc8b90c775ac 100644
--- a/libc/src/__support/net/CMakeLists.txt
+++ b/libc/src/__support/net/CMakeLists.txt
@@ -9,6 +9,7 @@ add_object_library(
libc.hdr.types.struct_in_addr
libc.hdr.types.struct_in6_addr
libc.hdr.inet_address_macros
+ libc.hdr.stdint_proxy
libc.src.__support.common
libc.src.__support.ctype_utils
libc.src.__support.CPP.optional
diff --git a/libc/src/__support/net/address.cpp b/libc/src/__support/net/address.cpp
index 8e0554ccc298e8..c4bf5432bc4caf 100644
--- a/libc/src/__support/net/address.cpp
+++ b/libc/src/__support/net/address.cpp
@@ -14,6 +14,7 @@
#include "src/__support/net/address.h"
#include "hdr/inet-address-macros.h"
+#include "hdr/stdint_proxy.h"
#include "hdr/types/in_addr_t.h"
#include "hdr/types/struct_in6_addr.h"
#include "hdr/types/struct_in_addr.h"
@@ -26,8 +27,46 @@
#include "src/string/memory_utils/inline_memcpy.h"
namespace LIBC_NAMESPACE_DECL {
+
namespace net {
+[[nodiscard]] bool str_to_ipv4(cpp::string_view src, struct in_addr &dst) {
+ uint8_t bytes[4];
+ size_t idx = 0;
+ uint32_t current_val = 0;
+ size_t digits_in_octet = 0;
+
+ for (char c : src) {
+ if (internal::isdigit(c)) {
+ // Reject octals and leading zeros
+ if (digits_in_octet > 0 && current_val == 0)
+ return false;
+
+ current_val = current_val * 10 + internal::b36_char_to_int(c);
+ if (current_val > 255)
+ return false;
+
+ ++digits_in_octet;
+ } else if (c == '.') {
+ if (digits_in_octet == 0 || idx == 3)
+ return false; // Empty part or too many dots
+
+ bytes[idx++] = static_cast<uint8_t>(current_val);
+ current_val = 0;
+ digits_in_octet = 0;
+ } else {
+ return false;
+ }
+ }
+
+ if (idx != 3 || digits_in_octet == 0)
+ return 0;
+
+ bytes[3] = static_cast<uint8_t>(current_val);
+ inline_memcpy(&dst.s_addr, bytes, 4);
+ return true;
+}
+
cpp::optional<in_addr_t> inet_addr(cpp::string_view src) {
constexpr int IPV4_MAX_DOT_NUM = 3;
in_addr_t parts[IPV4_MAX_DOT_NUM + 1] = {0};
diff --git a/libc/src/__support/net/address.h b/libc/src/__support/net/address.h
index 7c799b122e46e4..1ad3ab04415bec 100644
--- a/libc/src/__support/net/address.h
+++ b/libc/src/__support/net/address.h
@@ -31,6 +31,7 @@ cpp::optional<in_addr_t> inet_addr(cpp::string_view src);
/// provided address into the destination buffer. In case of error, returns
/// false and does not modify the buffer.
[[nodiscard]] bool ipv4_to_str(const struct in_addr &src, cpp::span<char> dst);
+[[nodiscard]] bool str_to_ipv4(cpp::string_view src, struct in_addr &dst);
/// Writes a string representation (including the terminating \0) of the
/// provided address into the destination buffer. In case of error, returns
diff --git a/libc/src/arpa/inet/CMakeLists.txt b/libc/src/arpa/inet/CMakeLists.txt
index e0b12ed33e9470..1096d8654511fa 100644
--- a/libc/src/arpa/inet/CMakeLists.txt
+++ b/libc/src/arpa/inet/CMakeLists.txt
@@ -90,6 +90,25 @@ add_entrypoint_object(
libc.src.__support.net.address
)
+add_entrypoint_object(
+ inet_pton
+ SRCS
+ inet_pton.cpp
+ HDRS
+ inet_pton.h
+ DEPENDS
+ libc.hdr.errno_macros
+ libc.hdr.stdint_proxy
+ libc.hdr.types.struct_in6_addr
+ libc.hdr.types.struct_in_addr
+ libc.src.__support.common
+ libc.src.__support.libc_errno
+ libc.src.__support.net.address
+ libc.src.__support.macros.config
+ libc.src.__support.macros.null_check
+ libc.hdr.sys_socket_macros
+)
+
add_entrypoint_object(
ntohl
SRCS
diff --git a/libc/src/arpa/inet/inet_pton.cpp b/libc/src/arpa/inet/inet_pton.cpp
new file mode 100644
index 00000000000000..9e933de108af41
--- /dev/null
+++ b/libc/src/arpa/inet/inet_pton.cpp
@@ -0,0 +1,39 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+/// This file contains the implementation for inet_pton
+///
+//===----------------------------------------------------------------------===//
+
+#include "inet_pton.h"
+
+#include "hdr/errno_macros.h"
+#include "hdr/stdint_proxy.h"
+#include "hdr/sys_socket_macros.h"
+#include "hdr/types/struct_in6_addr.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/null_check.h"
+#include "src/__support/net/address.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, inet_pton,
+ (int af, const char *__restrict src, void *__restrict dst)) {
+ LIBC_CRASH_ON_NULLPTR(src);
+ LIBC_CRASH_ON_NULLPTR(dst);
+ if (af != AF_INET) {
+ libc_errno = EAFNOSUPPORT;
+ return -1;
+ }
+ return net::str_to_ipv4(src, *reinterpret_cast<struct in_addr *>(dst));
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/arpa/inet/inet_pton.h b/libc/src/arpa/inet/inet_pton.h
new file mode 100644
index 00000000000000..ec682a4c9cf2f4
--- /dev/null
+++ b/libc/src/arpa/inet/inet_pton.h
@@ -0,0 +1,25 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+/// This file contains the declaration of POSIX inet_pton function
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_ARPA_INET_PTON_H
+#define LLVM_LIBC_SRC_ARPA_INET_PTON_H
+
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int inet_pton(int af, const char *__restrict src, void *__restrict dst);
+
+}
+
+#endif
diff --git a/libc/test/src/arpa/inet/CMakeLists.txt b/libc/test/src/arpa/inet/CMakeLists.txt
index c8e1ca5bf7f356..4fba96417bc03c 100644
--- a/libc/test/src/arpa/inet/CMakeLists.txt
+++ b/libc/test/src/arpa/inet/CMakeLists.txt
@@ -72,6 +72,21 @@ add_libc_test(
libc.test.UnitTest.ErrnoCheckingTest
)
+add_libc_test(
+ inet_pton
+ SUITE
+ libc_arpa_inet_unittests
+ SRCS
+ inet_pton_test.cpp
+ DEPENDS
+ libc.hdr.errno_macros
+ libc.hdr.types.struct_in_addr
+ libc.src.arpa.inet.inet_pton
+ libc.src.__support.libc_errno
+ libc.hdr.sys_socket_macros
+ libc.test.UnitTest.ErrnoCheckingTest
+)
+
add_libc_test(
ntohl
SUITE
diff --git a/libc/test/src/arpa/inet/inet_pton_test.cpp b/libc/test/src/arpa/inet/inet_pton_test.cpp
new file mode 100644
index 00000000000000..99b78a23a3479c
--- /dev/null
+++ b/libc/test/src/arpa/inet/inet_pton_test.cpp
@@ -0,0 +1,102 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+/// Unittests for inet_pton.
+///
+//===----------------------------------------------------------------------===//
+
+#include "hdr/errno_macros.h"
+#include "hdr/sys_socket_macros.h"
+#include "hdr/types/struct_in_addr.h"
+#include "src/__support/endian_internal.h"
+#include "src/__support/libc_errno.h"
+#include "src/arpa/inet/inet_pton.h"
+#include "test/UnitTest/ErrnoCheckingTest.h"
+#include "test/UnitTest/Test.h"
+
+using LlvmLibcInetPtonTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
+
+static uint32_t ipv4_bits(uint8_t a, uint8_t b, uint8_t c, uint8_t d) {
+ return LIBC_NAMESPACE::Endian::to_big_endian(
+ static_cast<uint32_t>(a) << 24 | static_cast<uint32_t>(b) << 16 |
+ static_cast<uint32_t>(c) << 8 | static_cast<uint32_t>(d));
+}
+
+TEST_F(LlvmLibcInetPtonTest, ValidIPv4Addresses) {
+ struct in_addr addr;
+
+ EXPECT_EQ(1, LIBC_NAMESPACE::inet_pton(AF_INET, "127.0.0.1", &addr));
+ EXPECT_EQ(addr.s_addr, ipv4_bits(127, 0, 0, 1));
+ ASSERT_ERRNO_SUCCESS();
+
+ EXPECT_EQ(1, LIBC_NAMESPACE::inet_pton(AF_INET, "192.168.1.254", &addr));
+ EXPECT_EQ(addr.s_addr, ipv4_bits(192, 168, 1, 254));
+ ASSERT_ERRNO_SUCCESS();
+
+ EXPECT_EQ(1, LIBC_NAMESPACE::inet_pton(AF_INET, "0.0.0.0", &addr));
+ EXPECT_EQ(addr.s_addr, ipv4_bits(0, 0, 0, 0));
+ ASSERT_ERRNO_SUCCESS();
+
+ EXPECT_EQ(1, LIBC_NAMESPACE::inet_pton(AF_INET, "255.255.255.255", &addr));
+ EXPECT_EQ(addr.s_addr, ipv4_bits(255, 255, 255, 255));
+ ASSERT_ERRNO_SUCCESS();
+}
+
+TEST_F(LlvmLibcInetPtonTest, InvalidOctetValues) {
+ struct in_addr addr;
+
+ EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET, "256.0.0.1", &addr));
+ EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET, "192.168.1.300", &addr));
+ EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET, "192.168.-1.1", &addr));
+ ASSERT_ERRNO_SUCCESS();
+}
+
+TEST_F(LlvmLibcInetPtonTest, InvalidFormats) {
+ struct in_addr addr;
+
+ EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET, "127.0.0", &addr));
+ EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET, "10.0.0.0.1", &addr));
+ EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET, ".1.2.3.4", &addr));
+ EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET, "1.2.3.4.", &addr));
+ EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET, "192..168.1.1", &addr));
+ EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET, "192.168.1.1a", &addr));
+ EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET, "abc.def.ghi.jkl", &addr));
+ EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET, "127.0.0.1 ", &addr));
+ EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET, "", &addr));
+ EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET, ".", &addr));
+ EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET, "0", &addr));
+ EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET, "1", &addr));
+ EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET, ".1", &addr));
+ EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET, "1.1", &addr));
+ EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET, "1.1.", &addr));
+ EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET, "1.1.1", &addr));
+ EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET, "1.1.1.", &addr));
+ ASSERT_ERRNO_SUCCESS();
+}
+
+TEST_F(LlvmLibcInetPtonTest, StrictPosixLeadingZeros) {
+ struct in_addr addr;
+
+ // inet_pton must reject octal-style leading zeros
+ EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET, "192.168.01.1", &addr));
+ EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET, "010.0.0.1", &addr));
+ EXPECT_EQ(0, LIBC_NAMESPACE::inet_pton(AF_INET, "00.0.0.0", &addr));
+ ASSERT_ERRNO_SUCCESS();
+}
+
+TEST_F(LlvmLibcInetPtonTest, InvalidAddressFamily) {
+ struct in_addr addr;
+
+ EXPECT_EQ(-1, LIBC_NAMESPACE::inet_pton(AF_INET + AF_INET6 + 1, "127.0.0.1",
+ &addr));
+ ASSERT_ERRNO_EQ(EAFNOSUPPORT);
+
+ EXPECT_EQ(-1, LIBC_NAMESPACE::inet_pton(12345, "127.0.0.1", &addr));
+ ASSERT_ERRNO_EQ(EAFNOSUPPORT);
+}
More information about the libc-commits
mailing list