[libc-commits] [libc] [libc] implement `inet_aton` (PR #162651)

Connector Switch via libc-commits libc-commits at lists.llvm.org
Tue Oct 21 08:10:21 PDT 2025


https://github.com/c8ef updated https://github.com/llvm/llvm-project/pull/162651

>From 9774e2daaa5e89c6684f91b82ab5b4b5c6b88c88 Mon Sep 17 00:00:00 2001
From: c8ef <c8ef at outlook.com>
Date: Thu, 9 Oct 2025 21:21:09 +0800
Subject: [PATCH 1/9] [libc] implement inet_aton

---
 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                | 10 ++-
 libc/src/arpa/inet/CMakeLists.txt          | 14 ++++
 libc/src/arpa/inet/inet_aton.cpp           | 63 +++++++++++++++
 libc/src/arpa/inet/inet_aton.h             | 21 +++++
 libc/test/src/arpa/inet/CMakeLists.txt     | 13 +++
 libc/test/src/arpa/inet/inet_aton_test.cpp | 93 ++++++++++++++++++++++
 9 files changed, 216 insertions(+), 1 deletion(-)
 create mode 100644 libc/src/arpa/inet/inet_aton.cpp
 create mode 100644 libc/src/arpa/inet/inet_aton.h
 create mode 100644 libc/test/src/arpa/inet/inet_aton_test.cpp

diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 8bf6c44b1d669..714120a79e39a 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -945,6 +945,7 @@ if(LLVM_LIBC_FULL_BUILD)
     # arpa/inet.h entrypoints
     libc.src.arpa.inet.htonl
     libc.src.arpa.inet.htons
+    libc.src.arpa.inet.inet_aton
     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 dffccbab9a8e9..f6bbb346d10e5 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -1077,6 +1077,7 @@ if(LLVM_LIBC_FULL_BUILD)
     # arpa/inet.h entrypoints
     libc.src.arpa.inet.htonl
     libc.src.arpa.inet.htons
+    libc.src.arpa.inet.inet_aton
     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 b4ab073ec912f..aa455e80ec5d3 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -1113,6 +1113,7 @@ if(LLVM_LIBC_FULL_BUILD)
     # arpa/inet.h entrypoints
     libc.src.arpa.inet.htonl
     libc.src.arpa.inet.htons
+    libc.src.arpa.inet.inet_aton
     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 10cd56d6ce786..edc8b4e52763f 100644
--- a/libc/include/arpa/inet.yaml
+++ b/libc/include/arpa/inet.yaml
@@ -1,7 +1,8 @@
 header: arpa/inet.h
 header_template: inet.h.def
 macros: []
-types: []
+types:
+  - type_name: in_addr
 enums: []
 objects: []
 functions:
@@ -17,6 +18,13 @@ functions:
     return_type: uint16_t
     arguments:
       - type: uint16_t
+  - name: inet_aton
+    standards:
+      - POSIX
+    return_type: int
+    arguments:
+      - type: const char *
+      - type: in_addr *
   - name: ntohl
     standards:
       - POSIX
diff --git a/libc/src/arpa/inet/CMakeLists.txt b/libc/src/arpa/inet/CMakeLists.txt
index 1f39a076fde91..fc17c395a6a24 100644
--- a/libc/src/arpa/inet/CMakeLists.txt
+++ b/libc/src/arpa/inet/CMakeLists.txt
@@ -22,6 +22,20 @@ add_entrypoint_object(
     libc.src.__support.common
 )
 
+add_entrypoint_object(
+  inet_aton
+  SRCS
+    inet_aton.cpp
+  HDRS
+    inet_aton.h
+  DEPENDS
+    libc.include.arpa_inet
+    libc.include.llvm-libc-types.in_addr
+    libc.src.__support.common
+    libc.src.__support.str_to_integer
+    libc.src.arpa.inet.htonl
+)
+
 add_entrypoint_object(
   ntohl
   SRCS
diff --git a/libc/src/arpa/inet/inet_aton.cpp b/libc/src/arpa/inet/inet_aton.cpp
new file mode 100644
index 0000000000000..183b147cc0c10
--- /dev/null
+++ b/libc/src/arpa/inet/inet_aton.cpp
@@ -0,0 +1,63 @@
+//===-- Implementation of inet_aton function ------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/arpa/inet/inet_aton.h"
+#include "src/__support/common.h"
+#include "src/__support/str_to_integer.h"
+#include "src/arpa/inet/htonl.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, inet_aton, (const char *cp, in_addr *inp)) {
+  unsigned long parts[4] = {0};
+  int dot_num = 0;
+
+  for (; dot_num < 4; ++dot_num) {
+    auto result = internal::strtointeger<unsigned long>(cp, 0);
+    parts[dot_num] = result;
+
+    if (result.has_error() || result.parsed_len == 0)
+      return 0;
+    char next_char = *(cp + result.parsed_len);
+    if (next_char != '.' && next_char != '\0')
+      return 0;
+    else if (next_char == '\0')
+      break;
+    else
+      cp += (result.parsed_len + 1);
+  }
+
+  unsigned long result = 0;
+  if (dot_num == 0) {
+    if (parts[0] > 0xffffffff)
+      return 0;
+    result = parts[0];
+  } else if (dot_num == 1) {
+    if (parts[0] > 0xff || parts[1] > 0xffffff)
+      return 0;
+    result = (parts[0] << 24) | parts[1];
+  } else if (dot_num == 2) {
+    if (parts[0] > 0xff || parts[1] > 0xff || parts[2] > 0xffff)
+      return 0;
+    result = (parts[0] << 24) | (parts[1] << 16) | parts[2];
+  } else if (dot_num == 3) {
+    if (parts[0] > 0xff || parts[1] > 0xff || parts[2] > 0xff ||
+        parts[3] > 0xff)
+      return 0;
+    result = (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8) | parts[3];
+  } else {
+    return 0;
+  }
+
+  if (inp)
+    inp->s_addr = LIBC_NAMESPACE::htonl(static_cast<uint32_t>(result));
+
+  return 1;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/arpa/inet/inet_aton.h b/libc/src/arpa/inet/inet_aton.h
new file mode 100644
index 0000000000000..ea387d1f6b2f6
--- /dev/null
+++ b/libc/src/arpa/inet/inet_aton.h
@@ -0,0 +1,21 @@
+//===-- Implementation header of inet_aton ----------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_ARPA_INET_INET_ATON_H
+#define LLVM_LIBC_SRC_ARPA_INET_INET_ATON_H
+
+#include "include/llvm-libc-types/in_addr.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int inet_aton(const char *cp, in_addr *inp);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_ARPA_INET_INET_ATON_H
diff --git a/libc/test/src/arpa/inet/CMakeLists.txt b/libc/test/src/arpa/inet/CMakeLists.txt
index 6e78e3a50e612..42fa49fe07267 100644
--- a/libc/test/src/arpa/inet/CMakeLists.txt
+++ b/libc/test/src/arpa/inet/CMakeLists.txt
@@ -26,6 +26,19 @@ add_libc_unittest(
     libc.src.arpa.inet.ntohs
 )
 
+add_libc_unittest(
+  inet_aton
+  SUITE
+    libc_arpa_inet_unittests
+  SRCS
+    inet_aton_test.cpp
+  CXX_STANDARD
+    20
+  DEPENDS
+    libc.src.arpa.inet.htonl
+    libc.src.arpa.inet.inet_aton
+)
+
 add_libc_unittest(
   ntohl
   SUITE
diff --git a/libc/test/src/arpa/inet/inet_aton_test.cpp b/libc/test/src/arpa/inet/inet_aton_test.cpp
new file mode 100644
index 0000000000000..0b438740b99b0
--- /dev/null
+++ b/libc/test/src/arpa/inet/inet_aton_test.cpp
@@ -0,0 +1,93 @@
+//===-- Unittests for inet_aton -------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/arpa/inet/htonl.h"
+#include "src/arpa/inet/inet_aton.h"
+#include "test/UnitTest/Test.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+TEST(LlvmLibcInetAton, ValidTest) {
+  in_addr a;
+
+  // a.b.c.d
+  a.s_addr = 0;
+  ASSERT_EQ(1, inet_aton("127.1.2.4", &a));
+  ASSERT_EQ(htonl(0x7f010204), a.s_addr);
+
+  // a.b.c
+  a.s_addr = 0;
+  ASSERT_EQ(1, inet_aton("127.1.4", &a));
+  ASSERT_EQ(htonl(0x7f010004), a.s_addr);
+
+  // a.b
+  a.s_addr = 0;
+  ASSERT_EQ(1, inet_aton("127.1", &a));
+  ASSERT_EQ(htonl(0x7f000001), a.s_addr);
+
+  // a
+  a.s_addr = 0;
+  ASSERT_EQ(1, inet_aton("0x7f000001", &a));
+  ASSERT_EQ(htonl(0x7f000001), a.s_addr);
+
+  // Hex (0x) and mixed-case hex digits.
+  a.s_addr = 0;
+  ASSERT_EQ(1, inet_aton("0xFf.0.0.1", &a));
+  ASSERT_EQ(htonl(0xff000001), a.s_addr);
+
+  // Hex (0X) and mixed-case hex digits.
+  a.s_addr = 0;
+  ASSERT_EQ(1, inet_aton("0XfF.0.0.1", &a));
+  ASSERT_EQ(htonl(0xff000001), a.s_addr);
+
+  // Octal.
+  a.s_addr = 0;
+  ASSERT_EQ(1, inet_aton("0177.0.0.1", &a));
+  ASSERT_EQ(htonl(0x7f000001), a.s_addr);
+
+  a.s_addr = 0;
+  ASSERT_EQ(1, inet_aton("036", &a));
+  ASSERT_EQ(htonl(036U), a.s_addr);
+}
+
+TEST(LlvmLibcInetAton, InvalidTest) {
+  ASSERT_EQ(0, inet_aton("", nullptr));           // Empty.
+  ASSERT_EQ(0, inet_aton("x", nullptr));          // Leading junk.
+  ASSERT_EQ(0, inet_aton("127.0.0.1x", nullptr)); // Trailing junk.
+  ASSERT_EQ(0, inet_aton("09.0.0.1", nullptr));   // Invalid octal.
+  ASSERT_EQ(0, inet_aton("0xg.0.0.1", nullptr));  // Invalid hex.
+
+  ASSERT_EQ(0, inet_aton("1.2.3.4.5", nullptr)); // Too many dots.
+  ASSERT_EQ(0, inet_aton("1.2.3.4.", nullptr));  // Trailing dot.
+
+  // Out of range a.b.c.d form.
+  ASSERT_EQ(0, inet_aton("999.0.0.1", nullptr));
+  ASSERT_EQ(0, inet_aton("0.999.0.1", nullptr));
+  ASSERT_EQ(0, inet_aton("0.0.999.1", nullptr));
+  ASSERT_EQ(0, inet_aton("0.0.0.999", nullptr));
+
+  // Out of range a.b.c form.
+  ASSERT_EQ(0, inet_aton("256.0.0", nullptr));
+  ASSERT_EQ(0, inet_aton("0.256.0", nullptr));
+  ASSERT_EQ(0, inet_aton("0.0.0x10000", nullptr));
+
+  // Out of range a.b form.
+  ASSERT_EQ(0, inet_aton("256.0", nullptr));
+  ASSERT_EQ(0, inet_aton("0.0x1000000", nullptr));
+
+  // Out of range a form.
+  ASSERT_EQ(0, inet_aton("0x100000000", nullptr));
+
+  // 64-bit overflow.
+  ASSERT_EQ(0, inet_aton("0x10000000000000000", nullptr));
+
+  // Out of range octal.
+  ASSERT_EQ(0, inet_aton("0400.0.0.1", nullptr));
+}
+
+} // namespace LIBC_NAMESPACE_DECL

>From 67fbf2ebc89835af60f06358d5eabb26f5b85d97 Mon Sep 17 00:00:00 2001
From: c8ef <c8ef at outlook.com>
Date: Thu, 9 Oct 2025 21:35:51 +0800
Subject: [PATCH 2/9] [libc] implement inet_aton

---
 libc/include/arpa/inet.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libc/include/arpa/inet.yaml b/libc/include/arpa/inet.yaml
index edc8b4e52763f..6e0629072b6ef 100644
--- a/libc/include/arpa/inet.yaml
+++ b/libc/include/arpa/inet.yaml
@@ -20,7 +20,7 @@ functions:
       - type: uint16_t
   - name: inet_aton
     standards:
-      - POSIX
+      - llvm_libc_ext
     return_type: int
     arguments:
       - type: const char *

>From 247a96ea6fd29a821f58e35b6fb3c581c5f0b38d Mon Sep 17 00:00:00 2001
From: c8ef <c8ef at outlook.com>
Date: Fri, 10 Oct 2025 00:05:03 +0800
Subject: [PATCH 3/9] address review comments

---
 libc/src/arpa/inet/CMakeLists.txt      |  1 -
 libc/src/arpa/inet/inet_aton.cpp       | 19 ++++++++++++-------
 libc/test/src/arpa/inet/CMakeLists.txt |  2 --
 3 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/libc/src/arpa/inet/CMakeLists.txt b/libc/src/arpa/inet/CMakeLists.txt
index fc17c395a6a24..bb43e24ec9d0b 100644
--- a/libc/src/arpa/inet/CMakeLists.txt
+++ b/libc/src/arpa/inet/CMakeLists.txt
@@ -33,7 +33,6 @@ add_entrypoint_object(
     libc.include.llvm-libc-types.in_addr
     libc.src.__support.common
     libc.src.__support.str_to_integer
-    libc.src.arpa.inet.htonl
 )
 
 add_entrypoint_object(
diff --git a/libc/src/arpa/inet/inet_aton.cpp b/libc/src/arpa/inet/inet_aton.cpp
index 183b147cc0c10..b2545e8984234 100644
--- a/libc/src/arpa/inet/inet_aton.cpp
+++ b/libc/src/arpa/inet/inet_aton.cpp
@@ -8,8 +8,8 @@
 
 #include "src/arpa/inet/inet_aton.h"
 #include "src/__support/common.h"
+#include "src/__support/endian_internal.h"
 #include "src/__support/str_to_integer.h"
-#include "src/arpa/inet/htonl.h"
 
 namespace LIBC_NAMESPACE_DECL {
 
@@ -33,29 +33,34 @@ LLVM_LIBC_FUNCTION(int, inet_aton, (const char *cp, in_addr *inp)) {
   }
 
   unsigned long result = 0;
-  if (dot_num == 0) {
+  switch (dot_num) {
+  case 0:
     if (parts[0] > 0xffffffff)
       return 0;
     result = parts[0];
-  } else if (dot_num == 1) {
+    break;
+  case 1:
     if (parts[0] > 0xff || parts[1] > 0xffffff)
       return 0;
     result = (parts[0] << 24) | parts[1];
-  } else if (dot_num == 2) {
+    break;
+  case 2:
     if (parts[0] > 0xff || parts[1] > 0xff || parts[2] > 0xffff)
       return 0;
     result = (parts[0] << 24) | (parts[1] << 16) | parts[2];
-  } else if (dot_num == 3) {
+    break;
+  case 3:
     if (parts[0] > 0xff || parts[1] > 0xff || parts[2] > 0xff ||
         parts[3] > 0xff)
       return 0;
     result = (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8) | parts[3];
-  } else {
+    break;
+  default:
     return 0;
   }
 
   if (inp)
-    inp->s_addr = LIBC_NAMESPACE::htonl(static_cast<uint32_t>(result));
+    inp->s_addr = Endian::to_big_endian(static_cast<uint32_t>(result));
 
   return 1;
 }
diff --git a/libc/test/src/arpa/inet/CMakeLists.txt b/libc/test/src/arpa/inet/CMakeLists.txt
index 42fa49fe07267..d24cd4450d895 100644
--- a/libc/test/src/arpa/inet/CMakeLists.txt
+++ b/libc/test/src/arpa/inet/CMakeLists.txt
@@ -32,8 +32,6 @@ add_libc_unittest(
     libc_arpa_inet_unittests
   SRCS
     inet_aton_test.cpp
-  CXX_STANDARD
-    20
   DEPENDS
     libc.src.arpa.inet.htonl
     libc.src.arpa.inet.inet_aton

>From c86be34864e733c19e9a3e55a2d042c57a24d985 Mon Sep 17 00:00:00 2001
From: c8ef <c8ef at outlook.com>
Date: Fri, 10 Oct 2025 22:34:18 +0800
Subject: [PATCH 4/9] test rejected binary integers

---
 libc/test/src/arpa/inet/inet_aton_test.cpp | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/libc/test/src/arpa/inet/inet_aton_test.cpp b/libc/test/src/arpa/inet/inet_aton_test.cpp
index 0b438740b99b0..45f1f87761ca4 100644
--- a/libc/test/src/arpa/inet/inet_aton_test.cpp
+++ b/libc/test/src/arpa/inet/inet_aton_test.cpp
@@ -56,14 +56,14 @@ TEST(LlvmLibcInetAton, ValidTest) {
 }
 
 TEST(LlvmLibcInetAton, InvalidTest) {
-  ASSERT_EQ(0, inet_aton("", nullptr));           // Empty.
-  ASSERT_EQ(0, inet_aton("x", nullptr));          // Leading junk.
-  ASSERT_EQ(0, inet_aton("127.0.0.1x", nullptr)); // Trailing junk.
-  ASSERT_EQ(0, inet_aton("09.0.0.1", nullptr));   // Invalid octal.
-  ASSERT_EQ(0, inet_aton("0xg.0.0.1", nullptr));  // Invalid hex.
-
-  ASSERT_EQ(0, inet_aton("1.2.3.4.5", nullptr)); // Too many dots.
-  ASSERT_EQ(0, inet_aton("1.2.3.4.", nullptr));  // Trailing dot.
+  ASSERT_EQ(0, inet_aton("", nullptr));            // Empty.
+  ASSERT_EQ(0, inet_aton("x", nullptr));           // Leading junk.
+  ASSERT_EQ(0, inet_aton("127.0.0.1x", nullptr));  // Trailing junk.
+  ASSERT_EQ(0, inet_aton("09.0.0.1", nullptr));    // Invalid octal.
+  ASSERT_EQ(0, inet_aton("0xg.0.0.1", nullptr));   // Invalid hex.
+  ASSERT_EQ(0, inet_aton("0b101.0.0.1", nullptr)); // Binary integers.
+  ASSERT_EQ(0, inet_aton("1.2.3.4.5", nullptr));   // Too many dots.
+  ASSERT_EQ(0, inet_aton("1.2.3.4.", nullptr));    // Trailing dot.
 
   // Out of range a.b.c.d form.
   ASSERT_EQ(0, inet_aton("999.0.0.1", nullptr));

>From a8b5f065f56ab52c5171e8907bb32c8015550149 Mon Sep 17 00:00:00 2001
From: c8ef <c8ef at outlook.com>
Date: Fri, 10 Oct 2025 22:43:34 +0800
Subject: [PATCH 5/9] rewrite as a loop

---
 libc/src/arpa/inet/inet_aton.cpp | 31 ++++++++-----------------------
 1 file changed, 8 insertions(+), 23 deletions(-)

diff --git a/libc/src/arpa/inet/inet_aton.cpp b/libc/src/arpa/inet/inet_aton.cpp
index b2545e8984234..4255c289748e5 100644
--- a/libc/src/arpa/inet/inet_aton.cpp
+++ b/libc/src/arpa/inet/inet_aton.cpp
@@ -32,31 +32,16 @@ LLVM_LIBC_FUNCTION(int, inet_aton, (const char *cp, in_addr *inp)) {
       cp += (result.parsed_len + 1);
   }
 
+  if (dot_num > 3)
+    return 0;
+
   unsigned long result = 0;
-  switch (dot_num) {
-  case 0:
-    if (parts[0] > 0xffffffff)
-      return 0;
-    result = parts[0];
-    break;
-  case 1:
-    if (parts[0] > 0xff || parts[1] > 0xffffff)
+  for (int i = 0; i <= dot_num; ++i) {
+    unsigned max_part = i == dot_num ? (0xffffffffUL >> (8 * dot_num)) : 0xffUL;
+    if (parts[i] > max_part)
       return 0;
-    result = (parts[0] << 24) | parts[1];
-    break;
-  case 2:
-    if (parts[0] > 0xff || parts[1] > 0xff || parts[2] > 0xffff)
-      return 0;
-    result = (parts[0] << 24) | (parts[1] << 16) | parts[2];
-    break;
-  case 3:
-    if (parts[0] > 0xff || parts[1] > 0xff || parts[2] > 0xff ||
-        parts[3] > 0xff)
-      return 0;
-    result = (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8) | parts[3];
-    break;
-  default:
-    return 0;
+    int shift = i == dot_num ? 0 : 8 * (3 - i);
+    result |= parts[i] << shift;
   }
 
   if (inp)

>From ec3514339500716570336bf4c9747c6f54963ff3 Mon Sep 17 00:00:00 2001
From: c8ef <c8ef at outlook.com>
Date: Fri, 10 Oct 2025 22:45:25 +0800
Subject: [PATCH 6/9] add missing long

---
 libc/src/arpa/inet/inet_aton.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/libc/src/arpa/inet/inet_aton.cpp b/libc/src/arpa/inet/inet_aton.cpp
index 4255c289748e5..136d0664cf220 100644
--- a/libc/src/arpa/inet/inet_aton.cpp
+++ b/libc/src/arpa/inet/inet_aton.cpp
@@ -37,7 +37,8 @@ LLVM_LIBC_FUNCTION(int, inet_aton, (const char *cp, in_addr *inp)) {
 
   unsigned long result = 0;
   for (int i = 0; i <= dot_num; ++i) {
-    unsigned max_part = i == dot_num ? (0xffffffffUL >> (8 * dot_num)) : 0xffUL;
+    unsigned long max_part =
+        i == dot_num ? (0xffffffffUL >> (8 * dot_num)) : 0xffUL;
     if (parts[i] > max_part)
       return 0;
     int shift = i == dot_num ? 0 : 8 * (3 - i);

>From e2b5b521508dfc2a87395c5bd6f3f73cbc212556 Mon Sep 17 00:00:00 2001
From: c8ef <c8ef at outlook.com>
Date: Sat, 11 Oct 2025 20:26:48 +0800
Subject: [PATCH 7/9] use IPV4_MAX_DOT_NUM

---
 libc/src/arpa/inet/inet_aton.cpp | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/libc/src/arpa/inet/inet_aton.cpp b/libc/src/arpa/inet/inet_aton.cpp
index 136d0664cf220..7d1811e42fba5 100644
--- a/libc/src/arpa/inet/inet_aton.cpp
+++ b/libc/src/arpa/inet/inet_aton.cpp
@@ -14,10 +14,11 @@
 namespace LIBC_NAMESPACE_DECL {
 
 LLVM_LIBC_FUNCTION(int, inet_aton, (const char *cp, in_addr *inp)) {
-  unsigned long parts[4] = {0};
+  constexpr int IPV4_MAX_DOT_NUM = 3;
+  unsigned long parts[IPV4_MAX_DOT_NUM + 1] = {0};
   int dot_num = 0;
 
-  for (; dot_num < 4; ++dot_num) {
+  for (; dot_num <= IPV4_MAX_DOT_NUM; ++dot_num) {
     auto result = internal::strtointeger<unsigned long>(cp, 0);
     parts[dot_num] = result;
 
@@ -32,7 +33,7 @@ LLVM_LIBC_FUNCTION(int, inet_aton, (const char *cp, in_addr *inp)) {
       cp += (result.parsed_len + 1);
   }
 
-  if (dot_num > 3)
+  if (dot_num > IPV4_MAX_DOT_NUM)
     return 0;
 
   unsigned long result = 0;
@@ -41,7 +42,7 @@ LLVM_LIBC_FUNCTION(int, inet_aton, (const char *cp, in_addr *inp)) {
         i == dot_num ? (0xffffffffUL >> (8 * dot_num)) : 0xffUL;
     if (parts[i] > max_part)
       return 0;
-    int shift = i == dot_num ? 0 : 8 * (3 - i);
+    int shift = i == dot_num ? 0 : 8 * (IPV4_MAX_DOT_NUM - i);
     result |= parts[i] << shift;
   }
 

>From 87d19e8f973699c9f296962aa95d75fa342e1688 Mon Sep 17 00:00:00 2001
From: c8ef <c8ef at outlook.com>
Date: Tue, 14 Oct 2025 08:45:13 +0800
Subject: [PATCH 8/9] address review comments

---
 libc/docs/dev/undefined_behavior.rst       |  7 +++++++
 libc/src/arpa/inet/inet_aton.cpp           |  2 ++
 libc/test/src/arpa/inet/inet_aton_test.cpp | 15 +++++++--------
 3 files changed, 16 insertions(+), 8 deletions(-)

diff --git a/libc/docs/dev/undefined_behavior.rst b/libc/docs/dev/undefined_behavior.rst
index aeeaf17c09aa5..444d10dd08e9c 100644
--- a/libc/docs/dev/undefined_behavior.rst
+++ b/libc/docs/dev/undefined_behavior.rst
@@ -156,3 +156,10 @@ parsed as normal. For l64a it's unspecified what happens if the input value is
 negative. For LLVM-libc, all inputs to l64a are treated as unsigned 32 bit ints.
 Additionally, the return of l64a is in a thread-local buffer that's overwritten
 on each call.
+
+`inet_aton` and Non-Standard Binary Integers
+--------------------------------------------
+The current implementation of the `inet_aton` function utilizes
+`internal::strtointeger` to parse IPv4 numbers-and-dots notations. This
+approach may permit the use of binary integers (prefixed with 0b), which is not
+supported by the standard.
diff --git a/libc/src/arpa/inet/inet_aton.cpp b/libc/src/arpa/inet/inet_aton.cpp
index 7d1811e42fba5..9e36f13fd589b 100644
--- a/libc/src/arpa/inet/inet_aton.cpp
+++ b/libc/src/arpa/inet/inet_aton.cpp
@@ -36,6 +36,8 @@ LLVM_LIBC_FUNCTION(int, inet_aton, (const char *cp, in_addr *inp)) {
   if (dot_num > IPV4_MAX_DOT_NUM)
     return 0;
 
+  // converts the Internet host address cp from the IPv4 numbers-and-dots
+  // notation into binary form (in network byte order)
   unsigned long result = 0;
   for (int i = 0; i <= dot_num; ++i) {
     unsigned long max_part =
diff --git a/libc/test/src/arpa/inet/inet_aton_test.cpp b/libc/test/src/arpa/inet/inet_aton_test.cpp
index 45f1f87761ca4..c9c97870e0dff 100644
--- a/libc/test/src/arpa/inet/inet_aton_test.cpp
+++ b/libc/test/src/arpa/inet/inet_aton_test.cpp
@@ -56,14 +56,13 @@ TEST(LlvmLibcInetAton, ValidTest) {
 }
 
 TEST(LlvmLibcInetAton, InvalidTest) {
-  ASSERT_EQ(0, inet_aton("", nullptr));            // Empty.
-  ASSERT_EQ(0, inet_aton("x", nullptr));           // Leading junk.
-  ASSERT_EQ(0, inet_aton("127.0.0.1x", nullptr));  // Trailing junk.
-  ASSERT_EQ(0, inet_aton("09.0.0.1", nullptr));    // Invalid octal.
-  ASSERT_EQ(0, inet_aton("0xg.0.0.1", nullptr));   // Invalid hex.
-  ASSERT_EQ(0, inet_aton("0b101.0.0.1", nullptr)); // Binary integers.
-  ASSERT_EQ(0, inet_aton("1.2.3.4.5", nullptr));   // Too many dots.
-  ASSERT_EQ(0, inet_aton("1.2.3.4.", nullptr));    // Trailing dot.
+  ASSERT_EQ(0, inet_aton("", nullptr));           // Empty.
+  ASSERT_EQ(0, inet_aton("x", nullptr));          // Leading junk.
+  ASSERT_EQ(0, inet_aton("127.0.0.1x", nullptr)); // Trailing junk.
+  ASSERT_EQ(0, inet_aton("09.0.0.1", nullptr));   // Invalid octal.
+  ASSERT_EQ(0, inet_aton("0xg.0.0.1", nullptr));  // Invalid hex.
+  ASSERT_EQ(0, inet_aton("1.2.3.4.5", nullptr));  // Too many dots.
+  ASSERT_EQ(0, inet_aton("1.2.3.4.", nullptr));   // Trailing dot.
 
   // Out of range a.b.c.d form.
   ASSERT_EQ(0, inet_aton("999.0.0.1", nullptr));

>From 018ca582b80dfe882622ad64722ab333a62c51da Mon Sep 17 00:00:00 2001
From: c8ef <c8ef at outlook.com>
Date: Tue, 21 Oct 2025 23:09:47 +0800
Subject: [PATCH 9/9] address review comments

---
 libc/docs/dev/undefined_behavior.rst | 8 ++++----
 libc/src/arpa/inet/inet_aton.cpp     | 2 +-
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/libc/docs/dev/undefined_behavior.rst b/libc/docs/dev/undefined_behavior.rst
index 444d10dd08e9c..4f8ac22919b0a 100644
--- a/libc/docs/dev/undefined_behavior.rst
+++ b/libc/docs/dev/undefined_behavior.rst
@@ -159,7 +159,7 @@ on each call.
 
 `inet_aton` and Non-Standard Binary Integers
 --------------------------------------------
-The current implementation of the `inet_aton` function utilizes
-`internal::strtointeger` to parse IPv4 numbers-and-dots notations. This
-approach may permit the use of binary integers (prefixed with 0b), which is not
-supported by the standard.
+The current implementation of the `inet_aton` function utilizes the same code
+as `strtol` to parse IPv4 numbers-and-dots notations. This approach may permit
+the use of binary integers (prefixed with 0b), which is not supported by the
+standard.
diff --git a/libc/src/arpa/inet/inet_aton.cpp b/libc/src/arpa/inet/inet_aton.cpp
index 9e36f13fd589b..71419cb9a00c8 100644
--- a/libc/src/arpa/inet/inet_aton.cpp
+++ b/libc/src/arpa/inet/inet_aton.cpp
@@ -37,7 +37,7 @@ LLVM_LIBC_FUNCTION(int, inet_aton, (const char *cp, in_addr *inp)) {
     return 0;
 
   // converts the Internet host address cp from the IPv4 numbers-and-dots
-  // notation into binary form (in network byte order)
+  // notation (a[.b[.c[.d]]]) into binary form (in network byte order)
   unsigned long result = 0;
   for (int i = 0; i <= dot_num; ++i) {
     unsigned long max_part =



More information about the libc-commits mailing list