[libc-commits] [libc] [libc] Add a differential fuzzer for inet_ntop (PR #207977)
Pavel Labath via libc-commits
libc-commits at lists.llvm.org
Tue Jul 7 04:52:39 PDT 2026
https://github.com/labath created https://github.com/llvm/llvm-project/pull/207977
The first byte of the input is used to select the address class and the size of the output buffer. The rest is used as the input.
We compare the results and also check that our implementation does not overflow the buffer.
Assisted by Gemini.
>From 2a49ec2200d43d4c33706dee7ea23158caeb9685 Mon Sep 17 00:00:00 2001
From: Pavel Labath <pavel at labath.sk>
Date: Mon, 15 Jun 2026 12:16:05 +0000
Subject: [PATCH] [libc] Add a differential fuzzer for inet_ntop
The first byte of the input is used to select the address class and the
size of the output buffer. The rest is used as the input.
We compare the results and also check that our implementation does not
overflow the buffer.
Assisted by Gemini.
---
libc/fuzzing/arpa/inet/CMakeLists.txt | 9 ++
.../arpa/inet/inet_ntop_differential_fuzz.cpp | 106 ++++++++++++++++++
2 files changed, 115 insertions(+)
create mode 100644 libc/fuzzing/arpa/inet/inet_ntop_differential_fuzz.cpp
diff --git a/libc/fuzzing/arpa/inet/CMakeLists.txt b/libc/fuzzing/arpa/inet/CMakeLists.txt
index 0a940799c448d..913290a889c44 100644
--- a/libc/fuzzing/arpa/inet/CMakeLists.txt
+++ b/libc/fuzzing/arpa/inet/CMakeLists.txt
@@ -7,3 +7,12 @@ add_libc_fuzzer(
libc.src.arpa.inet.inet_aton
libc.src.string.memcpy
)
+
+add_libc_fuzzer(
+ inet_ntop_differential_fuzz
+ SRCS
+ inet_ntop_differential_fuzz.cpp
+ DEPENDS
+ libc.src.arpa.inet.inet_ntop
+ libc.src.errno.errno
+)
diff --git a/libc/fuzzing/arpa/inet/inet_ntop_differential_fuzz.cpp b/libc/fuzzing/arpa/inet/inet_ntop_differential_fuzz.cpp
new file mode 100644
index 0000000000000..64f498c6f5aef
--- /dev/null
+++ b/libc/fuzzing/arpa/inet/inet_ntop_differential_fuzz.cpp
@@ -0,0 +1,106 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+/// Differential fuzz test for llvm-libc inet_ntop implementation.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/arpa/inet/inet_ntop.h"
+#include <arpa/inet.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ if (size < 1)
+ return 0;
+
+ uint8_t af_selector = data[0];
+
+ int af = (af_selector & 0x80) ? AF_INET : AF_INET6;
+ socklen_t dst_size = data[0] % 64;
+
+ // Extract address bytes. We allocate 16 bytes for IPv6, IPv4 will only use 4.
+ uint8_t address_bytes[16] = {0};
+ size_t payload_size = size - 1;
+ size_t copy_size = payload_size > 16 ? 16 : payload_size;
+ memcpy(address_bytes, data + 1, copy_size);
+
+ // Setup buffers for dst
+ constexpr size_t BUFFER_SIZE = 128;
+ char ref_dst[BUFFER_SIZE];
+ char impl_dst[BUFFER_SIZE];
+
+ // Initialize buffers with sentinel
+ memset(ref_dst, 0x5A, BUFFER_SIZE);
+ memset(impl_dst, 0x5A, BUFFER_SIZE);
+
+ // Call reference implementation
+ const char *ref_res = ::inet_ntop(af, address_bytes, ref_dst, dst_size);
+
+ // Call our implementation
+ const char *impl_res =
+ LIBC_NAMESPACE::inet_ntop(af, address_bytes, impl_dst, dst_size);
+
+ auto print_details = [&]() {
+ fprintf(stderr,
+ "Details:\n"
+ " af: %d\n"
+ " dst_size: %lu\n"
+ " address_bytes: %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x "
+ "%02x%02x %02x%02x %02x%02x\n"
+ " ref_res: %s\n"
+ " impl_res: %s\n",
+ af, static_cast<unsigned long>(dst_size), address_bytes[0],
+ address_bytes[1], address_bytes[2], address_bytes[3],
+ address_bytes[4], address_bytes[5], address_bytes[6],
+ address_bytes[7], address_bytes[8], address_bytes[9],
+ address_bytes[10], address_bytes[11], address_bytes[12],
+ address_bytes[13], address_bytes[14], address_bytes[15],
+ ref_res ? ref_res : "nullptr", impl_res ? impl_res : "nullptr");
+ };
+
+ // Compare results
+ if ((ref_res == nullptr) != (impl_res == nullptr)) {
+ fprintf(stderr, "Success/failure mismatch!\n");
+ print_details();
+ __builtin_trap();
+ }
+
+ if (ref_res != nullptr) {
+ // Both succeeded.
+ // Check that returned pointers are correct
+ if (ref_res != ref_dst || impl_res != impl_dst) {
+ fprintf(stderr, "Returned pointer does not match destination buffer!\n");
+ print_details();
+ __builtin_trap();
+ }
+ // Check that strings match
+ if (strcmp(ref_res, impl_res) != 0) {
+ fprintf(stderr, "Output string mismatch!\n");
+ print_details();
+ __builtin_trap();
+ }
+ }
+
+ // Check for out-of-bounds writes
+ for (size_t i = dst_size; i < BUFFER_SIZE; ++i) {
+ if (impl_dst[i] != 0x5A) {
+ fprintf(stderr,
+ "Out-of-bounds write detected at index %zu (expected 0x5A, got "
+ "0x%02x)!\n",
+ i, (unsigned char)impl_dst[i]);
+ print_details();
+ __builtin_trap();
+ }
+ }
+
+ return 0;
+}
More information about the libc-commits
mailing list