blob: fc286ac62d189152677b6cbcc4227df7d50f5e19 [file] [edit]
//===----------------------------------------------------------------------===//
//
// 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];
constexpr uint8_t SENTINEL = 0x5a;
memset(ref_dst, SENTINEL, BUFFER_SIZE);
memset(impl_dst, SENTINEL, 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] != SENTINEL) {
fprintf(stderr,
"Out-of-bounds write detected at index %zu (expected 0x%02x, got "
"0x%02x)!\n",
i, SENTINEL, static_cast<uint8_t>(impl_dst[i]));
print_details();
__builtin_trap();
}
}
return 0;
}