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

via libc-commits libc-commits at lists.llvm.org
Fri Sep 18 06:56:50 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libc

Author: yahia (afnrow)

<details>
<summary>Changes</summary>

Implement the `inet_pton` function for `IPV4` and its unit tests.

Assisted-by: gemini


---
Full diff: https://github.com/llvm/llvm-project/pull/224644.diff


7 Files Affected:

- (modified) libc/config/linux/x86_64/entrypoints.txt (+1) 
- (modified) libc/include/arpa/inet.yaml (+8) 
- (modified) libc/src/arpa/inet/CMakeLists.txt (+20) 
- (added) libc/src/arpa/inet/inet_pton.cpp (+73) 
- (added) libc/src/arpa/inet/inet_pton.h (+25) 
- (modified) libc/test/src/arpa/inet/CMakeLists.txt (+15) 
- (added) libc/test/src/arpa/inet/inet_pton_test.cpp (+93) 


``````````diff
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 8e748287a2469..6554cfe0037e6 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 6629974844186..b533382fedf4b 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 e0b12ed33e947..65ab3fd1bd562 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 0000000000000..632386c56d252
--- /dev/null
+++ b/libc/src/arpa/inet/inet_pton.cpp
@@ -0,0 +1,73 @@
+//===----------------------------------------------------------------------===//
+//
+// 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/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 "hdr/sys_socket_macros.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 0000000000000..ec682a4c9cf2f
--- /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 c8e1ca5bf7f35..5d9c98ba4cde3 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 0000000000000..ff49c374553b5
--- /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/libc_errno.h"
+#include "src/__support/endian_internal.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);
+}

``````````

</details>


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


More information about the libc-commits mailing list