blob: d2cef47734ea918c241d11211aef1b22bc3ddc34 [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_pton implementation.
///
//===----------------------------------------------------------------------===//
#include "src/__support/CPP/scope.h"
#include "src/arpa/inet/inet_pton.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;
// Create a null-terminated copy of the string to parse.
size_t str_size = size - 1;
char *str = new char[str_size + 1];
LIBC_NAMESPACE::cpp::scope_exit delete_str([&] { delete[] str; });
memcpy(str, data + 1, str_size);
str[str_size] = '\0';
// Setup destination buffers.
constexpr size_t BUFFER_SIZE = 64;
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.
int ref_res = ::inet_pton(af, str, ref_dst);
// Call our implementation.
int impl_res = LIBC_NAMESPACE::inet_pton(af, str, impl_dst);
size_t addr_size =
(af == AF_INET) ? sizeof(struct in_addr) : sizeof(struct in6_addr);
auto print_details = [&]() {
fprintf(stderr,
"Details:\n"
" af: %d (%s)\n"
" str: \"%s\"\n"
" ref_res: %d\n"
" impl_res: %d\n",
af, (af == AF_INET) ? "AF_INET" : "AF_INET6", str, ref_res,
impl_res);
if (ref_res == 1) {
fprintf(stderr, " ref_addr: ");
for (size_t i = 0; i < addr_size; ++i)
fprintf(stderr, "%02x", static_cast<uint8_t>(ref_dst[i]));
fprintf(stderr, "\n impl_addr: ");
for (size_t i = 0; i < addr_size; ++i)
fprintf(stderr, "%02x", static_cast<uint8_t>(impl_dst[i]));
fprintf(stderr, "\n");
}
};
// Compare results.
if (ref_res != impl_res) {
fprintf(stderr, "Success/failure mismatch!\n");
print_details();
__builtin_trap();
}
if (ref_res == 1) {
// Both succeeded. Check that parsed addresses match.
if (memcmp(ref_dst, impl_dst, addr_size) != 0) {
fprintf(stderr, "Parsed address mismatch!\n");
print_details();
__builtin_trap();
}
}
// Check for out-of-bounds writes.
for (size_t i = addr_size; i < BUFFER_SIZE; ++i) {
if (static_cast<uint8_t>(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;
}