From 9774e2daaa5e89c6684f91b82ab5b4b5c6b88c88 Mon Sep 17 00:00:00 2001 From: c8ef Date: Thu, 9 Oct 2025 21:21:09 +0800 Subject: [PATCH 1/8] [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(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(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 Date: Thu, 9 Oct 2025 21:35:51 +0800 Subject: [PATCH 2/8] [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 Date: Fri, 10 Oct 2025 00:05:03 +0800 Subject: [PATCH 3/8] 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(result)); + inp->s_addr = Endian::to_big_endian(static_cast(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 Date: Fri, 10 Oct 2025 22:34:18 +0800 Subject: [PATCH 4/8] 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 Date: Fri, 10 Oct 2025 22:43:34 +0800 Subject: [PATCH 5/8] 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 Date: Fri, 10 Oct 2025 22:45:25 +0800 Subject: [PATCH 6/8] 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 Date: Sat, 11 Oct 2025 20:26:48 +0800 Subject: [PATCH 7/8] 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(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 Date: Tue, 14 Oct 2025 08:45:13 +0800 Subject: [PATCH 8/8] 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));