[libc-commits] [libc] Implement inet_pton (PR #224644)

via libc-commits libc-commits at lists.llvm.org
Thu Sep 24 06:19:33 PDT 2026


https://github.com/afnrow updated https://github.com/llvm/llvm-project/pull/224644

>From a31c27bd79a2597448a03521d9d700af706155c2 Mon Sep 17 00:00:00 2001
From: yahia ahmed <yahia.a.abdrabou at gmail.com>
Date: Fri, 18 Sep 2026 17:05:37 +0300
Subject: [PATCH 1/5] fix style issue and add entrypoint

---
 libc/config/linux/aarch64/entrypoints.txt  |  1 +
 libc/config/linux/riscv/entrypoints.txt    |  1 +
 libc/config/linux/x86_64/entrypoints.txt   |  1 +
 libc/include/arpa/inet.yaml                |  8 ++
 libc/src/arpa/inet/CMakeLists.txt          | 20 +++++
 libc/src/arpa/inet/inet_pton.cpp           | 72 +++++++++++++++++
 libc/src/arpa/inet/inet_pton.h             | 25 ++++++
 libc/test/src/arpa/inet/CMakeLists.txt     | 15 ++++
 libc/test/src/arpa/inet/inet_pton_test.cpp | 93 ++++++++++++++++++++++
 9 files changed, 236 insertions(+)
 create mode 100644 libc/src/arpa/inet/inet_pton.cpp
 create mode 100644 libc/src/arpa/inet/inet_pton.h
 create mode 100644 libc/test/src/arpa/inet/inet_pton_test.cpp

diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 4de8ce85b05691..3363191bb153a7 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -1109,6 +1109,7 @@ if(LLVM_LIBC_FULL_BUILD)
     libc.src.arpa.inet.inet_aton
     libc.src.arpa.inet.inet_ntoa
     libc.src.arpa.inet.inet_ntop
+    libc.src.arpa.inet.inet_pton
     libc.src.arpa.inet.ntohl
     libc.src.arpa.inet.ntohs
 
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index 889b4c5c79dbb8..815725a074e066 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -6,6 +6,7 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.arpa.inet.inet_aton
     libc.src.arpa.inet.inet_ntoa
     libc.src.arpa.inet.inet_ntop
+    libc.src.arpa.inet.inet_pton
     libc.src.arpa.inet.ntohl
     libc.src.arpa.inet.ntohs
 
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 8e748287a24692..6554cfe0037e6b 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -6,6 +6,7 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.arpa.inet.inet_aton
     libc.src.arpa.inet.inet_ntoa
     libc.src.arpa.inet.inet_ntop
+    libc.src.arpa.inet.inet_pton
     libc.src.arpa.inet.ntohl
     libc.src.arpa.inet.ntohs
 
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/arpa/inet/CMakeLists.txt b/libc/src/arpa/inet/CMakeLists.txt
index e0b12ed33e9470..65ab3fd1bd5620 100644
--- a/libc/src/arpa/inet/CMakeLists.txt
+++ b/libc/src/arpa/inet/CMakeLists.txt
@@ -90,6 +90,26 @@ 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.CPP.string_view
+    libc.src.__support.common
+    libc.src.__support.libc_errno
+    libc.src.__support.macros.config
+    libc.src.__support.macros.null_check
+    libc.src.__support.str_to_integer
+    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..f7794a171dde31
--- /dev/null
+++ b/libc/src/arpa/inet/inet_pton.cpp
@@ -0,0 +1,72 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 "hdr/types/struct_in_addr.h"
+#include "src/__support/CPP/string_view.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/str_to_integer.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_INET6) {
+    return 0;
+  } else if (af != AF_INET) {
+    libc_errno = EAFNOSUPPORT;
+    return -1;
+  }
+  uint8_t bytes[4];
+  size_t start = 0;
+  cpp::string_view str(src);
+  size_t i{0};
+  for (; i < 4; ++i) {
+    size_t end = str.find_first_of('.', start);
+    if (i < 3 && start == cpp::string_view::npos)
+      return 0; // Missing dot
+    if (i == 3 && end != cpp::string_view::npos)
+      return 0; // Extra dot
+    cpp::string_view part =
+        (i == 3) ? str.substr(start) : str.substr(start, end - start);
+    if (part.empty())
+      return 0; // empty part e.g. 192..1.1
+    if (part.size() > 1 && part[0] == '0')
+      return 0;
+    // Ensure all characters are valid ascii
+    for (char c : part) {
+      if (c < '0' || c > '9')
+        return 0;
+    }
+    auto result = internal::strtointeger<uint32_t>(part.data(), 10);
+    if (result.has_error() || result.value > 255 || result.value < 0)
+      return 0;
+    bytes[i] = static_cast<uint8_t>(result.value);
+    start = end + 1;
+  }
+  auto *addr = reinterpret_cast<struct in_addr *>(dst);
+  __builtin_memcpy(&addr->s_addr, bytes, 4);
+  return 1;
+}
+
+} // 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..5d9c98ba4cde36 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..e8f548386cbe09
--- /dev/null
+++ b/libc/test/src/arpa/inet/inet_pton_test.cpp
@@ -0,0 +1,93 @@
+//===----------------------------------------------------------------------===//
+//
+// 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));
+  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);
+}

