[libc] Implement inet_ntoa (#208702)

Implement inet_ntoa, reusing the internal net::ipv4_to_str helper that
backs inet_ntop.

The result is stored in a *thread-local* static buffer. A thread-local
buffer is not required for POSIX conformance, but there is some
precedent for that, both in llvm libc (e.g. `strsignal`) and in glibc
(whose `inet_ntoa` uses it). I'm doing the same for maximum
compatiblity.

Assisted by Gemini.
This commit is contained in:
Pavel Labath 2026-07-15 09:08:26 +02:00 committed by GitHub
parent 7881a37588
commit 89fa7352a2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 138 additions and 3 deletions

View file

@ -1039,6 +1039,7 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.arpa.inet.htons
libc.src.arpa.inet.inet_addr
libc.src.arpa.inet.inet_aton
libc.src.arpa.inet.inet_ntoa
libc.src.arpa.inet.inet_ntop
libc.src.arpa.inet.ntohl
libc.src.arpa.inet.ntohs

View file

@ -4,6 +4,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.arpa.inet.htons
libc.src.arpa.inet.inet_addr
libc.src.arpa.inet.inet_aton
libc.src.arpa.inet.inet_ntoa
libc.src.arpa.inet.inet_ntop
libc.src.arpa.inet.ntohl
libc.src.arpa.inet.ntohs

View file

@ -4,6 +4,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.arpa.inet.htons
libc.src.arpa.inet.inet_addr
libc.src.arpa.inet.inet_aton
libc.src.arpa.inet.inet_ntoa
libc.src.arpa.inet.inet_ntop
libc.src.arpa.inet.ntohl
libc.src.arpa.inet.ntohs

View file

@ -22,7 +22,6 @@ types:
- type_name: in_addr_t
- type_name: socklen_t
- type_name: struct_in_addr
- type_name: socklen_t
enums: []
objects: []
functions:
@ -39,6 +38,12 @@ functions:
arguments:
- type: const char *
- type: struct in_addr *
- name: inet_ntoa
standards:
- posix
return_type: char *
arguments:
- type: struct in_addr
- name: inet_ntop
standards:
- posix

View file

@ -51,6 +51,22 @@ add_entrypoint_object(
libc.src.__support.net.address
)
add_entrypoint_object(
inet_ntoa
SRCS
inet_ntoa.cpp
HDRS
inet_ntoa.h
DEPENDS
libc.include.arpa_inet
libc.hdr.inet_address_macros
libc.hdr.types.struct_in_addr
libc.src.__support.common
libc.src.__support.CPP.span
libc.src.__support.macros.config
libc.src.__support.net.address
)
add_entrypoint_object(
inet_ntop
SRCS
@ -72,7 +88,6 @@ add_entrypoint_object(
libc.src.__support.net.address
)
add_entrypoint_object(
ntohl
SRCS

View file

@ -0,0 +1,29 @@
//===----------------------------------------------------------------------===//
//
// 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
/// Implementation of inet_ntoa function.
///
//===----------------------------------------------------------------------===//
#include "src/arpa/inet/inet_ntoa.h"
#include "hdr/inet-address-macros.h"
#include "src/__support/CPP/span.h"
#include "src/__support/common.h"
#include "src/__support/net/address.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(char *, inet_ntoa, (struct in_addr in)) {
static LIBC_THREAD_LOCAL char buffer[INET_ADDRSTRLEN];
// Buffer is large enough for any address.
(void)net::ipv4_to_str(in, cpp::span<char>(buffer, INET_ADDRSTRLEN));
return buffer;
}
} // namespace LIBC_NAMESPACE_DECL

View file

@ -0,0 +1,26 @@
//===----------------------------------------------------------------------===//
//
// 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
/// Implementation header of inet_ntoa.
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_SRC_ARPA_INET_INET_NTOA_H
#define LLVM_LIBC_SRC_ARPA_INET_INET_NTOA_H
#include "hdr/types/struct_in_addr.h"
#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
char *inet_ntoa(struct in_addr in);
} // namespace LIBC_NAMESPACE_DECL
#endif // LLVM_LIBC_SRC_ARPA_INET_INET_NTOA_H

View file

@ -44,6 +44,18 @@ add_libc_unittest(
libc.src.arpa.inet.inet_aton
)
add_libc_unittest(
inet_ntoa
SUITE
libc_arpa_inet_unittests
SRCS
inet_ntoa_test.cpp
DEPENDS
libc.src.arpa.inet.inet_ntoa
libc.hdr.types.struct_in_addr
libc.src.__support.endian_internal
)
add_libc_unittest(
inet_ntop
SUITE
@ -60,7 +72,6 @@ add_libc_unittest(
libc.test.UnitTest.ErrnoCheckingTest
)
add_libc_unittest(
ntohl
SUITE

View file

@ -0,0 +1,46 @@
//===----------------------------------------------------------------------===//
//
// 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_ntoa.
///
//===----------------------------------------------------------------------===//
#include "hdr/types/struct_in_addr.h"
#include "src/__support/endian_internal.h"
#include "src/arpa/inet/inet_ntoa.h"
#include "test/UnitTest/Test.h"
static struct in_addr make_addr(uint8_t a, uint8_t b, uint8_t c, uint8_t d) {
struct in_addr addr;
addr.s_addr = 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));
return addr;
}
TEST(LlvmLibcInetNtoaTest, BasicConversion) {
EXPECT_STREQ("127.0.0.1", LIBC_NAMESPACE::inet_ntoa(make_addr(127, 0, 0, 1)));
EXPECT_STREQ("0.0.0.0", LIBC_NAMESPACE::inet_ntoa(make_addr(0, 0, 0, 0)));
EXPECT_STREQ("255.255.255.255",
LIBC_NAMESPACE::inet_ntoa(make_addr(255, 255, 255, 255)));
EXPECT_STREQ("192.168.1.100",
LIBC_NAMESPACE::inet_ntoa(make_addr(192, 168, 1, 100)));
EXPECT_STREQ("10.0.0.1", LIBC_NAMESPACE::inet_ntoa(make_addr(10, 0, 0, 1)));
}
TEST(LlvmLibcInetNtoaTest, BufferReuseAndOverwrite) {
char *ptr1 = LIBC_NAMESPACE::inet_ntoa(make_addr(1, 2, 3, 4));
EXPECT_STREQ("1.2.3.4", ptr1);
char *ptr2 = LIBC_NAMESPACE::inet_ntoa(make_addr(5, 6, 7, 8));
// Our implementation returns pointer to the same static buffer
EXPECT_EQ(ptr1, ptr2);
EXPECT_STREQ("5.6.7.8", ptr1);
EXPECT_STREQ("5.6.7.8", ptr2);
}