>From 554b843eda7d9b95101f5d5799b48bd1665a464b Mon Sep 17 00:00:00 2001
From: yahia ahmed <yahia.a.abdrabou at gmail.com>
Date: Mon, 21 Sep 2026 18:26:14 +0300
Subject: [PATCH 2/5] add inet_pton to address.h

---
 libc/config/linux/aarch64/entrypoints.txt |  5 ++-
 libc/config/linux/riscv/entrypoints.txt   |  4 ++-
 libc/config/linux/x86_64/entrypoints.txt  |  5 ++-
 libc/src/__support/net/CMakeLists.txt     |  1 +
 libc/src/__support/net/address.cpp        | 41 +++++++++++++++++++++++
 libc/src/__support/net/address.h          |  3 +-
 libc/src/arpa/inet/CMakeLists.txt         |  3 +-
 libc/src/arpa/inet/inet_pton.cpp          | 40 ++--------------------
 libc/test/src/arpa/inet/CMakeLists.txt    |  2 +-
 9 files changed, 60 insertions(+), 44 deletions(-)

diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 3363191bb153a7..127fe7621e1b8d 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -1109,7 +1109,6 @@ if(LLVM_LIBC_FULL_BUILD)
     libc.src.arpa.inet.inet_aton
     libc.src.arpa.inet.inet_ntoa
     libc.src.arpa.inet.inet_ntop
-    libc.src.arpa.inet.inet_pton
     libc.src.arpa.inet.ntohl
     libc.src.arpa.inet.ntohs
 
@@ -1429,6 +1428,10 @@ 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 815725a074e066..5147d1bce844c1 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -6,7 +6,6 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.arpa.inet.inet_aton
     libc.src.arpa.inet.inet_ntoa
     libc.src.arpa.inet.inet_ntop
-    libc.src.arpa.inet.inet_pton
     libc.src.arpa.inet.ntohl
     libc.src.arpa.inet.ntohs
 
@@ -1652,6 +1651,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 6554cfe0037e6b..24eaef6a94679e 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -6,7 +6,6 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.arpa.inet.inet_aton
     libc.src.arpa.inet.inet_ntoa
     libc.src.arpa.inet.inet_ntop
-    libc.src.arpa.inet.inet_pton
     libc.src.arpa.inet.ntohl
     libc.src.arpa.inet.ntohs
 
@@ -1667,6 +1666,10 @@ 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/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..ec9a381c5a21ee 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,48 @@
 #include "src/string/memory_utils/inline_memcpy.h"
 
 namespace LIBC_NAMESPACE_DECL {
+
 namespace net {
 
+int inet_pton_v4(cpp::string_view src, void *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 (c >= '0' && c <= '9') {
+      // Reject octals and leading zeros
+      if (digits_in_octet > 0 && current_val == 0)
+        return 0;
+
+      current_val = current_val * 10 + static_cast<uint32_t>(c - '0');
+      if (current_val > 255)
+        return 0;
+
+      ++digits_in_octet;
+    } else if (c == '.') {
+      if (digits_in_octet == 0 || idx == 3)
+        return 0; // Empty part or too many dots
+
+      bytes[idx++] = static_cast<uint8_t>(current_val);
+      current_val = 0;
+      digits_in_octet = 0;
+    } else {
+      return 0; // Not ASCII
+    }
+  }
+
+  if (idx != 3 || digits_in_octet == 0)
+    return 0;
+
+  bytes[3] = static_cast<uint8_t>(current_val);
+
+  auto addr = reinterpret_cast<struct in_addr *>(dst);
+  __builtin_memcpy(&addr->s_addr, bytes, 4);
+  return 1;
+}
+
 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..d7e04c60be88ae 100644
--- a/libc/src/__support/net/address.h
+++ b/libc/src/__support/net/address.h
@@ -25,7 +25,8 @@
 namespace LIBC_NAMESPACE_DECL {
 namespace net {
 
-cpp::optional<in_addr_t> inet_addr(cpp::string_view src);
+int inet_addr(cpp::string_view src, void *dst);
+int inet_pton_v4(cpp::string_view src, void *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 65ab3fd1bd5620..1096d8654511fa 100644
--- a/libc/src/arpa/inet/CMakeLists.txt
+++ b/libc/src/arpa/inet/CMakeLists.txt
@@ -101,12 +101,11 @@ add_entrypoint_object(
     libc.hdr.stdint_proxy
     libc.hdr.types.struct_in6_addr
     libc.hdr.types.struct_in_addr
-    libc.src.__support.CPP.string_view
     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.src.__support.str_to_integer
     libc.hdr.sys_socket_macros
 )
 
diff --git a/libc/src/arpa/inet/inet_pton.cpp b/libc/src/arpa/inet/inet_pton.cpp
index f7794a171dde31..53366e5a038c05 100644
--- a/libc/src/arpa/inet/inet_pton.cpp
+++ b/libc/src/arpa/inet/inet_pton.cpp
@@ -16,14 +16,11 @@
 #include "hdr/errno_macros.h"
 #include "hdr/stdint_proxy.h"
 #include "hdr/sys_socket_macros.h"
-#include "hdr/types/struct_in6_addr.h"
-#include "hdr/types/struct_in_addr.h"
-#include "src/__support/CPP/string_view.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/str_to_integer.h"
+#include "src/__support/net/address.h"
 
 namespace LIBC_NAMESPACE_DECL {
 
@@ -31,42 +28,11 @@ 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_INET6) {
-    return 0;
-  } else if (af != AF_INET) {
+  if (af != AF_INET) {
     libc_errno = EAFNOSUPPORT;
     return -1;
   }
-  uint8_t bytes[4];
-  size_t start = 0;
-  cpp::string_view str(src);
-  size_t i{0};
-  for (; i < 4; ++i) {
-    size_t end = str.find_first_of('.', start);
-    if (i < 3 && start == cpp::string_view::npos)
-      return 0; // Missing dot
-    if (i == 3 && end != cpp::string_view::npos)
-      return 0; // Extra dot
-    cpp::string_view part =
-        (i == 3) ? str.substr(start) : str.substr(start, end - start);
-    if (part.empty())
-      return 0; // empty part e.g. 192..1.1
-    if (part.size() > 1 && part[0] == '0')
-      return 0;
-    // Ensure all characters are valid ascii
-    for (char c : part) {
-      if (c < '0' || c > '9')
-        return 0;
-    }
-    auto result = internal::strtointeger<uint32_t>(part.data(), 10);
-    if (result.has_error() || result.value > 255 || result.value < 0)
-      return 0;
-    bytes[i] = static_cast<uint8_t>(result.value);
-    start = end + 1;
-  }
-  auto *addr = reinterpret_cast<struct in_addr *>(dst);
-  __builtin_memcpy(&addr->s_addr, bytes, 4);
-  return 1;
+  return net::inet_pton_v4(src, dst);
 }
 
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/src/arpa/inet/CMakeLists.txt b/libc/test/src/arpa/inet/CMakeLists.txt
index 5d9c98ba4cde36..4fba96417bc03c 100644
--- a/libc/test/src/arpa/inet/CMakeLists.txt
+++ b/libc/test/src/arpa/inet/CMakeLists.txt
@@ -75,7 +75,7 @@ add_libc_test(
 add_libc_test(
   inet_pton
   SUITE
-   libc_arpa_inet_unittests
+    libc_arpa_inet_unittests
   SRCS
     inet_pton_test.cpp
   DEPENDS

>From d2a445f2c74bb76c4ba859b22ccfb869c885b378 Mon Sep 17 00:00:00 2001
From: yahia ahmed <yahia.a.abdrabou at gmail.com>
Date: Tue, 22 Sep 2026 16:18:30 +0300
Subject: [PATCH 3/5] address comments and change signature and add tests

---
 libc/config/linux/aarch64/entrypoints.txt  | 5 +----
 libc/config/linux/x86_64/entrypoints.txt   | 5 +----
 libc/src/__support/net/address.cpp         | 7 +++----
 libc/src/__support/net/address.h           | 2 +-
 libc/src/arpa/inet/inet_pton.cpp           | 2 +-
 libc/test/src/arpa/inet/inet_pton_test.cpp | 9 +++++++++
 6 files changed, 16 insertions(+), 14 deletions(-)

diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 127fe7621e1b8d..14cc2b9d343e72 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -1428,10 +1428,6 @@ 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
 
@@ -1442,6 +1438,7 @@ if(LLVM_LIBC_ENABLE_EXPERIMENTAL_ENTRYPOINTS)
       # net/if.h entrypoints
       libc.src.net.if_freenameindex
       libc.src.net.if_nameindex
+      libc.src.arpa.inet.inet_pton
 
       # netdb.h entrypoints
       libc.src.netdb.freeaddrinfo
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 24eaef6a94679e..f054e7f5a63be9 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -1666,10 +1666,6 @@ 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
 
@@ -1680,6 +1676,7 @@ if(LLVM_LIBC_ENABLE_EXPERIMENTAL_ENTRYPOINTS)
       # net/if.h entrypoints
       libc.src.net.if_freenameindex
       libc.src.net.if_nameindex
+      libc.src.arpa.inet.inet_pton
 
       # netdb.h entrypoints
       libc.src.netdb.freeaddrinfo
diff --git a/libc/src/__support/net/address.cpp b/libc/src/__support/net/address.cpp
index ec9a381c5a21ee..44d6b7633ff56f 100644
--- a/libc/src/__support/net/address.cpp
+++ b/libc/src/__support/net/address.cpp
@@ -30,7 +30,7 @@ namespace LIBC_NAMESPACE_DECL {
 
 namespace net {
 
-int inet_pton_v4(cpp::string_view src, void *dst) {
+[[nodiscard]] int str_to_ipv4(cpp::string_view src, void *dst) {
   uint8_t bytes[4];
   size_t idx = 0;
   uint32_t current_val = 0;
@@ -63,9 +63,8 @@ int inet_pton_v4(cpp::string_view src, void *dst) {
     return 0;
 
   bytes[3] = static_cast<uint8_t>(current_val);
-
-  auto addr = reinterpret_cast<struct in_addr *>(dst);
-  __builtin_memcpy(&addr->s_addr, bytes, 4);
+  auto *addr = reinterpret_cast<struct in_addr *>(dst);
+  inline_memcpy(&addr->s_addr, bytes, 4);
   return 1;
 }
 
diff --git a/libc/src/__support/net/address.h b/libc/src/__support/net/address.h
index d7e04c60be88ae..cbe69b075c90a0 100644
--- a/libc/src/__support/net/address.h
+++ b/libc/src/__support/net/address.h
@@ -26,12 +26,12 @@ namespace LIBC_NAMESPACE_DECL {
 namespace net {
 
 int inet_addr(cpp::string_view src, void *dst);
-int inet_pton_v4(cpp::string_view src, void *dst);
 
 /// Writes a string representation (including the terminating \0) of the
 /// 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]] int str_to_ipv4(cpp::string_view src, void *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/inet_pton.cpp b/libc/src/arpa/inet/inet_pton.cpp
index 53366e5a038c05..79fc8f51893a31 100644
--- a/libc/src/arpa/inet/inet_pton.cpp
+++ b/libc/src/arpa/inet/inet_pton.cpp
@@ -32,7 +32,7 @@ LLVM_LIBC_FUNCTION(int, inet_pton,
     libc_errno = EAFNOSUPPORT;
     return -1;
   }
-  return net::inet_pton_v4(src, dst);
+  return net::str_to_ipv4(src, dst);
 }
 
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/src/arpa/inet/inet_pton_test.cpp b/libc/test/src/arpa/inet/inet_pton_test.cpp
index e8f548386cbe09..99b78a23a3479c 100644
--- a/libc/test/src/arpa/inet/inet_pton_test.cpp
+++ b/libc/test/src/arpa/inet/inet_pton_test.cpp
@@ -68,6 +68,15 @@ TEST_F(LlvmLibcInetPtonTest, InvalidFormats) {
   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();
 }
 

>From ca73252c99d1950883f7c371bfeab6aaad84797f Mon Sep 17 00:00:00 2001
From: yahia ahmed <yahia.a.abdrabou at gmail.com>
Date: Tue, 22 Sep 2026 16:25:45 +0300
Subject: [PATCH 4/5] trigger CI

---
 libc/src/__support/net/address.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libc/src/__support/net/address.h b/libc/src/__support/net/address.h
index cbe69b075c90a0..cc75919a3e3f67 100644
--- a/libc/src/__support/net/address.h
+++ b/libc/src/__support/net/address.h
@@ -25,7 +25,7 @@
 namespace LIBC_NAMESPACE_DECL {
 namespace net {
 
-int inet_addr(cpp::string_view src, void *dst);
+cpp::optional<in_addr_t> inet_addr(cpp::string_view src);
 
 /// Writes a string representation (including the terminating \0) of the
 /// provided address into the destination buffer. In case of error, returns

>From 7bd6a07e65db1e2b9c670ba8d525d72cad60bf9a Mon Sep 17 00:00:00 2001
From: yahia ahmed <yahia.a.abdrabou at gmail.com>
Date: Thu, 24 Sep 2026 16:18:33 +0300
Subject: [PATCH 5/5] add ctype functions

---
 libc/src/__support/net/address.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/libc/src/__support/net/address.cpp b/libc/src/__support/net/address.cpp
index 44d6b7633ff56f..05ae40cc506bd6 100644
--- a/libc/src/__support/net/address.cpp
+++ b/libc/src/__support/net/address.cpp
@@ -37,12 +37,12 @@ namespace net {
   size_t digits_in_octet = 0;
 
   for (char c : src) {
-    if (c >= '0' && c <= '9') {
+    if (internal::isdigit(c)) {
       // Reject octals and leading zeros
       if (digits_in_octet > 0 && current_val == 0)
         return 0;
 
-      current_val = current_val * 10 + static_cast<uint32_t>(c - '0');
+      current_val = current_val * 10 + internal::b36_char_to_int(c);
       if (current_val > 255)
         return 0;
 



More information about the libc-commits mailing list