Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7dc1bc9e18 | ||
|
|
14b3cacbb7 | ||
|
|
00ba6618a8 | ||
|
|
743a43d504 | ||
|
|
8f9d7c3c28 | ||
|
|
f41dcd31f6 | ||
|
|
b05f13c87b |
@@ -23,10 +23,6 @@ Files: tests/thirdparty/fifo_map/*
|
||||
Copyright: 2015-2017 Niels Lohmann
|
||||
License: MIT
|
||||
|
||||
Files: tests/thirdparty/Fuzzer/*
|
||||
Copyright: 2003-2022 LLVM Project.
|
||||
License: Apache-2.0
|
||||
|
||||
Files: tests/thirdparty/imapdl/*
|
||||
Copyright: 2017 Georg Sauthoff <mail@gms.tf>
|
||||
License: GPL-3.0-only
|
||||
|
||||
@@ -20,9 +20,7 @@ cc_library(
|
||||
hdrs = [
|
||||
"include/nlohmann/adl_serializer.hpp",
|
||||
"include/nlohmann/byte_container_with_subtype.hpp",
|
||||
"include/nlohmann/detail/abi_config.hpp",
|
||||
"include/nlohmann/detail/abi_macros.hpp",
|
||||
"include/nlohmann/detail/bit_ops.hpp",
|
||||
"include/nlohmann/detail/conversions/from_json.hpp",
|
||||
"include/nlohmann/detail/conversions/to_chars.hpp",
|
||||
"include/nlohmann/detail/conversions/to_json.hpp",
|
||||
@@ -35,7 +33,6 @@ cc_library(
|
||||
"include/nlohmann/detail/input/number_parse.hpp",
|
||||
"include/nlohmann/detail/input/parser.hpp",
|
||||
"include/nlohmann/detail/input/position_t.hpp",
|
||||
"include/nlohmann/detail/input/pow5_table.hpp",
|
||||
"include/nlohmann/detail/input/string_scan.hpp",
|
||||
"include/nlohmann/detail/iterators/internal_iterator.hpp",
|
||||
"include/nlohmann/detail/iterators/iter_impl.hpp",
|
||||
@@ -66,13 +63,6 @@ cc_library(
|
||||
"include/nlohmann/detail/string_escape.hpp",
|
||||
"include/nlohmann/detail/string_utils.hpp",
|
||||
"include/nlohmann/detail/value_t.hpp",
|
||||
"include/nlohmann/detail/view/builder.hpp",
|
||||
"include/nlohmann/detail/view/document_data.hpp",
|
||||
"include/nlohmann/detail/view/macro_scope.hpp",
|
||||
"include/nlohmann/detail/view/macro_unscope.hpp",
|
||||
"include/nlohmann/detail/view/node.hpp",
|
||||
"include/nlohmann/detail/view/scan.hpp",
|
||||
"include/nlohmann/detail/view/string_ref.hpp",
|
||||
"include/nlohmann/json.hpp",
|
||||
"include/nlohmann/json_fwd.hpp",
|
||||
"include/nlohmann/ordered_map.hpp",
|
||||
|
||||
@@ -1395,7 +1395,6 @@ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR I
|
||||
- The class contains a slightly modified version of the Grisu2 algorithm from Florian Loitsch which is licensed under the [MIT License](https://opensource.org/licenses/MIT) (see above). Copyright © 2009 [Florian Loitsch](https://florian.loitsch.com/)
|
||||
- The class contains a copy of [Hedley](https://nemequ.github.io/hedley/) from Evan Nemerson which is licensed as [CC0-1.0](https://creativecommons.org/publicdomain/zero/1.0/).
|
||||
- The class contains parts of [Google Abseil](https://github.com/abseil/abseil-cpp) which is licensed under the [Apache 2.0 License](https://opensource.org/licenses/Apache-2.0).
|
||||
- The class contains an adapted version of the Eisel-Lemire algorithm and its table of powers of five from [fast_float](https://github.com/fastfloat/fast_float) by Daniel Lemire and contributors, which is available under the [MIT License](https://opensource.org/licenses/MIT) (used here), the Apache 2.0 License, and the Boost Software License. Copyright © 2021 The fast_float authors
|
||||
|
||||
<img align="right" src="https://git.fsfe.org/reuse/reuse-ci/raw/branch/master/reuse-horizontal.png" alt="REUSE Software">
|
||||
|
||||
|
||||
@@ -19,5 +19,3 @@ The class contains the UTF-8 Decoder from Bjoern Hoehrmann which is licensed und
|
||||
The class contains a slightly modified version of the Grisu2 algorithm from Florian Loitsch which is licensed under the [MIT License](https://opensource.org/licenses/MIT) (see above). Copyright © 2009 [Florian Loitsch](https://florian.loitsch.com/)
|
||||
|
||||
The class contains a copy of [Hedley](https://nemequ.github.io/hedley/) from Evan Nemerson which is licensed as [CC0-1.0](https://creativecommons.org/publicdomain/zero/1.0/).
|
||||
|
||||
The class contains an adapted version of the Eisel-Lemire algorithm and its table of powers of five from [fast_float](https://github.com/fastfloat/fast_float) by Daniel Lemire and contributors, which is available under the [MIT License](https://opensource.org/licenses/MIT) (used here), the Apache 2.0 License, and the Boost Software License. Copyright © 2021 The fast_float authors
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <nlohmann/detail/abi_macros.hpp>
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
namespace detail
|
||||
{
|
||||
|
||||
/*!
|
||||
@brief the configuration macros that change the library's behavior
|
||||
|
||||
json.hpp undefines these macros at its end (see macro_unscope.hpp), so code
|
||||
that builds on the library after it (json_view.hpp) reads them here. Like the
|
||||
macros, they are part of the ABI namespace, so they always match the
|
||||
basic_json they are used with.
|
||||
*/
|
||||
struct abi_config
|
||||
{
|
||||
/// JSON_STRICT_NUL_HANDLING: a null byte is an error, not the end of input
|
||||
static constexpr bool strict_nul_handling = JSON_STRICT_NUL_HANDLING != 0;
|
||||
/// JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
|
||||
static constexpr bool legacy_discarded_value_comparison = JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON != 0;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
@@ -1,105 +0,0 @@
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint> // uint64_t
|
||||
|
||||
#include <nlohmann/detail/abi_macros.hpp>
|
||||
|
||||
// Portable bit-level helpers for the number and string scanners. They use
|
||||
// compiler builtins where available and plain C++ otherwise, so they need no
|
||||
// platform headers and work regardless of byte order.
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
namespace detail
|
||||
{
|
||||
|
||||
/// number of leading zero bits of x (x != 0)
|
||||
inline int count_leading_zeros(std::uint64_t x) noexcept
|
||||
{
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
return __builtin_clzll(x);
|
||||
#else
|
||||
int n = 0;
|
||||
for (int shift = 32; shift != 0; shift >>= 1)
|
||||
{
|
||||
if ((x >> (64 - shift)) == 0)
|
||||
{
|
||||
n += shift;
|
||||
x <<= shift;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// number of trailing zero bits of x (x != 0)
|
||||
inline int count_trailing_zeros(std::uint64_t x) noexcept
|
||||
{
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
return __builtin_ctzll(x);
|
||||
#else
|
||||
int n = 0;
|
||||
for (int shift = 32; shift != 0; shift >>= 1)
|
||||
{
|
||||
if ((x << (64 - shift)) == 0)
|
||||
{
|
||||
n += shift;
|
||||
x >>= shift;
|
||||
}
|
||||
}
|
||||
return n;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// the 128-bit product of two 64-bit numbers
|
||||
struct uint128_parts
|
||||
{
|
||||
std::uint64_t low;
|
||||
std::uint64_t high;
|
||||
};
|
||||
|
||||
inline uint128_parts full_multiplication(std::uint64_t a, std::uint64_t b) noexcept
|
||||
{
|
||||
#if defined(__SIZEOF_INT128__)
|
||||
__extension__ using uint128 = unsigned __int128;
|
||||
const uint128 r = static_cast<uint128>(a) * b;
|
||||
return {static_cast<std::uint64_t>(r), static_cast<std::uint64_t>(r >> 64u)};
|
||||
#else
|
||||
const std::uint64_t a_lo = a & 0xFFFFFFFFu;
|
||||
const std::uint64_t a_hi = a >> 32u;
|
||||
const std::uint64_t b_lo = b & 0xFFFFFFFFu;
|
||||
const std::uint64_t b_hi = b >> 32u;
|
||||
const std::uint64_t lo_lo = a_lo * b_lo;
|
||||
const std::uint64_t hi_lo = a_hi * b_lo;
|
||||
const std::uint64_t lo_hi = a_lo * b_hi;
|
||||
const std::uint64_t hi_hi = a_hi * b_hi;
|
||||
const std::uint64_t cross = (lo_lo >> 32u) + (hi_lo & 0xFFFFFFFFu) + lo_hi;
|
||||
return {(cross << 32u) | (lo_lo & 0xFFFFFFFFu), (hi_lo >> 32u) + (cross >> 32u) + hi_hi};
|
||||
#endif
|
||||
}
|
||||
|
||||
/// eight bytes as a little-endian word (compilers fold this into one load on
|
||||
/// little-endian targets)
|
||||
inline std::uint64_t read_eight_bytes(const unsigned char* b) noexcept
|
||||
{
|
||||
return static_cast<std::uint64_t>(b[0]) | (static_cast<std::uint64_t>(b[1]) << 8u)
|
||||
| (static_cast<std::uint64_t>(b[2]) << 16u) | (static_cast<std::uint64_t>(b[3]) << 24u)
|
||||
| (static_cast<std::uint64_t>(b[4]) << 32u) | (static_cast<std::uint64_t>(b[5]) << 40u)
|
||||
| (static_cast<std::uint64_t>(b[6]) << 48u) | (static_cast<std::uint64_t>(b[7]) << 56u);
|
||||
}
|
||||
|
||||
/// eight bytes as a little-endian word
|
||||
inline std::uint64_t read_eight_bytes(const char* p) noexcept
|
||||
{
|
||||
return read_eight_bytes(reinterpret_cast<const unsigned char*>(p)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
@@ -9,8 +9,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <array> // array
|
||||
#include <clocale> // localeconv
|
||||
#include <cstddef> // size_t
|
||||
#include <cstdio> // snprintf
|
||||
#include <cstdlib> // strtof, strtod, strtold, strtoll, strtoull
|
||||
#include <initializer_list> // initializer_list
|
||||
#include <string> // char_traits, string
|
||||
#include <utility> // move
|
||||
@@ -216,46 +218,20 @@ class lexer : public lexer_base<BasicJsonType>
|
||||
|
||||
private:
|
||||
/////////////////////
|
||||
// scan functions
|
||||
// locales
|
||||
/////////////////////
|
||||
|
||||
/// contiguous input: try to decode the 4 hex digits following `\u`
|
||||
/// directly from the input buffer via hex_codepoint(), instead of 4 calls
|
||||
/// to get(). On success, advances the adapter and the position counters
|
||||
/// exactly as those 4 get() calls would (a hex digit is never '\n', so
|
||||
/// only the flat counters move) and leaves @a current holding the last of
|
||||
/// the 4 digits, just as the last such get() would; the codepoint is
|
||||
/// written to @a out. Makes no state change and returns false - for a
|
||||
/// pending unget, fewer than 4 remaining bytes, or any of the 4 bytes not
|
||||
/// being a hex digit - so the caller falls back unchanged to the
|
||||
/// per-character loop, which then reports the same diagnostic (stopping
|
||||
/// at the first invalid digit) as before this optimization.
|
||||
bool get_codepoint_bulk(std::true_type /*bulk*/, int& out)
|
||||
/// return the decimal point of the current locale
|
||||
static char get_decimal_point() noexcept
|
||||
{
|
||||
if (next_unget || ia.bulk_remaining() < 4)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
const char_type* const raw = ia.bulk_data();
|
||||
const int codepoint = hex_codepoint(reinterpret_cast<const unsigned char*>(raw));
|
||||
if (codepoint < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
ia.bulk_skip(4);
|
||||
// a hex digit is never a newline, so only the flat counters advance
|
||||
position.chars_read_total += 4;
|
||||
position.chars_read_current_line += 4;
|
||||
current = char_traits<char_type>::to_int_type(raw[3]);
|
||||
out = codepoint;
|
||||
return true;
|
||||
const auto* loc = localeconv();
|
||||
JSON_ASSERT(loc != nullptr);
|
||||
return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point);
|
||||
}
|
||||
|
||||
/// streaming input: no bulk fast path
|
||||
bool get_codepoint_bulk(std::false_type /*bulk*/, int& /*out*/) const noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
/////////////////////
|
||||
// scan functions
|
||||
/////////////////////
|
||||
|
||||
/*!
|
||||
@brief get codepoint from 4 hex characters following `\u`
|
||||
@@ -276,14 +252,6 @@ class lexer : public lexer_base<BasicJsonType>
|
||||
{
|
||||
// this function only makes sense after reading `\u`
|
||||
JSON_ASSERT(current == 'u');
|
||||
|
||||
// contiguous input: decode all 4 hex digits directly from the buffer
|
||||
int fast_codepoint = 0;
|
||||
if (get_codepoint_bulk(std::integral_constant<bool, bulk_scan> {}, fast_codepoint))
|
||||
{
|
||||
return fast_codepoint;
|
||||
}
|
||||
|
||||
int codepoint = 0;
|
||||
|
||||
const auto factors = { 12u, 8u, 4u, 0u };
|
||||
@@ -1068,6 +1036,24 @@ class lexer : public lexer_base<BasicJsonType>
|
||||
}
|
||||
}
|
||||
|
||||
JSON_HEDLEY_NON_NULL(2)
|
||||
static void strtof(float& f, const char* str, char** endptr) noexcept
|
||||
{
|
||||
f = std::strtof(str, endptr);
|
||||
}
|
||||
|
||||
JSON_HEDLEY_NON_NULL(2)
|
||||
static void strtof(double& f, const char* str, char** endptr) noexcept
|
||||
{
|
||||
f = std::strtod(str, endptr);
|
||||
}
|
||||
|
||||
JSON_HEDLEY_NON_NULL(2)
|
||||
static void strtof(long double& f, const char* str, char** endptr) noexcept
|
||||
{
|
||||
f = std::strtold(str, endptr);
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief scan a number literal
|
||||
|
||||
@@ -1107,7 +1093,7 @@ class lexer : public lexer_base<BasicJsonType>
|
||||
@note The scanner is independent of the current locale: token_buffer
|
||||
always holds `.`. Only the std::strtod fallback of convert_number()
|
||||
depends on the locale, and it looks up the decimal point right
|
||||
before converting (see detail::convert_float_locale_aware()).
|
||||
before converting (see convert_float_locale_aware()).
|
||||
*/
|
||||
token_type scan_number() // lgtm [cpp/use-of-goto] `goto` is used in this function to implement the number-parsing state machine described above. By design, any finite input will eventually reach the "done" state or return token_type::parse_error. In each intermediate state, 1 byte of the input is appended to the token_buffer vector, and only the already initialized variables token_buffer, number_type, and error_message are manipulated.
|
||||
{
|
||||
@@ -1438,6 +1424,59 @@ scan_number_done:
|
||||
return token_type::uninitialized;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief check whether Clinger's fast path can still succeed for this token
|
||||
|
||||
parse_float_fast() needs a significand below 2^53. A mantissa with 17 or
|
||||
more significant digits is at least 10^16 and therefore always exceeds it,
|
||||
so calling the fast path would walk the token one extra time only to
|
||||
decline before strtod has to run anyway.
|
||||
|
||||
Significant digits are the mantissa's digits from the first nonzero one on;
|
||||
the sign, the decimal point, leading zeros, and the exponent do not count.
|
||||
The answer is derived from indices - the digits are not scanned again - so
|
||||
this stays off the hot path of the number scanners.
|
||||
|
||||
@param[in] mantissa_end offset just past the last mantissa byte in
|
||||
token_buffer
|
||||
@return false if parse_float_fast() is guaranteed to decline
|
||||
*/
|
||||
bool mantissa_fits_clinger(std::size_t mantissa_end) const
|
||||
{
|
||||
// 10^16 already exceeds 2^53, so 17 digits can never fit
|
||||
constexpr std::size_t limit = 17;
|
||||
|
||||
const std::size_t neg = (!token_buffer.empty() && token_buffer[0] == '-') ? 1u : 0u;
|
||||
const std::size_t has_dot = (decimal_point_position != std::string::npos) ? 1u : 0u;
|
||||
// the JSON grammar restricts the integer part to "0" or [1-9][0-9]*, so
|
||||
// a leading zero can only be a lone "0", which is not significant
|
||||
const std::size_t lead_zero = (token_buffer[neg] == '0') ? 1u : 0u;
|
||||
JSON_ASSERT(mantissa_end >= neg + has_dot + lead_zero);
|
||||
std::size_t digits = mantissa_end - neg - has_dot - lead_zero;
|
||||
|
||||
if (JSON_HEDLEY_LIKELY(digits < limit))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Only a number below 1 can carry further insignificant zeros, and only
|
||||
// while the count stays at the limit does removing them change the
|
||||
// answer - so this loop is skipped for all but a few tokens. The
|
||||
// fraction is located through decimal_point_position rather than by
|
||||
// searching '.'.
|
||||
if (lead_zero != 0)
|
||||
{
|
||||
JSON_ASSERT(has_dot != 0); // an integer "0" cannot reach the limit
|
||||
for (std::size_t i = decimal_point_position + 1;
|
||||
digits >= limit && i < mantissa_end && token_buffer[i] == '0'; ++i)
|
||||
{
|
||||
--digits;
|
||||
}
|
||||
}
|
||||
|
||||
return digits < limit;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief convert the number text in token_buffer to its value and token type
|
||||
|
||||
@@ -1451,7 +1490,7 @@ scan_number_done:
|
||||
token_buffer (the index of 'e'/'E', or
|
||||
token_buffer.size() when there is no exponent);
|
||||
used to skip Clinger's fast path when it cannot
|
||||
possibly succeed - see detail::mantissa_fits_clinger()
|
||||
possibly succeed - see mantissa_fits_clinger()
|
||||
*/
|
||||
token_type convert_number(token_type number_type, std::size_t mantissa_end)
|
||||
{
|
||||
@@ -1524,15 +1563,77 @@ scan_number_done:
|
||||
// (Eisel-Lemire, locale-independent, correctly rounded) when available;
|
||||
// otherwise the exact Clinger fast path (double only); otherwise the
|
||||
// locale-aware strtof/strtod/strtold.
|
||||
if (convert_float_fast(num_begin, num_end, decimal_point_position, mantissa_end, value_float))
|
||||
if (parse_float_from_chars(num_begin, num_end, value_float))
|
||||
{
|
||||
return token_type::value_float;
|
||||
}
|
||||
// Skipping a fast path that cannot succeed is lossless and saves a full
|
||||
// extra pass over the token's bytes, which otherwise shows up on
|
||||
// high-precision inputs such as canada.json
|
||||
if (mantissa_fits_clinger(mantissa_end)
|
||||
&& parse_float_fast(num_begin, num_end, value_float))
|
||||
{
|
||||
return token_type::value_float;
|
||||
}
|
||||
|
||||
convert_float_locale_aware(token_buffer, decimal_point_position, value_float);
|
||||
convert_float_locale_aware();
|
||||
return token_type::value_float;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief convert the float in token_buffer with strtof/strtod/strtold
|
||||
|
||||
These functions expect the decimal point of the *current* locale, so it is
|
||||
looked up right before the conversion instead of once when the lexer is
|
||||
constructed: a locale change in between (by a parser callback, a SAX
|
||||
handler, or another thread) must not truncate the value (#5198). The
|
||||
token has been validated before, so if the conversion stops early and the
|
||||
decimal point changed in the meantime, the locale changed between the
|
||||
lookup and the call, and the conversion is repeated with the new decimal
|
||||
point. If the decimal point did not change, a retry cannot succeed: the
|
||||
locale's decimal point is not a single character (e.g., the two-byte
|
||||
U+066B of ar_EG.UTF-8 or fa_IR.UTF-8) and cannot be substituted in place.
|
||||
The value strtod parsed up to that point is kept, as before this change.
|
||||
|
||||
Note that changing the locale in another thread *while* strtod runs is
|
||||
undefined behavior of the C library, which this function cannot prevent.
|
||||
*/
|
||||
void convert_float_locale_aware()
|
||||
{
|
||||
const bool has_dot = decimal_point_position != std::string::npos;
|
||||
char decimal_point = get_decimal_point();
|
||||
for (;;)
|
||||
{
|
||||
const bool substitute = has_dot && decimal_point != '.';
|
||||
if (substitute)
|
||||
{
|
||||
token_buffer[decimal_point_position] = static_cast<typename string_t::value_type>(decimal_point);
|
||||
}
|
||||
|
||||
char* endptr = nullptr; // NOLINT(misc-const-correctness,cppcoreguidelines-pro-type-vararg,hicpp-vararg)
|
||||
strtof(value_float, token_buffer.data(), &endptr);
|
||||
|
||||
if (substitute)
|
||||
{
|
||||
// get_string() hands the token to the SAX interface with '.'
|
||||
token_buffer[decimal_point_position] = '.';
|
||||
}
|
||||
|
||||
if (JSON_HEDLEY_LIKELY(endptr == token_buffer.data() + token_buffer.size()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// retry only if the locale changed; otherwise, this would loop forever
|
||||
const char current_decimal_point = get_decimal_point();
|
||||
if (current_decimal_point == decimal_point)
|
||||
{
|
||||
return;
|
||||
}
|
||||
decimal_point = current_decimal_point;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief contiguous fast path for scanning a number
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2021 The fast_float authors <https://github.com/fastfloat/fast_float>
|
||||
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
@@ -11,16 +10,10 @@
|
||||
|
||||
#include <array> // array
|
||||
#include <cfloat> // FLT_EVAL_METHOD
|
||||
#include <clocale> // localeconv
|
||||
#include <cstddef> // size_t
|
||||
#include <cstdint> // int64_t, uint64_t
|
||||
#include <cstdlib> // strtof, strtod, strtold
|
||||
#include <cstring> // memcpy
|
||||
#include <limits> // numeric_limits
|
||||
#include <string> // string
|
||||
|
||||
#include <nlohmann/detail/bit_ops.hpp>
|
||||
#include <nlohmann/detail/input/pow5_table.hpp>
|
||||
#include <nlohmann/detail/macro_scope.hpp>
|
||||
|
||||
// std::from_chars lives in <charconv>, but being in C++17 mode does not
|
||||
@@ -36,9 +29,8 @@
|
||||
|
||||
// This file contains the value-conversion helpers used by the lexer to turn an
|
||||
// already-validated number token into a value, without the locale/errno
|
||||
// overhead of std::strtoull/std::strtod where possible. They are free functions
|
||||
// so the lexer stays focused on scanning (see lexer::convert_number()) and so
|
||||
// that other parsers of JSON text can convert tokens exactly like it does.
|
||||
// overhead of std::strtoull/std::strtod. They are free functions so the lexer
|
||||
// stays focused on scanning; see lexer::convert_number().
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
namespace detail
|
||||
@@ -301,415 +293,5 @@ bool parse_float_from_chars(const char* first, const char* last, FloatType& out)
|
||||
#endif
|
||||
}
|
||||
|
||||
/// whether the eight bytes of @a v (see read_eight_bytes()) are ASCII digits
|
||||
/// (after fast_float's is_made_of_eight_digits_fast)
|
||||
inline bool is_eight_digits(std::uint64_t v) noexcept
|
||||
{
|
||||
return ((v & 0xF0F0F0F0F0F0F0F0u) | (((v + 0x0606060606060606u) & 0xF0F0F0F0F0F0F0F0u) >> 4u)) == 0x3333333333333333u;
|
||||
}
|
||||
|
||||
/// the value of the eight ASCII digits in @a v (see read_eight_bytes()), three
|
||||
/// multiplications instead of eight (after simdjson and fast_float)
|
||||
inline std::uint32_t parse_eight_digits(std::uint64_t v) noexcept
|
||||
{
|
||||
v = ((v & 0x0F0F0F0F0F0F0F0Fu) * 2561u) >> 8u;
|
||||
v = ((v & 0x00FF00FF00FF00FFu) * 6553601u) >> 16u;
|
||||
return static_cast<std::uint32_t>(((v & 0x0000FFFF0000FFFFu) * 42949672960001u) >> 32u);
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief the double nearest to w * 10^q (Eisel-Lemire)
|
||||
|
||||
The algorithm of Daniel Lemire, "Number Parsing at a Gigabyte per Second"
|
||||
(Software: Practice and Experience, 2021), after fast_float's compute_float
|
||||
(used under the MIT license). With a 128-bit approximation of 5^q, the product
|
||||
is always sufficient to round correctly for w with at most 19 digits (Noble
|
||||
Mushtak and Daniel Lemire, "Fast number parsing without fallback", Software:
|
||||
Practice and Experience, 2023). Only integer arithmetic is used, so the result
|
||||
does not depend on the floating-point environment.
|
||||
|
||||
@param[in] q decimal exponent
|
||||
@param[in] w significand, w != 0
|
||||
@return the IEEE-754 bits of the positive result (0 for underflow, infinity
|
||||
for overflow)
|
||||
*/
|
||||
inline std::uint64_t eisel_lemire(std::int64_t q, std::uint64_t w) noexcept
|
||||
{
|
||||
constexpr int mantissa_bits = 52;
|
||||
constexpr std::uint64_t infinity = std::uint64_t{0x7FF} << mantissa_bits;
|
||||
if (q < pow5_128_smallest_power)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (q > pow5_128_largest_power)
|
||||
{
|
||||
return infinity;
|
||||
}
|
||||
|
||||
const int lz = count_leading_zeros(w);
|
||||
w <<= static_cast<unsigned>(lz);
|
||||
const auto index = static_cast<std::size_t>(2 * (q - pow5_128_smallest_power));
|
||||
uint128_parts product = full_multiplication(w, pow5_128()[index]);
|
||||
constexpr std::uint64_t precision_mask = 0xFFFFFFFFFFFFFFFFu >> (mantissa_bits + 3);
|
||||
if ((product.high & precision_mask) == precision_mask)
|
||||
{
|
||||
// the lower bits may carry into the result: use the next 64 bits of 5^q
|
||||
const uint128_parts second = full_multiplication(w, pow5_128()[index + 1]);
|
||||
product.low += second.high;
|
||||
if (second.high > product.low)
|
||||
{
|
||||
++product.high;
|
||||
}
|
||||
}
|
||||
|
||||
const auto upperbit = static_cast<int>(product.high >> 63u);
|
||||
const int shift = upperbit + 64 - mantissa_bits - 3;
|
||||
std::uint64_t mantissa = product.high >> static_cast<unsigned>(shift);
|
||||
// floor(log2(10^q)) + 63 + 1023, with log2(10) ~ 217706 / 2^16
|
||||
std::int64_t power2 = (((152170 + 65536) * q) >> 16) + 63 + upperbit - lz + 1023;
|
||||
|
||||
if (power2 <= 0) // subnormal
|
||||
{
|
||||
if (-power2 + 1 >= 64)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
mantissa >>= static_cast<unsigned>(-power2 + 1);
|
||||
mantissa += (mantissa & 1u);
|
||||
mantissa >>= 1u;
|
||||
// rounding up may produce the smallest normal number
|
||||
power2 = (mantissa < (std::uint64_t{1} << mantissa_bits)) ? 0 : 1;
|
||||
return mantissa | (static_cast<std::uint64_t>(power2) << mantissa_bits);
|
||||
}
|
||||
|
||||
// a value exactly between two doubles rounds to even; this can only
|
||||
// happen for small |q|, where 5^q is exact
|
||||
if (product.low <= 1 && q >= -4 && q <= 23 && (mantissa & 3u) == 1
|
||||
&& (mantissa << static_cast<unsigned>(shift)) == product.high)
|
||||
{
|
||||
mantissa &= ~std::uint64_t{1};
|
||||
}
|
||||
mantissa += (mantissa & 1u);
|
||||
mantissa >>= 1u;
|
||||
if (mantissa >= (std::uint64_t{2} << mantissa_bits))
|
||||
{
|
||||
mantissa = std::uint64_t{1} << mantissa_bits;
|
||||
++power2;
|
||||
}
|
||||
mantissa &= ~(std::uint64_t{1} << mantissa_bits);
|
||||
if (power2 >= 0x7FF)
|
||||
{
|
||||
return infinity;
|
||||
}
|
||||
return mantissa | (static_cast<std::uint64_t>(power2) << mantissa_bits);
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief parse a validated float token with the Eisel-Lemire algorithm
|
||||
|
||||
The significand is accumulated eight digits at a time where possible. A token
|
||||
with more than 19 significant digits is truncated to w; the value then lies
|
||||
in [w, w + 1) * 10^q, and it is only returned if both ends round to the same
|
||||
double, which covers all but a few such tokens.
|
||||
|
||||
@param[in] first pointer to the first character of the token
|
||||
@param[in] last pointer past the last character
|
||||
@param[out] out the correctly rounded value on success (±infinity if it
|
||||
overflows, like strtod)
|
||||
@return true on success; false if strtod must decide
|
||||
*/
|
||||
inline bool parse_float_eisel_lemire(const char* first, const char* last, double& out) noexcept
|
||||
{
|
||||
const char* p = first;
|
||||
const bool negative = (p != last && *p == '-');
|
||||
if (negative)
|
||||
{
|
||||
++p;
|
||||
}
|
||||
|
||||
std::uint64_t w = 0;
|
||||
int digits = 0; // significant digits in w
|
||||
std::int64_t exponent = 0;
|
||||
bool truncated = false;
|
||||
bool in_fraction = false;
|
||||
for (;;)
|
||||
{
|
||||
// eight digits at a time, as long as they fit into w
|
||||
while (w != 0 && digits <= 19 - 8 && last - p >= 8)
|
||||
{
|
||||
const std::uint64_t v = read_eight_bytes(p);
|
||||
if (!is_eight_digits(v))
|
||||
{
|
||||
break;
|
||||
}
|
||||
w = (w * 100000000u) + parse_eight_digits(v);
|
||||
digits += 8;
|
||||
exponent -= in_fraction ? 8 : 0;
|
||||
p += 8;
|
||||
}
|
||||
if (p == last)
|
||||
{
|
||||
break;
|
||||
}
|
||||
const char c = *p;
|
||||
if (c >= '0' && c <= '9')
|
||||
{
|
||||
if (w == 0 && c == '0')
|
||||
{
|
||||
// leading zeros are not significant, but scale a fraction
|
||||
exponent -= in_fraction ? 1 : 0;
|
||||
}
|
||||
else if (digits < 19)
|
||||
{
|
||||
w = (w * 10u) + static_cast<std::uint64_t>(c - '0');
|
||||
++digits;
|
||||
exponent -= in_fraction ? 1 : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// dropped: the value lies between w and w + 1 (in units of
|
||||
// the last kept digit) unless all dropped digits are zero
|
||||
truncated = truncated || c != '0';
|
||||
exponent += in_fraction ? 0 : 1;
|
||||
}
|
||||
++p;
|
||||
}
|
||||
else if (c == '.')
|
||||
{
|
||||
in_fraction = true;
|
||||
++p;
|
||||
}
|
||||
else
|
||||
{
|
||||
break; // 'e' or 'E'
|
||||
}
|
||||
}
|
||||
|
||||
if (p != last)
|
||||
{
|
||||
++p; // 'e' or 'E'
|
||||
bool exp_negative = false;
|
||||
if (p != last && (*p == '-' || *p == '+'))
|
||||
{
|
||||
exp_negative = (*p == '-');
|
||||
++p;
|
||||
}
|
||||
std::int64_t exp_value = 0;
|
||||
for (; p != last; ++p)
|
||||
{
|
||||
// saturate: any exponent beyond this under- or overflows anyway
|
||||
if (exp_value < 100000)
|
||||
{
|
||||
exp_value = (exp_value * 10) + (*p - '0');
|
||||
}
|
||||
}
|
||||
exponent += exp_negative ? -exp_value : exp_value;
|
||||
}
|
||||
|
||||
std::uint64_t bits = 0;
|
||||
if (w != 0)
|
||||
{
|
||||
bits = eisel_lemire(exponent, w);
|
||||
if (truncated && (w + 1 == 0 || eisel_lemire(exponent, w + 1) != bits))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bits |= negative ? (std::uint64_t{1} << 63u) : 0u;
|
||||
static_assert(sizeof(double) == sizeof(std::uint64_t), "double must have 64 bits");
|
||||
std::memcpy(&out, &bits, sizeof(out));
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Eisel-Lemire is only implemented for `double`
|
||||
template<typename FloatType>
|
||||
bool parse_float_eisel_lemire(const char* /*first*/, const char* /*last*/, FloatType& /*out*/) noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief check whether Clinger's fast path can still succeed for a float token
|
||||
|
||||
parse_float_fast() needs a significand below 2^53. A mantissa with 17 or
|
||||
more significant digits is at least 10^16 and therefore always exceeds it,
|
||||
so calling the fast path would walk the token one extra time only to
|
||||
decline before strtod has to run anyway.
|
||||
|
||||
Significant digits are the mantissa's digits from the first nonzero one on;
|
||||
the sign, the decimal point, leading zeros, and the exponent do not count.
|
||||
The answer is derived from indices - the digits are not scanned again - so
|
||||
this stays off the hot path of the number scanners.
|
||||
|
||||
@param[in] token the validated number token ('.' as decimal point)
|
||||
@param[in] decimal_point_position index of the '.' in @a token, or
|
||||
std::string::npos if there is none
|
||||
@param[in] mantissa_end offset just past the last mantissa byte
|
||||
@return false if parse_float_fast() is guaranteed to decline
|
||||
*/
|
||||
inline bool mantissa_fits_clinger(const char* token, std::size_t decimal_point_position, std::size_t mantissa_end) noexcept
|
||||
{
|
||||
// 10^16 already exceeds 2^53, so 17 digits can never fit
|
||||
constexpr std::size_t limit = 17;
|
||||
|
||||
const std::size_t neg = (token[0] == '-') ? 1u : 0u;
|
||||
const std::size_t has_dot = (decimal_point_position != std::string::npos) ? 1u : 0u;
|
||||
// the JSON grammar restricts the integer part to "0" or [1-9][0-9]*, so
|
||||
// a leading zero can only be a lone "0", which is not significant
|
||||
const std::size_t lead_zero = (token[neg] == '0') ? 1u : 0u;
|
||||
JSON_ASSERT(mantissa_end >= neg + has_dot + lead_zero);
|
||||
std::size_t digits = mantissa_end - neg - has_dot - lead_zero;
|
||||
|
||||
if (JSON_HEDLEY_LIKELY(digits < limit))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Only a number below 1 can carry further insignificant zeros, and only
|
||||
// while the count stays at the limit does removing them change the
|
||||
// answer - so this loop is skipped for all but a few tokens. The
|
||||
// fraction is located through decimal_point_position rather than by
|
||||
// searching '.'.
|
||||
if (lead_zero != 0)
|
||||
{
|
||||
JSON_ASSERT(has_dot != 0); // an integer "0" cannot reach the limit
|
||||
for (std::size_t i = decimal_point_position + 1;
|
||||
digits >= limit && i < mantissa_end && token[i] == '0'; ++i)
|
||||
{
|
||||
--digits;
|
||||
}
|
||||
}
|
||||
|
||||
return digits < limit;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief convert a validated float token without the C library, if possible
|
||||
|
||||
Tries std::from_chars (when available), Clinger's exact fast path (double
|
||||
only, skipped when it cannot succeed), and the Eisel-Lemire algorithm (double
|
||||
only).
|
||||
|
||||
@param[in] first pointer to the first character of the token
|
||||
@param[in] last pointer past the last character
|
||||
@param[in] decimal_point_position index of the '.' in the token, or
|
||||
std::string::npos if there is none
|
||||
@param[in] mantissa_end offset just past the last mantissa byte (the
|
||||
index of 'e'/'E', or the token length)
|
||||
@param[out] value the converted value on success
|
||||
@return true if the value was converted; false if convert_float_locale_aware()
|
||||
must convert it
|
||||
*/
|
||||
template<typename FloatType>
|
||||
bool convert_float_fast(const char* first, const char* last, std::size_t decimal_point_position,
|
||||
std::size_t mantissa_end, FloatType& value) noexcept
|
||||
{
|
||||
if (parse_float_from_chars(first, last, value))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// Skipping a fast path that cannot succeed is lossless and saves a full
|
||||
// extra pass over the token's bytes, which otherwise shows up on
|
||||
// high-precision inputs such as canada.json
|
||||
if (mantissa_fits_clinger(first, decimal_point_position, mantissa_end)
|
||||
&& parse_float_fast(first, last, value))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return parse_float_eisel_lemire(first, last, value);
|
||||
}
|
||||
|
||||
/// std::strtof, std::strtod, or std::strtold, chosen by the type of @a f
|
||||
JSON_HEDLEY_NON_NULL(2)
|
||||
inline void strtof_by_type(float& f, const char* str, char** endptr) noexcept
|
||||
{
|
||||
f = std::strtof(str, endptr);
|
||||
}
|
||||
|
||||
/// std::strtof, std::strtod, or std::strtold, chosen by the type of @a f
|
||||
JSON_HEDLEY_NON_NULL(2)
|
||||
inline void strtof_by_type(double& f, const char* str, char** endptr) noexcept
|
||||
{
|
||||
f = std::strtod(str, endptr);
|
||||
}
|
||||
|
||||
/// std::strtof, std::strtod, or std::strtold, chosen by the type of @a f
|
||||
JSON_HEDLEY_NON_NULL(2)
|
||||
inline void strtof_by_type(long double& f, const char* str, char** endptr) noexcept
|
||||
{
|
||||
f = std::strtold(str, endptr);
|
||||
}
|
||||
|
||||
/// return the decimal point of the current locale
|
||||
inline char get_decimal_point() noexcept
|
||||
{
|
||||
const auto* loc = localeconv();
|
||||
JSON_ASSERT(loc != nullptr);
|
||||
return (loc->decimal_point == nullptr) ? '.' : *(loc->decimal_point);
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief convert a validated float token with strtof/strtod/strtold
|
||||
|
||||
These functions expect the decimal point of the *current* locale, so it is
|
||||
looked up right before the conversion instead of once when the lexer is
|
||||
constructed: a locale change in between (by a parser callback, a SAX
|
||||
handler, or another thread) must not truncate the value (#5198). The
|
||||
token has been validated before, so if the conversion stops early and the
|
||||
decimal point changed in the meantime, the locale changed between the
|
||||
lookup and the call, and the conversion is repeated with the new decimal
|
||||
point. If the decimal point did not change, a retry cannot succeed: the
|
||||
locale's decimal point is not a single character (e.g., the two-byte
|
||||
U+066B of ar_EG.UTF-8 or fa_IR.UTF-8) and cannot be substituted in place.
|
||||
The value strtod parsed up to that point is kept, as before this change.
|
||||
|
||||
Note that changing the locale in another thread *while* strtod runs is
|
||||
undefined behavior of the C library, which this function cannot prevent.
|
||||
|
||||
@param[in,out] token the token with '.' as decimal point; its
|
||||
decimal point is replaced during the
|
||||
conversion and restored afterwards
|
||||
(data() must be NUL-terminated)
|
||||
@param[in] decimal_point_position index of the '.' in @a token, or
|
||||
std::string::npos if there is none
|
||||
@param[out] value the converted value
|
||||
*/
|
||||
template<typename StringType, typename FloatType>
|
||||
void convert_float_locale_aware(StringType& token, std::size_t decimal_point_position, FloatType& value)
|
||||
{
|
||||
const bool has_dot = decimal_point_position != std::string::npos;
|
||||
char decimal_point = get_decimal_point();
|
||||
for (;;)
|
||||
{
|
||||
const bool substitute = has_dot && decimal_point != '.';
|
||||
if (substitute)
|
||||
{
|
||||
token[decimal_point_position] = static_cast<typename StringType::value_type>(decimal_point);
|
||||
}
|
||||
|
||||
char* endptr = nullptr; // NOLINT(misc-const-correctness,cppcoreguidelines-pro-type-vararg,hicpp-vararg)
|
||||
strtof_by_type(value, token.data(), &endptr);
|
||||
|
||||
if (substitute)
|
||||
{
|
||||
// the caller hands the token on (e.g. to the SAX interface) with '.'
|
||||
token[decimal_point_position] = '.';
|
||||
}
|
||||
|
||||
if (JSON_HEDLEY_LIKELY(endptr == token.data() + token.size()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// retry only if the locale changed; otherwise, this would loop forever
|
||||
const char current_decimal_point = get_decimal_point();
|
||||
if (current_decimal_point == decimal_point)
|
||||
{
|
||||
return;
|
||||
}
|
||||
decimal_point = current_decimal_point;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
|
||||
@@ -1,371 +0,0 @@
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2021 The fast_float authors <https://github.com/fastfloat/fast_float>
|
||||
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array> // array
|
||||
#include <cstdint> // int64_t, uint64_t
|
||||
|
||||
#include <nlohmann/detail/abi_macros.hpp>
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
namespace detail
|
||||
{
|
||||
|
||||
/// the range of decimal exponents covered by pow5_128()
|
||||
constexpr std::int64_t pow5_128_smallest_power = -342;
|
||||
constexpr std::int64_t pow5_128_largest_power = 308;
|
||||
|
||||
/*!
|
||||
@brief 128-bit approximations of 5^q for q in [-342, 308]
|
||||
|
||||
Entry q (at index 2 * (q + 342)) holds the most significant 128 bits of 5^q,
|
||||
normalized so that the highest bit is set: for q >= 0 the truncated value, for
|
||||
q < 0 the value rounded up. This is the table of fast_float (Daniel Lemire and
|
||||
contributors, used under the MIT license), generated like its
|
||||
script/table_generation.py; unit-class_lexer.cpp recomputes every entry.
|
||||
*/
|
||||
inline const std::array<std::uint64_t, 1302>& pow5_128() noexcept
|
||||
{
|
||||
static const std::array<std::uint64_t, 1302> table =
|
||||
{
|
||||
{
|
||||
0xeef453d6923bd65au, 0x113faa2906a13b3fu, 0x9558b4661b6565f8u, 0x4ac7ca59a424c507u,
|
||||
0xbaaee17fa23ebf76u, 0x5d79bcf00d2df649u, 0xe95a99df8ace6f53u, 0xf4d82c2c107973dcu,
|
||||
0x91d8a02bb6c10594u, 0x79071b9b8a4be869u, 0xb64ec836a47146f9u, 0x9748e2826cdee284u,
|
||||
0xe3e27a444d8d98b7u, 0xfd1b1b2308169b25u, 0x8e6d8c6ab0787f72u, 0xfe30f0f5e50e20f7u,
|
||||
0xb208ef855c969f4fu, 0xbdbd2d335e51a935u, 0xde8b2b66b3bc4723u, 0xad2c788035e61382u,
|
||||
0x8b16fb203055ac76u, 0x4c3bcb5021afcc31u, 0xaddcb9e83c6b1793u, 0xdf4abe242a1bbf3du,
|
||||
0xd953e8624b85dd78u, 0xd71d6dad34a2af0du, 0x87d4713d6f33aa6bu, 0x8672648c40e5ad68u,
|
||||
0xa9c98d8ccb009506u, 0x680efdaf511f18c2u, 0xd43bf0effdc0ba48u, 0x0212bd1b2566def2u,
|
||||
0x84a57695fe98746du, 0x014bb630f7604b57u, 0xa5ced43b7e3e9188u, 0x419ea3bd35385e2du,
|
||||
0xcf42894a5dce35eau, 0x52064cac828675b9u, 0x818995ce7aa0e1b2u, 0x7343efebd1940993u,
|
||||
0xa1ebfb4219491a1fu, 0x1014ebe6c5f90bf8u, 0xca66fa129f9b60a6u, 0xd41a26e077774ef6u,
|
||||
0xfd00b897478238d0u, 0x8920b098955522b4u, 0x9e20735e8cb16382u, 0x55b46e5f5d5535b0u,
|
||||
0xc5a890362fddbc62u, 0xeb2189f734aa831du, 0xf712b443bbd52b7bu, 0xa5e9ec7501d523e4u,
|
||||
0x9a6bb0aa55653b2du, 0x47b233c92125366eu, 0xc1069cd4eabe89f8u, 0x999ec0bb696e840au,
|
||||
0xf148440a256e2c76u, 0xc00670ea43ca250du, 0x96cd2a865764dbcau, 0x380406926a5e5728u,
|
||||
0xbc807527ed3e12bcu, 0xc605083704f5ecf2u, 0xeba09271e88d976bu, 0xf7864a44c633682eu,
|
||||
0x93445b8731587ea3u, 0x7ab3ee6afbe0211du, 0xb8157268fdae9e4cu, 0x5960ea05bad82964u,
|
||||
0xe61acf033d1a45dfu, 0x6fb92487298e33bdu, 0x8fd0c16206306babu, 0xa5d3b6d479f8e056u,
|
||||
0xb3c4f1ba87bc8696u, 0x8f48a4899877186cu, 0xe0b62e2929aba83cu, 0x331acdabfe94de87u,
|
||||
0x8c71dcd9ba0b4925u, 0x9ff0c08b7f1d0b14u, 0xaf8e5410288e1b6fu, 0x07ecf0ae5ee44dd9u,
|
||||
0xdb71e91432b1a24au, 0xc9e82cd9f69d6150u, 0x892731ac9faf056eu, 0xbe311c083a225cd2u,
|
||||
0xab70fe17c79ac6cau, 0x6dbd630a48aaf406u, 0xd64d3d9db981787du, 0x092cbbccdad5b108u,
|
||||
0x85f0468293f0eb4eu, 0x25bbf56008c58ea5u, 0xa76c582338ed2621u, 0xaf2af2b80af6f24eu,
|
||||
0xd1476e2c07286faau, 0x1af5af660db4aee1u, 0x82cca4db847945cau, 0x50d98d9fc890ed4du,
|
||||
0xa37fce126597973cu, 0xe50ff107bab528a0u, 0xcc5fc196fefd7d0cu, 0x1e53ed49a96272c8u,
|
||||
0xff77b1fcbebcdc4fu, 0x25e8e89c13bb0f7au, 0x9faacf3df73609b1u, 0x77b191618c54e9acu,
|
||||
0xc795830d75038c1du, 0xd59df5b9ef6a2417u, 0xf97ae3d0d2446f25u, 0x4b0573286b44ad1du,
|
||||
0x9becce62836ac577u, 0x4ee367f9430aec32u, 0xc2e801fb244576d5u, 0x229c41f793cda73fu,
|
||||
0xf3a20279ed56d48au, 0x6b43527578c1110fu, 0x9845418c345644d6u, 0x830a13896b78aaa9u,
|
||||
0xbe5691ef416bd60cu, 0x23cc986bc656d553u, 0xedec366b11c6cb8fu, 0x2cbfbe86b7ec8aa8u,
|
||||
0x94b3a202eb1c3f39u, 0x7bf7d71432f3d6a9u, 0xb9e08a83a5e34f07u, 0xdaf5ccd93fb0cc53u,
|
||||
0xe858ad248f5c22c9u, 0xd1b3400f8f9cff68u, 0x91376c36d99995beu, 0x23100809b9c21fa1u,
|
||||
0xb58547448ffffb2du, 0xabd40a0c2832a78au, 0xe2e69915b3fff9f9u, 0x16c90c8f323f516cu,
|
||||
0x8dd01fad907ffc3bu, 0xae3da7d97f6792e3u, 0xb1442798f49ffb4au, 0x99cd11cfdf41779cu,
|
||||
0xdd95317f31c7fa1du, 0x40405643d711d583u, 0x8a7d3eef7f1cfc52u, 0x482835ea666b2572u,
|
||||
0xad1c8eab5ee43b66u, 0xda3243650005eecfu, 0xd863b256369d4a40u, 0x90bed43e40076a82u,
|
||||
0x873e4f75e2224e68u, 0x5a7744a6e804a291u, 0xa90de3535aaae202u, 0x711515d0a205cb36u,
|
||||
0xd3515c2831559a83u, 0x0d5a5b44ca873e03u, 0x8412d9991ed58091u, 0xe858790afe9486c2u,
|
||||
0xa5178fff668ae0b6u, 0x626e974dbe39a872u, 0xce5d73ff402d98e3u, 0xfb0a3d212dc8128fu,
|
||||
0x80fa687f881c7f8eu, 0x7ce66634bc9d0b99u, 0xa139029f6a239f72u, 0x1c1fffc1ebc44e80u,
|
||||
0xc987434744ac874eu, 0xa327ffb266b56220u, 0xfbe9141915d7a922u, 0x4bf1ff9f0062baa8u,
|
||||
0x9d71ac8fada6c9b5u, 0x6f773fc3603db4a9u, 0xc4ce17b399107c22u, 0xcb550fb4384d21d3u,
|
||||
0xf6019da07f549b2bu, 0x7e2a53a146606a48u, 0x99c102844f94e0fbu, 0x2eda7444cbfc426du,
|
||||
0xc0314325637a1939u, 0xfa911155fefb5308u, 0xf03d93eebc589f88u, 0x793555ab7eba27cau,
|
||||
0x96267c7535b763b5u, 0x4bc1558b2f3458deu, 0xbbb01b9283253ca2u, 0x9eb1aaedfb016f16u,
|
||||
0xea9c227723ee8bcbu, 0x465e15a979c1cadcu, 0x92a1958a7675175fu, 0x0bfacd89ec191ec9u,
|
||||
0xb749faed14125d36u, 0xcef980ec671f667bu, 0xe51c79a85916f484u, 0x82b7e12780e7401au,
|
||||
0x8f31cc0937ae58d2u, 0xd1b2ecb8b0908810u, 0xb2fe3f0b8599ef07u, 0x861fa7e6dcb4aa15u,
|
||||
0xdfbdcece67006ac9u, 0x67a791e093e1d49au, 0x8bd6a141006042bdu, 0xe0c8bb2c5c6d24e0u,
|
||||
0xaecc49914078536du, 0x58fae9f773886e18u, 0xda7f5bf590966848u, 0xaf39a475506a899eu,
|
||||
0x888f99797a5e012du, 0x6d8406c952429603u, 0xaab37fd7d8f58178u, 0xc8e5087ba6d33b83u,
|
||||
0xd5605fcdcf32e1d6u, 0xfb1e4a9a90880a64u, 0x855c3be0a17fcd26u, 0x5cf2eea09a55067fu,
|
||||
0xa6b34ad8c9dfc06fu, 0xf42faa48c0ea481eu, 0xd0601d8efc57b08bu, 0xf13b94daf124da26u,
|
||||
0x823c12795db6ce57u, 0x76c53d08d6b70858u, 0xa2cb1717b52481edu, 0x54768c4b0c64ca6eu,
|
||||
0xcb7ddcdda26da268u, 0xa9942f5dcf7dfd09u, 0xfe5d54150b090b02u, 0xd3f93b35435d7c4cu,
|
||||
0x9efa548d26e5a6e1u, 0xc47bc5014a1a6dafu, 0xc6b8e9b0709f109au, 0x359ab6419ca1091bu,
|
||||
0xf867241c8cc6d4c0u, 0xc30163d203c94b62u, 0x9b407691d7fc44f8u, 0x79e0de63425dcf1du,
|
||||
0xc21094364dfb5636u, 0x985915fc12f542e4u, 0xf294b943e17a2bc4u, 0x3e6f5b7b17b2939du,
|
||||
0x979cf3ca6cec5b5au, 0xa705992ceecf9c42u, 0xbd8430bd08277231u, 0x50c6ff782a838353u,
|
||||
0xece53cec4a314ebdu, 0xa4f8bf5635246428u, 0x940f4613ae5ed136u, 0x871b7795e136be99u,
|
||||
0xb913179899f68584u, 0x28e2557b59846e3fu, 0xe757dd7ec07426e5u, 0x331aeada2fe589cfu,
|
||||
0x9096ea6f3848984fu, 0x3ff0d2c85def7621u, 0xb4bca50b065abe63u, 0x0fed077a756b53a9u,
|
||||
0xe1ebce4dc7f16dfbu, 0xd3e8495912c62894u, 0x8d3360f09cf6e4bdu, 0x64712dd7abbbd95cu,
|
||||
0xb080392cc4349decu, 0xbd8d794d96aacfb3u, 0xdca04777f541c567u, 0xecf0d7a0fc5583a0u,
|
||||
0x89e42caaf9491b60u, 0xf41686c49db57244u, 0xac5d37d5b79b6239u, 0x311c2875c522ced5u,
|
||||
0xd77485cb25823ac7u, 0x7d633293366b828bu, 0x86a8d39ef77164bcu, 0xae5dff9c02033197u,
|
||||
0xa8530886b54dbdebu, 0xd9f57f830283fdfcu, 0xd267caa862a12d66u, 0xd072df63c324fd7bu,
|
||||
0x8380dea93da4bc60u, 0x4247cb9e59f71e6du, 0xa46116538d0deb78u, 0x52d9be85f074e608u,
|
||||
0xcd795be870516656u, 0x67902e276c921f8bu, 0x806bd9714632dff6u, 0x00ba1cd8a3db53b6u,
|
||||
0xa086cfcd97bf97f3u, 0x80e8a40eccd228a4u, 0xc8a883c0fdaf7df0u, 0x6122cd128006b2cdu,
|
||||
0xfad2a4b13d1b5d6cu, 0x796b805720085f81u, 0x9cc3a6eec6311a63u, 0xcbe3303674053bb0u,
|
||||
0xc3f490aa77bd60fcu, 0xbedbfc4411068a9cu, 0xf4f1b4d515acb93bu, 0xee92fb5515482d44u,
|
||||
0x991711052d8bf3c5u, 0x751bdd152d4d1c4au, 0xbf5cd54678eef0b6u, 0xd262d45a78a0635du,
|
||||
0xef340a98172aace4u, 0x86fb897116c87c34u, 0x9580869f0e7aac0eu, 0xd45d35e6ae3d4da0u,
|
||||
0xbae0a846d2195712u, 0x8974836059cca109u, 0xe998d258869facd7u, 0x2bd1a438703fc94bu,
|
||||
0x91ff83775423cc06u, 0x7b6306a34627ddcfu, 0xb67f6455292cbf08u, 0x1a3bc84c17b1d542u,
|
||||
0xe41f3d6a7377eecau, 0x20caba5f1d9e4a93u, 0x8e938662882af53eu, 0x547eb47b7282ee9cu,
|
||||
0xb23867fb2a35b28du, 0xe99e619a4f23aa43u, 0xdec681f9f4c31f31u, 0x6405fa00e2ec94d4u,
|
||||
0x8b3c113c38f9f37eu, 0xde83bc408dd3dd04u, 0xae0b158b4738705eu, 0x9624ab50b148d445u,
|
||||
0xd98ddaee19068c76u, 0x3badd624dd9b0957u, 0x87f8a8d4cfa417c9u, 0xe54ca5d70a80e5d6u,
|
||||
0xa9f6d30a038d1dbcu, 0x5e9fcf4ccd211f4cu, 0xd47487cc8470652bu, 0x7647c3200069671fu,
|
||||
0x84c8d4dfd2c63f3bu, 0x29ecd9f40041e073u, 0xa5fb0a17c777cf09u, 0xf468107100525890u,
|
||||
0xcf79cc9db955c2ccu, 0x7182148d4066eeb4u, 0x81ac1fe293d599bfu, 0xc6f14cd848405530u,
|
||||
0xa21727db38cb002fu, 0xb8ada00e5a506a7cu, 0xca9cf1d206fdc03bu, 0xa6d90811f0e4851cu,
|
||||
0xfd442e4688bd304au, 0x908f4a166d1da663u, 0x9e4a9cec15763e2eu, 0x9a598e4e043287feu,
|
||||
0xc5dd44271ad3cdbau, 0x40eff1e1853f29fdu, 0xf7549530e188c128u, 0xd12bee59e68ef47cu,
|
||||
0x9a94dd3e8cf578b9u, 0x82bb74f8301958ceu, 0xc13a148e3032d6e7u, 0xe36a52363c1faf01u,
|
||||
0xf18899b1bc3f8ca1u, 0xdc44e6c3cb279ac1u, 0x96f5600f15a7b7e5u, 0x29ab103a5ef8c0b9u,
|
||||
0xbcb2b812db11a5deu, 0x7415d448f6b6f0e7u, 0xebdf661791d60f56u, 0x111b495b3464ad21u,
|
||||
0x936b9fcebb25c995u, 0xcab10dd900beec34u, 0xb84687c269ef3bfbu, 0x3d5d514f40eea742u,
|
||||
0xe65829b3046b0afau, 0x0cb4a5a3112a5112u, 0x8ff71a0fe2c2e6dcu, 0x47f0e785eaba72abu,
|
||||
0xb3f4e093db73a093u, 0x59ed216765690f56u, 0xe0f218b8d25088b8u, 0x306869c13ec3532cu,
|
||||
0x8c974f7383725573u, 0x1e414218c73a13fbu, 0xafbd2350644eeacfu, 0xe5d1929ef90898fau,
|
||||
0xdbac6c247d62a583u, 0xdf45f746b74abf39u, 0x894bc396ce5da772u, 0x6b8bba8c328eb783u,
|
||||
0xab9eb47c81f5114fu, 0x066ea92f3f326564u, 0xd686619ba27255a2u, 0xc80a537b0efefebdu,
|
||||
0x8613fd0145877585u, 0xbd06742ce95f5f36u, 0xa798fc4196e952e7u, 0x2c48113823b73704u,
|
||||
0xd17f3b51fca3a7a0u, 0xf75a15862ca504c5u, 0x82ef85133de648c4u, 0x9a984d73dbe722fbu,
|
||||
0xa3ab66580d5fdaf5u, 0xc13e60d0d2e0ebbau, 0xcc963fee10b7d1b3u, 0x318df905079926a8u,
|
||||
0xffbbcfe994e5c61fu, 0xfdf17746497f7052u, 0x9fd561f1fd0f9bd3u, 0xfeb6ea8bedefa633u,
|
||||
0xc7caba6e7c5382c8u, 0xfe64a52ee96b8fc0u, 0xf9bd690a1b68637bu, 0x3dfdce7aa3c673b0u,
|
||||
0x9c1661a651213e2du, 0x06bea10ca65c084eu, 0xc31bfa0fe5698db8u, 0x486e494fcff30a62u,
|
||||
0xf3e2f893dec3f126u, 0x5a89dba3c3efccfau, 0x986ddb5c6b3a76b7u, 0xf89629465a75e01cu,
|
||||
0xbe89523386091465u, 0xf6bbb397f1135823u, 0xee2ba6c0678b597fu, 0x746aa07ded582e2cu,
|
||||
0x94db483840b717efu, 0xa8c2a44eb4571cdcu, 0xba121a4650e4ddebu, 0x92f34d62616ce413u,
|
||||
0xe896a0d7e51e1566u, 0x77b020baf9c81d17u, 0x915e2486ef32cd60u, 0x0ace1474dc1d122eu,
|
||||
0xb5b5ada8aaff80b8u, 0x0d819992132456bau, 0xe3231912d5bf60e6u, 0x10e1fff697ed6c69u,
|
||||
0x8df5efabc5979c8fu, 0xca8d3ffa1ef463c1u, 0xb1736b96b6fd83b3u, 0xbd308ff8a6b17cb2u,
|
||||
0xddd0467c64bce4a0u, 0xac7cb3f6d05ddbdeu, 0x8aa22c0dbef60ee4u, 0x6bcdf07a423aa96bu,
|
||||
0xad4ab7112eb3929du, 0x86c16c98d2c953c6u, 0xd89d64d57a607744u, 0xe871c7bf077ba8b7u,
|
||||
0x87625f056c7c4a8bu, 0x11471cd764ad4972u, 0xa93af6c6c79b5d2du, 0xd598e40d3dd89bcfu,
|
||||
0xd389b47879823479u, 0x4aff1d108d4ec2c3u, 0x843610cb4bf160cbu, 0xcedf722a585139bau,
|
||||
0xa54394fe1eedb8feu, 0xc2974eb4ee658828u, 0xce947a3da6a9273eu, 0x733d226229feea32u,
|
||||
0x811ccc668829b887u, 0x0806357d5a3f525fu, 0xa163ff802a3426a8u, 0xca07c2dcb0cf26f7u,
|
||||
0xc9bcff6034c13052u, 0xfc89b393dd02f0b5u, 0xfc2c3f3841f17c67u, 0xbbac2078d443ace2u,
|
||||
0x9d9ba7832936edc0u, 0xd54b944b84aa4c0du, 0xc5029163f384a931u, 0x0a9e795e65d4df11u,
|
||||
0xf64335bcf065d37du, 0x4d4617b5ff4a16d5u, 0x99ea0196163fa42eu, 0x504bced1bf8e4e45u,
|
||||
0xc06481fb9bcf8d39u, 0xe45ec2862f71e1d6u, 0xf07da27a82c37088u, 0x5d767327bb4e5a4cu,
|
||||
0x964e858c91ba2655u, 0x3a6a07f8d510f86fu, 0xbbe226efb628afeau, 0x890489f70a55368bu,
|
||||
0xeadab0aba3b2dbe5u, 0x2b45ac74ccea842eu, 0x92c8ae6b464fc96fu, 0x3b0b8bc90012929du,
|
||||
0xb77ada0617e3bbcbu, 0x09ce6ebb40173744u, 0xe55990879ddcaabdu, 0xcc420a6a101d0515u,
|
||||
0x8f57fa54c2a9eab6u, 0x9fa946824a12232du, 0xb32df8e9f3546564u, 0x47939822dc96abf9u,
|
||||
0xdff9772470297ebdu, 0x59787e2b93bc56f7u, 0x8bfbea76c619ef36u, 0x57eb4edb3c55b65au,
|
||||
0xaefae51477a06b03u, 0xede622920b6b23f1u, 0xdab99e59958885c4u, 0xe95fab368e45ecedu,
|
||||
0x88b402f7fd75539bu, 0x11dbcb0218ebb414u, 0xaae103b5fcd2a881u, 0xd652bdc29f26a119u,
|
||||
0xd59944a37c0752a2u, 0x4be76d3346f0495fu, 0x857fcae62d8493a5u, 0x6f70a4400c562ddbu,
|
||||
0xa6dfbd9fb8e5b88eu, 0xcb4ccd500f6bb952u, 0xd097ad07a71f26b2u, 0x7e2000a41346a7a7u,
|
||||
0x825ecc24c873782fu, 0x8ed400668c0c28c8u, 0xa2f67f2dfa90563bu, 0x728900802f0f32fau,
|
||||
0xcbb41ef979346bcau, 0x4f2b40a03ad2ffb9u, 0xfea126b7d78186bcu, 0xe2f610c84987bfa8u,
|
||||
0x9f24b832e6b0f436u, 0x0dd9ca7d2df4d7c9u, 0xc6ede63fa05d3143u, 0x91503d1c79720dbbu,
|
||||
0xf8a95fcf88747d94u, 0x75a44c6397ce912au, 0x9b69dbe1b548ce7cu, 0xc986afbe3ee11abau,
|
||||
0xc24452da229b021bu, 0xfbe85badce996168u, 0xf2d56790ab41c2a2u, 0xfae27299423fb9c3u,
|
||||
0x97c560ba6b0919a5u, 0xdccd879fc967d41au, 0xbdb6b8e905cb600fu, 0x5400e987bbc1c920u,
|
||||
0xed246723473e3813u, 0x290123e9aab23b68u, 0x9436c0760c86e30bu, 0xf9a0b6720aaf6521u,
|
||||
0xb94470938fa89bceu, 0xf808e40e8d5b3e69u, 0xe7958cb87392c2c2u, 0xb60b1d1230b20e04u,
|
||||
0x90bd77f3483bb9b9u, 0xb1c6f22b5e6f48c2u, 0xb4ecd5f01a4aa828u, 0x1e38aeb6360b1af3u,
|
||||
0xe2280b6c20dd5232u, 0x25c6da63c38de1b0u, 0x8d590723948a535fu, 0x579c487e5a38ad0eu,
|
||||
0xb0af48ec79ace837u, 0x2d835a9df0c6d851u, 0xdcdb1b2798182244u, 0xf8e431456cf88e65u,
|
||||
0x8a08f0f8bf0f156bu, 0x1b8e9ecb641b58ffu, 0xac8b2d36eed2dac5u, 0xe272467e3d222f3fu,
|
||||
0xd7adf884aa879177u, 0x5b0ed81dcc6abb0fu, 0x86ccbb52ea94baeau, 0x98e947129fc2b4e9u,
|
||||
0xa87fea27a539e9a5u, 0x3f2398d747b36224u, 0xd29fe4b18e88640eu, 0x8eec7f0d19a03aadu,
|
||||
0x83a3eeeef9153e89u, 0x1953cf68300424acu, 0xa48ceaaab75a8e2bu, 0x5fa8c3423c052dd7u,
|
||||
0xcdb02555653131b6u, 0x3792f412cb06794du, 0x808e17555f3ebf11u, 0xe2bbd88bbee40bd0u,
|
||||
0xa0b19d2ab70e6ed6u, 0x5b6aceaeae9d0ec4u, 0xc8de047564d20a8bu, 0xf245825a5a445275u,
|
||||
0xfb158592be068d2eu, 0xeed6e2f0f0d56712u, 0x9ced737bb6c4183du, 0x55464dd69685606bu,
|
||||
0xc428d05aa4751e4cu, 0xaa97e14c3c26b886u, 0xf53304714d9265dfu, 0xd53dd99f4b3066a8u,
|
||||
0x993fe2c6d07b7fabu, 0xe546a8038efe4029u, 0xbf8fdb78849a5f96u, 0xde98520472bdd033u,
|
||||
0xef73d256a5c0f77cu, 0x963e66858f6d4440u, 0x95a8637627989aadu, 0xdde7001379a44aa8u,
|
||||
0xbb127c53b17ec159u, 0x5560c018580d5d52u, 0xe9d71b689dde71afu, 0xaab8f01e6e10b4a6u,
|
||||
0x9226712162ab070du, 0xcab3961304ca70e8u, 0xb6b00d69bb55c8d1u, 0x3d607b97c5fd0d22u,
|
||||
0xe45c10c42a2b3b05u, 0x8cb89a7db77c506au, 0x8eb98a7a9a5b04e3u, 0x77f3608e92adb242u,
|
||||
0xb267ed1940f1c61cu, 0x55f038b237591ed3u, 0xdf01e85f912e37a3u, 0x6b6c46dec52f6688u,
|
||||
0x8b61313bbabce2c6u, 0x2323ac4b3b3da015u, 0xae397d8aa96c1b77u, 0xabec975e0a0d081au,
|
||||
0xd9c7dced53c72255u, 0x96e7bd358c904a21u, 0x881cea14545c7575u, 0x7e50d64177da2e54u,
|
||||
0xaa242499697392d2u, 0xdde50bd1d5d0b9e9u, 0xd4ad2dbfc3d07787u, 0x955e4ec64b44e864u,
|
||||
0x84ec3c97da624ab4u, 0xbd5af13bef0b113eu, 0xa6274bbdd0fadd61u, 0xecb1ad8aeacdd58eu,
|
||||
0xcfb11ead453994bau, 0x67de18eda5814af2u, 0x81ceb32c4b43fcf4u, 0x80eacf948770ced7u,
|
||||
0xa2425ff75e14fc31u, 0xa1258379a94d028du, 0xcad2f7f5359a3b3eu, 0x096ee45813a04330u,
|
||||
0xfd87b5f28300ca0du, 0x8bca9d6e188853fcu, 0x9e74d1b791e07e48u, 0x775ea264cf55347eu,
|
||||
0xc612062576589ddau, 0x95364afe032a819eu, 0xf79687aed3eec551u, 0x3a83ddbd83f52205u,
|
||||
0x9abe14cd44753b52u, 0xc4926a9672793543u, 0xc16d9a0095928a27u, 0x75b7053c0f178294u,
|
||||
0xf1c90080baf72cb1u, 0x5324c68b12dd6339u, 0x971da05074da7beeu, 0xd3f6fc16ebca5e04u,
|
||||
0xbce5086492111aeau, 0x88f4bb1ca6bcf585u, 0xec1e4a7db69561a5u, 0x2b31e9e3d06c32e6u,
|
||||
0x9392ee8e921d5d07u, 0x3aff322e62439fd0u, 0xb877aa3236a4b449u, 0x09befeb9fad487c3u,
|
||||
0xe69594bec44de15bu, 0x4c2ebe687989a9b4u, 0x901d7cf73ab0acd9u, 0x0f9d37014bf60a11u,
|
||||
0xb424dc35095cd80fu, 0x538484c19ef38c95u, 0xe12e13424bb40e13u, 0x2865a5f206b06fbau,
|
||||
0x8cbccc096f5088cbu, 0xf93f87b7442e45d4u, 0xafebff0bcb24aafeu, 0xf78f69a51539d749u,
|
||||
0xdbe6fecebdedd5beu, 0xb573440e5a884d1cu, 0x89705f4136b4a597u, 0x31680a88f8953031u,
|
||||
0xabcc77118461cefcu, 0xfdc20d2b36ba7c3eu, 0xd6bf94d5e57a42bcu, 0x3d32907604691b4du,
|
||||
0x8637bd05af6c69b5u, 0xa63f9a49c2c1b110u, 0xa7c5ac471b478423u, 0x0fcf80dc33721d54u,
|
||||
0xd1b71758e219652bu, 0xd3c36113404ea4a9u, 0x83126e978d4fdf3bu, 0x645a1cac083126eau,
|
||||
0xa3d70a3d70a3d70au, 0x3d70a3d70a3d70a4u, 0xccccccccccccccccu, 0xcccccccccccccccdu,
|
||||
0x8000000000000000u, 0x0000000000000000u, 0xa000000000000000u, 0x0000000000000000u,
|
||||
0xc800000000000000u, 0x0000000000000000u, 0xfa00000000000000u, 0x0000000000000000u,
|
||||
0x9c40000000000000u, 0x0000000000000000u, 0xc350000000000000u, 0x0000000000000000u,
|
||||
0xf424000000000000u, 0x0000000000000000u, 0x9896800000000000u, 0x0000000000000000u,
|
||||
0xbebc200000000000u, 0x0000000000000000u, 0xee6b280000000000u, 0x0000000000000000u,
|
||||
0x9502f90000000000u, 0x0000000000000000u, 0xba43b74000000000u, 0x0000000000000000u,
|
||||
0xe8d4a51000000000u, 0x0000000000000000u, 0x9184e72a00000000u, 0x0000000000000000u,
|
||||
0xb5e620f480000000u, 0x0000000000000000u, 0xe35fa931a0000000u, 0x0000000000000000u,
|
||||
0x8e1bc9bf04000000u, 0x0000000000000000u, 0xb1a2bc2ec5000000u, 0x0000000000000000u,
|
||||
0xde0b6b3a76400000u, 0x0000000000000000u, 0x8ac7230489e80000u, 0x0000000000000000u,
|
||||
0xad78ebc5ac620000u, 0x0000000000000000u, 0xd8d726b7177a8000u, 0x0000000000000000u,
|
||||
0x878678326eac9000u, 0x0000000000000000u, 0xa968163f0a57b400u, 0x0000000000000000u,
|
||||
0xd3c21bcecceda100u, 0x0000000000000000u, 0x84595161401484a0u, 0x0000000000000000u,
|
||||
0xa56fa5b99019a5c8u, 0x0000000000000000u, 0xcecb8f27f4200f3au, 0x0000000000000000u,
|
||||
0x813f3978f8940984u, 0x4000000000000000u, 0xa18f07d736b90be5u, 0x5000000000000000u,
|
||||
0xc9f2c9cd04674edeu, 0xa400000000000000u, 0xfc6f7c4045812296u, 0x4d00000000000000u,
|
||||
0x9dc5ada82b70b59du, 0xf020000000000000u, 0xc5371912364ce305u, 0x6c28000000000000u,
|
||||
0xf684df56c3e01bc6u, 0xc732000000000000u, 0x9a130b963a6c115cu, 0x3c7f400000000000u,
|
||||
0xc097ce7bc90715b3u, 0x4b9f100000000000u, 0xf0bdc21abb48db20u, 0x1e86d40000000000u,
|
||||
0x96769950b50d88f4u, 0x1314448000000000u, 0xbc143fa4e250eb31u, 0x17d955a000000000u,
|
||||
0xeb194f8e1ae525fdu, 0x5dcfab0800000000u, 0x92efd1b8d0cf37beu, 0x5aa1cae500000000u,
|
||||
0xb7abc627050305adu, 0xf14a3d9e40000000u, 0xe596b7b0c643c719u, 0x6d9ccd05d0000000u,
|
||||
0x8f7e32ce7bea5c6fu, 0xe4820023a2000000u, 0xb35dbf821ae4f38bu, 0xdda2802c8a800000u,
|
||||
0xe0352f62a19e306eu, 0xd50b2037ad200000u, 0x8c213d9da502de45u, 0x4526f422cc340000u,
|
||||
0xaf298d050e4395d6u, 0x9670b12b7f410000u, 0xdaf3f04651d47b4cu, 0x3c0cdd765f114000u,
|
||||
0x88d8762bf324cd0fu, 0xa5880a69fb6ac800u, 0xab0e93b6efee0053u, 0x8eea0d047a457a00u,
|
||||
0xd5d238a4abe98068u, 0x72a4904598d6d880u, 0x85a36366eb71f041u, 0x47a6da2b7f864750u,
|
||||
0xa70c3c40a64e6c51u, 0x999090b65f67d924u, 0xd0cf4b50cfe20765u, 0xfff4b4e3f741cf6du,
|
||||
0x82818f1281ed449fu, 0xbff8f10e7a8921a4u, 0xa321f2d7226895c7u, 0xaff72d52192b6a0du,
|
||||
0xcbea6f8ceb02bb39u, 0x9bf4f8a69f764490u, 0xfee50b7025c36a08u, 0x02f236d04753d5b4u,
|
||||
0x9f4f2726179a2245u, 0x01d762422c946590u, 0xc722f0ef9d80aad6u, 0x424d3ad2b7b97ef5u,
|
||||
0xf8ebad2b84e0d58bu, 0xd2e0898765a7deb2u, 0x9b934c3b330c8577u, 0x63cc55f49f88eb2fu,
|
||||
0xc2781f49ffcfa6d5u, 0x3cbf6b71c76b25fbu, 0xf316271c7fc3908au, 0x8bef464e3945ef7au,
|
||||
0x97edd871cfda3a56u, 0x97758bf0e3cbb5acu, 0xbde94e8e43d0c8ecu, 0x3d52eeed1cbea317u,
|
||||
0xed63a231d4c4fb27u, 0x4ca7aaa863ee4bddu, 0x945e455f24fb1cf8u, 0x8fe8caa93e74ef6au,
|
||||
0xb975d6b6ee39e436u, 0xb3e2fd538e122b44u, 0xe7d34c64a9c85d44u, 0x60dbbca87196b616u,
|
||||
0x90e40fbeea1d3a4au, 0xbc8955e946fe31cdu, 0xb51d13aea4a488ddu, 0x6babab6398bdbe41u,
|
||||
0xe264589a4dcdab14u, 0xc696963c7eed2dd1u, 0x8d7eb76070a08aecu, 0xfc1e1de5cf543ca2u,
|
||||
0xb0de65388cc8ada8u, 0x3b25a55f43294bcbu, 0xdd15fe86affad912u, 0x49ef0eb713f39ebeu,
|
||||
0x8a2dbf142dfcc7abu, 0x6e3569326c784337u, 0xacb92ed9397bf996u, 0x49c2c37f07965404u,
|
||||
0xd7e77a8f87daf7fbu, 0xdc33745ec97be906u, 0x86f0ac99b4e8dafdu, 0x69a028bb3ded71a3u,
|
||||
0xa8acd7c0222311bcu, 0xc40832ea0d68ce0cu, 0xd2d80db02aabd62bu, 0xf50a3fa490c30190u,
|
||||
0x83c7088e1aab65dbu, 0x792667c6da79e0fau, 0xa4b8cab1a1563f52u, 0x577001b891185938u,
|
||||
0xcde6fd5e09abcf26u, 0xed4c0226b55e6f86u, 0x80b05e5ac60b6178u, 0x544f8158315b05b4u,
|
||||
0xa0dc75f1778e39d6u, 0x696361ae3db1c721u, 0xc913936dd571c84cu, 0x03bc3a19cd1e38e9u,
|
||||
0xfb5878494ace3a5fu, 0x04ab48a04065c723u, 0x9d174b2dcec0e47bu, 0x62eb0d64283f9c76u,
|
||||
0xc45d1df942711d9au, 0x3ba5d0bd324f8394u, 0xf5746577930d6500u, 0xca8f44ec7ee36479u,
|
||||
0x9968bf6abbe85f20u, 0x7e998b13cf4e1ecbu, 0xbfc2ef456ae276e8u, 0x9e3fedd8c321a67eu,
|
||||
0xefb3ab16c59b14a2u, 0xc5cfe94ef3ea101eu, 0x95d04aee3b80ece5u, 0xbba1f1d158724a12u,
|
||||
0xbb445da9ca61281fu, 0x2a8a6e45ae8edc97u, 0xea1575143cf97226u, 0xf52d09d71a3293bdu,
|
||||
0x924d692ca61be758u, 0x593c2626705f9c56u, 0xb6e0c377cfa2e12eu, 0x6f8b2fb00c77836cu,
|
||||
0xe498f455c38b997au, 0x0b6dfb9c0f956447u, 0x8edf98b59a373fecu, 0x4724bd4189bd5eacu,
|
||||
0xb2977ee300c50fe7u, 0x58edec91ec2cb657u, 0xdf3d5e9bc0f653e1u, 0x2f2967b66737e3edu,
|
||||
0x8b865b215899f46cu, 0xbd79e0d20082ee74u, 0xae67f1e9aec07187u, 0xecd8590680a3aa11u,
|
||||
0xda01ee641a708de9u, 0xe80e6f4820cc9495u, 0x884134fe908658b2u, 0x3109058d147fdcddu,
|
||||
0xaa51823e34a7eedeu, 0xbd4b46f0599fd415u, 0xd4e5e2cdc1d1ea96u, 0x6c9e18ac7007c91au,
|
||||
0x850fadc09923329eu, 0x03e2cf6bc604ddb0u, 0xa6539930bf6bff45u, 0x84db8346b786151cu,
|
||||
0xcfe87f7cef46ff16u, 0xe612641865679a63u, 0x81f14fae158c5f6eu, 0x4fcb7e8f3f60c07eu,
|
||||
0xa26da3999aef7749u, 0xe3be5e330f38f09du, 0xcb090c8001ab551cu, 0x5cadf5bfd3072cc5u,
|
||||
0xfdcb4fa002162a63u, 0x73d9732fc7c8f7f6u, 0x9e9f11c4014dda7eu, 0x2867e7fddcdd9afau,
|
||||
0xc646d63501a1511du, 0xb281e1fd541501b8u, 0xf7d88bc24209a565u, 0x1f225a7ca91a4226u,
|
||||
0x9ae757596946075fu, 0x3375788de9b06958u, 0xc1a12d2fc3978937u, 0x0052d6b1641c83aeu,
|
||||
0xf209787bb47d6b84u, 0xc0678c5dbd23a49au, 0x9745eb4d50ce6332u, 0xf840b7ba963646e0u,
|
||||
0xbd176620a501fbffu, 0xb650e5a93bc3d898u, 0xec5d3fa8ce427affu, 0xa3e51f138ab4cebeu,
|
||||
0x93ba47c980e98cdfu, 0xc66f336c36b10137u, 0xb8a8d9bbe123f017u, 0xb80b0047445d4184u,
|
||||
0xe6d3102ad96cec1du, 0xa60dc059157491e5u, 0x9043ea1ac7e41392u, 0x87c89837ad68db2fu,
|
||||
0xb454e4a179dd1877u, 0x29babe4598c311fbu, 0xe16a1dc9d8545e94u, 0xf4296dd6fef3d67au,
|
||||
0x8ce2529e2734bb1du, 0x1899e4a65f58660cu, 0xb01ae745b101e9e4u, 0x5ec05dcff72e7f8fu,
|
||||
0xdc21a1171d42645du, 0x76707543f4fa1f73u, 0x899504ae72497ebau, 0x6a06494a791c53a8u,
|
||||
0xabfa45da0edbde69u, 0x0487db9d17636892u, 0xd6f8d7509292d603u, 0x45a9d2845d3c42b6u,
|
||||
0x865b86925b9bc5c2u, 0x0b8a2392ba45a9b2u, 0xa7f26836f282b732u, 0x8e6cac7768d7141eu,
|
||||
0xd1ef0244af2364ffu, 0x3207d795430cd926u, 0x8335616aed761f1fu, 0x7f44e6bd49e807b8u,
|
||||
0xa402b9c5a8d3a6e7u, 0x5f16206c9c6209a6u, 0xcd036837130890a1u, 0x36dba887c37a8c0fu,
|
||||
0x802221226be55a64u, 0xc2494954da2c9789u, 0xa02aa96b06deb0fdu, 0xf2db9baa10b7bd6cu,
|
||||
0xc83553c5c8965d3du, 0x6f92829494e5acc7u, 0xfa42a8b73abbf48cu, 0xcb772339ba1f17f9u,
|
||||
0x9c69a97284b578d7u, 0xff2a760414536efbu, 0xc38413cf25e2d70du, 0xfef5138519684abau,
|
||||
0xf46518c2ef5b8cd1u, 0x7eb258665fc25d69u, 0x98bf2f79d5993802u, 0xef2f773ffbd97a61u,
|
||||
0xbeeefb584aff8603u, 0xaafb550ffacfd8fau, 0xeeaaba2e5dbf6784u, 0x95ba2a53f983cf38u,
|
||||
0x952ab45cfa97a0b2u, 0xdd945a747bf26183u, 0xba756174393d88dfu, 0x94f971119aeef9e4u,
|
||||
0xe912b9d1478ceb17u, 0x7a37cd5601aab85du, 0x91abb422ccb812eeu, 0xac62e055c10ab33au,
|
||||
0xb616a12b7fe617aau, 0x577b986b314d6009u, 0xe39c49765fdf9d94u, 0xed5a7e85fda0b80bu,
|
||||
0x8e41ade9fbebc27du, 0x14588f13be847307u, 0xb1d219647ae6b31cu, 0x596eb2d8ae258fc8u,
|
||||
0xde469fbd99a05fe3u, 0x6fca5f8ed9aef3bbu, 0x8aec23d680043beeu, 0x25de7bb9480d5854u,
|
||||
0xada72ccc20054ae9u, 0xaf561aa79a10ae6au, 0xd910f7ff28069da4u, 0x1b2ba1518094da04u,
|
||||
0x87aa9aff79042286u, 0x90fb44d2f05d0842u, 0xa99541bf57452b28u, 0x353a1607ac744a53u,
|
||||
0xd3fa922f2d1675f2u, 0x42889b8997915ce8u, 0x847c9b5d7c2e09b7u, 0x69956135febada11u,
|
||||
0xa59bc234db398c25u, 0x43fab9837e699095u, 0xcf02b2c21207ef2eu, 0x94f967e45e03f4bbu,
|
||||
0x8161afb94b44f57du, 0x1d1be0eebac278f5u, 0xa1ba1ba79e1632dcu, 0x6462d92a69731732u,
|
||||
0xca28a291859bbf93u, 0x7d7b8f7503cfdcfeu, 0xfcb2cb35e702af78u, 0x5cda735244c3d43eu,
|
||||
0x9defbf01b061adabu, 0x3a0888136afa64a7u, 0xc56baec21c7a1916u, 0x088aaa1845b8fdd0u,
|
||||
0xf6c69a72a3989f5bu, 0x8aad549e57273d45u, 0x9a3c2087a63f6399u, 0x36ac54e2f678864bu,
|
||||
0xc0cb28a98fcf3c7fu, 0x84576a1bb416a7ddu, 0xf0fdf2d3f3c30b9fu, 0x656d44a2a11c51d5u,
|
||||
0x969eb7c47859e743u, 0x9f644ae5a4b1b325u, 0xbc4665b596706114u, 0x873d5d9f0dde1feeu,
|
||||
0xeb57ff22fc0c7959u, 0xa90cb506d155a7eau, 0x9316ff75dd87cbd8u, 0x09a7f12442d588f2u,
|
||||
0xb7dcbf5354e9beceu, 0x0c11ed6d538aeb2fu, 0xe5d3ef282a242e81u, 0x8f1668c8a86da5fau,
|
||||
0x8fa475791a569d10u, 0xf96e017d694487bcu, 0xb38d92d760ec4455u, 0x37c981dcc395a9acu,
|
||||
0xe070f78d3927556au, 0x85bbe253f47b1417u, 0x8c469ab843b89562u, 0x93956d7478ccec8eu,
|
||||
0xaf58416654a6babbu, 0x387ac8d1970027b2u, 0xdb2e51bfe9d0696au, 0x06997b05fcc0319eu,
|
||||
0x88fcf317f22241e2u, 0x441fece3bdf81f03u, 0xab3c2fddeeaad25au, 0xd527e81cad7626c3u,
|
||||
0xd60b3bd56a5586f1u, 0x8a71e223d8d3b074u, 0x85c7056562757456u, 0xf6872d5667844e49u,
|
||||
0xa738c6bebb12d16cu, 0xb428f8ac016561dbu, 0xd106f86e69d785c7u, 0xe13336d701beba52u,
|
||||
0x82a45b450226b39cu, 0xecc0024661173473u, 0xa34d721642b06084u, 0x27f002d7f95d0190u,
|
||||
0xcc20ce9bd35c78a5u, 0x31ec038df7b441f4u, 0xff290242c83396ceu, 0x7e67047175a15271u,
|
||||
0x9f79a169bd203e41u, 0x0f0062c6e984d386u, 0xc75809c42c684dd1u, 0x52c07b78a3e60868u,
|
||||
0xf92e0c3537826145u, 0xa7709a56ccdf8a82u, 0x9bbcc7a142b17ccbu, 0x88a66076400bb691u,
|
||||
0xc2abf989935ddbfeu, 0x6acff893d00ea435u, 0xf356f7ebf83552feu, 0x0583f6b8c4124d43u,
|
||||
0x98165af37b2153deu, 0xc3727a337a8b704au, 0xbe1bf1b059e9a8d6u, 0x744f18c0592e4c5cu,
|
||||
0xeda2ee1c7064130cu, 0x1162def06f79df73u, 0x9485d4d1c63e8be7u, 0x8addcb5645ac2ba8u,
|
||||
0xb9a74a0637ce2ee1u, 0x6d953e2bd7173692u, 0xe8111c87c5c1ba99u, 0xc8fa8db6ccdd0437u,
|
||||
0x910ab1d4db9914a0u, 0x1d9c9892400a22a2u, 0xb54d5e4a127f59c8u, 0x2503beb6d00cab4bu,
|
||||
0xe2a0b5dc971f303au, 0x2e44ae64840fd61du, 0x8da471a9de737e24u, 0x5ceaecfed289e5d2u,
|
||||
0xb10d8e1456105dadu, 0x7425a83e872c5f47u, 0xdd50f1996b947518u, 0xd12f124e28f77719u,
|
||||
0x8a5296ffe33cc92fu, 0x82bd6b70d99aaa6fu, 0xace73cbfdc0bfb7bu, 0x636cc64d1001550bu,
|
||||
0xd8210befd30efa5au, 0x3c47f7e05401aa4eu, 0x8714a775e3e95c78u, 0x65acfaec34810a71u,
|
||||
0xa8d9d1535ce3b396u, 0x7f1839a741a14d0du, 0xd31045a8341ca07cu, 0x1ede48111209a050u,
|
||||
0x83ea2b892091e44du, 0x934aed0aab460432u, 0xa4e4b66b68b65d60u, 0xf81da84d5617853fu,
|
||||
0xce1de40642e3f4b9u, 0x36251260ab9d668eu, 0x80d2ae83e9ce78f3u, 0xc1d72b7c6b426019u,
|
||||
0xa1075a24e4421730u, 0xb24cf65b8612f81fu, 0xc94930ae1d529cfcu, 0xdee033f26797b627u,
|
||||
0xfb9b7cd9a4a7443cu, 0x169840ef017da3b1u, 0x9d412e0806e88aa5u, 0x8e1f289560ee864eu,
|
||||
0xc491798a08a2ad4eu, 0xf1a6f2bab92a27e2u, 0xf5b5d7ec8acb58a2u, 0xae10af696774b1dbu,
|
||||
0x9991a6f3d6bf1765u, 0xacca6da1e0a8ef29u, 0xbff610b0cc6edd3fu, 0x17fd090a58d32af3u,
|
||||
0xeff394dcff8a948eu, 0xddfc4b4cef07f5b0u, 0x95f83d0a1fb69cd9u, 0x4abdaf101564f98eu,
|
||||
0xbb764c4ca7a4440fu, 0x9d6d1ad41abe37f1u, 0xea53df5fd18d5513u, 0x84c86189216dc5edu,
|
||||
0x92746b9be2f8552cu, 0x32fd3cf5b4e49bb4u, 0xb7118682dbb66a77u, 0x3fbc8c33221dc2a1u,
|
||||
0xe4d5e82392a40515u, 0x0fabaf3feaa5334au, 0x8f05b1163ba6832du, 0x29cb4d87f2a7400eu,
|
||||
0xb2c71d5bca9023f8u, 0x743e20e9ef511012u, 0xdf78e4b2bd342cf6u, 0x914da9246b255416u,
|
||||
0x8bab8eefb6409c1au, 0x1ad089b6c2f7548eu, 0xae9672aba3d0c320u, 0xa184ac2473b529b1u,
|
||||
0xda3c0f568cc4f3e8u, 0xc9e5d72d90a2741eu, 0x8865899617fb1871u, 0x7e2fa67c7a658892u,
|
||||
0xaa7eebfb9df9de8du, 0xddbb901b98feeab7u, 0xd51ea6fa85785631u, 0x552a74227f3ea565u,
|
||||
0x8533285c936b35deu, 0xd53a88958f87275fu, 0xa67ff273b8460356u, 0x8a892abaf368f137u,
|
||||
0xd01fef10a657842cu, 0x2d2b7569b0432d85u, 0x8213f56a67f6b29bu, 0x9c3b29620e29fc73u,
|
||||
0xa298f2c501f45f42u, 0x8349f3ba91b47b8fu, 0xcb3f2f7642717713u, 0x241c70a936219a73u,
|
||||
0xfe0efb53d30dd4d7u, 0xed238cd383aa0110u, 0x9ec95d1463e8a506u, 0xf4363804324a40aau,
|
||||
0xc67bb4597ce2ce48u, 0xb143c6053edcd0d5u, 0xf81aa16fdc1b81dau, 0xdd94b7868e94050au,
|
||||
0x9b10a4e5e9913128u, 0xca7cf2b4191c8326u, 0xc1d4ce1f63f57d72u, 0xfd1c2f611f63a3f0u,
|
||||
0xf24a01a73cf2dccfu, 0xbc633b39673c8cecu, 0x976e41088617ca01u, 0xd5be0503e085d813u,
|
||||
0xbd49d14aa79dbc82u, 0x4b2d8644d8a74e18u, 0xec9c459d51852ba2u, 0xddf8e7d60ed1219eu,
|
||||
0x93e1ab8252f33b45u, 0xcabb90e5c942b503u, 0xb8da1662e7b00a17u, 0x3d6a751f3b936243u,
|
||||
0xe7109bfba19c0c9du, 0x0cc512670a783ad4u, 0x906a617d450187e2u, 0x27fb2b80668b24c5u,
|
||||
0xb484f9dc9641e9dau, 0xb1f9f660802dedf6u, 0xe1a63853bbd26451u, 0x5e7873f8a0396973u,
|
||||
0x8d07e33455637eb2u, 0xdb0b487b6423e1e8u, 0xb049dc016abc5e5fu, 0x91ce1a9a3d2cda62u,
|
||||
0xdc5c5301c56b75f7u, 0x7641a140cc7810fbu, 0x89b9b3e11b6329bau, 0xa9e904c87fcb0a9du,
|
||||
0xac2820d9623bf429u, 0x546345fa9fbdcd44u, 0xd732290fbacaf133u, 0xa97c177947ad4095u,
|
||||
0x867f59a9d4bed6c0u, 0x49ed8eabcccc485du, 0xa81f301449ee8c70u, 0x5c68f256bfff5a74u,
|
||||
0xd226fc195c6a2f8cu, 0x73832eec6fff3111u, 0x83585d8fd9c25db7u, 0xc831fd53c5ff7eabu,
|
||||
0xa42e74f3d032f525u, 0xba3e7ca8b77f5e55u, 0xcd3a1230c43fb26fu, 0x28ce1bd2e55f35ebu,
|
||||
0x80444b5e7aa7cf85u, 0x7980d163cf5b81b3u, 0xa0555e361951c366u, 0xd7e105bcc332621fu,
|
||||
0xc86ab5c39fa63440u, 0x8dd9472bf3fefaa7u, 0xfa856334878fc150u, 0xb14f98f6f0feb951u,
|
||||
0x9c935e00d4b9d8d2u, 0x6ed1bf9a569f33d3u, 0xc3b8358109e84f07u, 0x0a862f80ec4700c8u,
|
||||
0xf4a642e14c6262c8u, 0xcd27bb612758c0fau, 0x98e7e9cccfbd7dbdu, 0x8038d51cb897789cu,
|
||||
0xbf21e44003acdd2cu, 0xe0470a63e6bd56c3u, 0xeeea5d5004981478u, 0x1858ccfce06cac74u,
|
||||
0x95527a5202df0ccbu, 0x0f37801e0c43ebc8u, 0xbaa718e68396cffdu, 0xd30560258f54e6bau,
|
||||
0xe950df20247c83fdu, 0x47c6b82ef32a2069u, 0x91d28b7416cdd27eu, 0x4cdc331d57fa5441u,
|
||||
0xb6472e511c81471du, 0xe0133fe4adf8e952u, 0xe3d8f9e563a198e5u, 0x58180fddd97723a6u,
|
||||
0x8e679c2f5e44ff8fu, 0x570f09eaa7ea7648u,
|
||||
}
|
||||
};
|
||||
return table;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
@@ -8,12 +8,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array> // array
|
||||
#include <cstddef> // size_t
|
||||
#include <cstdint> // uint64_t, uint8_t
|
||||
#include <cstdint> // uint64_t
|
||||
#include <cstring> // memcpy
|
||||
|
||||
#include <nlohmann/detail/bit_ops.hpp>
|
||||
#include <nlohmann/detail/macro_scope.hpp>
|
||||
|
||||
// Optional SIMD backend for bulk UTF-8 validation. This is an opt-in external
|
||||
@@ -71,12 +69,18 @@ inline std::size_t find_string_special(const unsigned char* data, std::size_t n)
|
||||
std::size_t i = 0;
|
||||
for (; i + 8 <= n; i += 8)
|
||||
{
|
||||
const std::uint64_t special = swar_string_special(read_eight_bytes(data + i));
|
||||
if (special != 0)
|
||||
std::uint64_t word = 0;
|
||||
std::memcpy(&word, data + i, sizeof(word));
|
||||
if (swar_string_special(word) != 0)
|
||||
{
|
||||
// the lowest flagged byte is the first special one: the borrows of
|
||||
// the subtractions can only flag bytes above a true hit
|
||||
return i + (static_cast<std::size_t>(count_trailing_zeros(special)) / 8);
|
||||
// a special byte is in this word; locate it (endian-agnostic)
|
||||
for (std::size_t j = 0; j < 8; ++j)
|
||||
{
|
||||
if (is_string_special(data[i + j]))
|
||||
{
|
||||
return i + j;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (; i < n; ++i)
|
||||
@@ -110,7 +114,8 @@ inline std::size_t find_ascii_copyable_run(const unsigned char* data, std::size_
|
||||
std::size_t i = 0;
|
||||
for (; i + 8 <= n; i += 8)
|
||||
{
|
||||
const std::uint64_t v = read_eight_bytes(data + i);
|
||||
std::uint64_t v = 0;
|
||||
std::memcpy(&v, data + i, sizeof(v));
|
||||
const std::uint64_t q = v ^ 0x2222222222222222ull; // '"' (0x22)
|
||||
const std::uint64_t b = v ^ 0x5C5C5C5C5C5C5C5Cull; // '\\' (0x5C)
|
||||
const std::uint64_t d = v ^ 0x7F7F7F7F7F7F7F7Full; // DEL (0x7F)
|
||||
@@ -121,9 +126,7 @@ inline std::size_t find_ascii_copyable_run(const unsigned char* data, std::size_
|
||||
| (v & high); // >= 0x80
|
||||
if (stop != 0)
|
||||
{
|
||||
// the lowest flagged byte is the first one to stop at (see
|
||||
// find_string_special())
|
||||
return i + (static_cast<std::size_t>(count_trailing_zeros(stop)) / 8);
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (; i < n; ++i)
|
||||
@@ -250,18 +253,12 @@ inline std::size_t scalar_string_bulk_run(const unsigned char* data, std::size_t
|
||||
{
|
||||
break; // end of buffer, or a quote/escape/control byte
|
||||
}
|
||||
// a run of multi-byte sequences (e.g. CJK text) is validated sequence
|
||||
// by sequence without searching for the next special byte in between
|
||||
do
|
||||
const std::size_t seq = validate_one_utf8(data + pos, n - pos);
|
||||
if (seq == 0)
|
||||
{
|
||||
const std::size_t seq = validate_one_utf8(data + pos, n - pos);
|
||||
if (seq == 0)
|
||||
{
|
||||
return pos; // ill-formed or truncated: let the byte path diagnose it
|
||||
}
|
||||
pos += seq;
|
||||
break; // ill-formed or truncated: let the byte path diagnose it
|
||||
}
|
||||
while (pos < n && data[pos] >= 0x80u);
|
||||
pos += seq;
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
@@ -276,7 +273,8 @@ inline std::size_t find_string_delimiter(const unsigned char* data, std::size_t
|
||||
std::size_t i = 0;
|
||||
for (; i + 8 <= n; i += 8)
|
||||
{
|
||||
const std::uint64_t v = read_eight_bytes(data + i);
|
||||
std::uint64_t v = 0;
|
||||
std::memcpy(&v, data + i, sizeof(v));
|
||||
const std::uint64_t q = v ^ 0x2222222222222222ull;
|
||||
const std::uint64_t b = v ^ 0x5C5C5C5C5C5C5C5Cull;
|
||||
const std::uint64_t hit = ((q - ones) & ~q & high)
|
||||
@@ -284,8 +282,14 @@ inline std::size_t find_string_delimiter(const unsigned char* data, std::size_t
|
||||
| ((v - 0x2020202020202020ull) & ~v & high);
|
||||
if (hit != 0)
|
||||
{
|
||||
// the lowest flagged byte is the first delimiter (see find_string_special())
|
||||
return i + (static_cast<std::size_t>(count_trailing_zeros(hit)) / 8);
|
||||
for (std::size_t j = 0; j < 8; ++j)
|
||||
{
|
||||
const unsigned char c = data[i + j];
|
||||
if (c == '\"' || c == '\\' || c < 0x20u)
|
||||
{
|
||||
return i + j;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (; i < n; ++i)
|
||||
@@ -316,50 +320,5 @@ inline std::size_t string_bulk_run(const unsigned char* data, std::size_t n) noe
|
||||
return scalar_string_bulk_run(data, n);
|
||||
}
|
||||
|
||||
// Decode the 4 hex digits at [data, data+4) - the digits following a `\u`
|
||||
// escape - into a codepoint 0x0000..0xFFFF via one table lookup per byte
|
||||
// (after yyjson's read_hex_u16), or return -1 if any of the 4 bytes is not a
|
||||
// hex digit ('0'..'9', 'A'..'F', 'a'..'f'). The caller must already have
|
||||
// checked that 4 bytes are available; used by lexer::get_codepoint()'s
|
||||
// contiguous fast path. On -1 it falls back to the byte-at-a-time loop, which
|
||||
// stops at the first invalid digit, so the reported error and position are
|
||||
// unaffected by this fast path.
|
||||
inline int hex_codepoint(const unsigned char* data) noexcept
|
||||
{
|
||||
static const std::array<std::uint8_t, 256> hex_digit_table = // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
{
|
||||
{
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 00..0F
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 10..1F
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 20..2F
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 30..3F ('0'..'9')
|
||||
0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 40..4F ('A'..'F')
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 50..5F
|
||||
0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 60..6F ('a'..'f')
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 70..7F
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 80..8F
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 90..9F
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // A0..AF
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // B0..BF
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // C0..CF
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // D0..DF
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // E0..EF
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF // F0..FF
|
||||
}
|
||||
};
|
||||
|
||||
const std::uint8_t d0 = hex_digit_table[data[0]];
|
||||
const std::uint8_t d1 = hex_digit_table[data[1]];
|
||||
const std::uint8_t d2 = hex_digit_table[data[2]];
|
||||
const std::uint8_t d3 = hex_digit_table[data[3]];
|
||||
// every valid digit is <= 0xF; the combined OR only exceeds it if at
|
||||
// least one of the four bytes was not a hex digit (looked up as 0xFF)
|
||||
if ((d0 | d1 | d2 | d3) > 0x0F)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return (d0 << 12) | (d1 << 8) | (d2 << 4) | d3;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
|
||||
@@ -1,130 +0,0 @@
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array> // array
|
||||
#include <cstddef> // size_t
|
||||
#include <cstring> // memcpy
|
||||
#include <new> // operator new, placement new
|
||||
#include <string> // string
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <nlohmann/detail/view/macro_scope.hpp>
|
||||
#include <nlohmann/detail/view/node.hpp>
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
namespace detail
|
||||
{
|
||||
namespace view
|
||||
{
|
||||
|
||||
/// storage of a parsed document; heap-allocated (header and an initial node
|
||||
/// array in one block) so that views survive moves of the owning document
|
||||
struct document_data
|
||||
{
|
||||
const char* src = nullptr;
|
||||
std::size_t size = 0;
|
||||
node* tape = nullptr;
|
||||
std::size_t tape_size = 0;
|
||||
std::size_t tape_cap = 0;
|
||||
node* inline_tape = nullptr; ///< node array allocated together with this header
|
||||
std::size_t inline_cap = 0;
|
||||
std::string arena{}; ///< decoded strings that contained escapes // NOLINT(readability-redundant-member-init)
|
||||
std::string owned{}; ///< owned copy of the input, if any // NOLINT(readability-redundant-member-init)
|
||||
std::array<const char*, 4> base = {{nullptr, nullptr, nullptr, nullptr}}; ///< string bases: source, arena (indexed by flags & node_flags::storage)
|
||||
bool discarded = true;
|
||||
|
||||
/// one allocation for the header and room for `nodes` nodes; large
|
||||
/// documents get a separate node array instead (so it can be trimmed)
|
||||
static document_data* create(std::size_t nodes)
|
||||
{
|
||||
nodes = nodes <= 256 ? nodes : 0;
|
||||
void* mem = ::operator new (sizeof(document_data) + (nodes * sizeof(node)));
|
||||
auto* d = new (mem) document_data(); // NOLINT(cppcoreguidelines-owning-memory): owned by the returned pointer, freed by deleter
|
||||
// (aligned: sizeof is a multiple of the alignment; through void*, as GCC's -Wcast-align wants)
|
||||
d->inline_tape = static_cast<node*>(static_cast<void*>(static_cast<char*>(mem) + sizeof(document_data))); // NOLINT(bugprone-casting-through-void)
|
||||
d->inline_cap = nodes;
|
||||
d->tape = d->inline_tape;
|
||||
d->tape_cap = nodes;
|
||||
return d;
|
||||
}
|
||||
|
||||
struct deleter
|
||||
{
|
||||
void operator()(document_data* d) const noexcept
|
||||
{
|
||||
d->~document_data();
|
||||
::operator delete (d);
|
||||
}
|
||||
};
|
||||
|
||||
document_data() noexcept = default;
|
||||
document_data(const document_data&) = delete;
|
||||
document_data(document_data&&) = delete;
|
||||
document_data& operator=(const document_data&) = delete;
|
||||
document_data& operator=(document_data&&) = delete;
|
||||
~document_data()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void release() noexcept
|
||||
{
|
||||
if (tape != inline_tape)
|
||||
{
|
||||
::operator delete (tape);
|
||||
}
|
||||
tape = inline_tape;
|
||||
tape_cap = inline_cap;
|
||||
}
|
||||
|
||||
/// make room for n nodes; keeps the first tape_size nodes
|
||||
void reserve(std::size_t n)
|
||||
{
|
||||
if (n <= tape_cap)
|
||||
{
|
||||
return;
|
||||
}
|
||||
node* fresh = static_cast<node*>(::operator new (n * sizeof(node)));
|
||||
if (tape_size != 0)
|
||||
{
|
||||
std::memcpy(fresh, tape, tape_size * sizeof(node));
|
||||
}
|
||||
release();
|
||||
tape = fresh;
|
||||
tape_cap = n;
|
||||
}
|
||||
|
||||
const char* str(const node& n) const noexcept
|
||||
{
|
||||
return base[n.flags & node_flags::storage] + n.off;
|
||||
}
|
||||
|
||||
/// the node after n's subtree (containers span `next` nodes, scalars one)
|
||||
static NLOHMANN_VIEW_ALWAYS_INLINE const node* after(const node* n) noexcept
|
||||
{
|
||||
return n + (is_container(*n) ? n->next : 1u);
|
||||
}
|
||||
|
||||
/// first element (array) or first key (object) of a container
|
||||
static NLOHMANN_VIEW_ALWAYS_INLINE const node* first_child(const node* n) noexcept
|
||||
{
|
||||
return n + 1;
|
||||
}
|
||||
|
||||
/// end of the elements of a container
|
||||
static NLOHMANN_VIEW_ALWAYS_INLINE const node* child_end(const node* n) noexcept
|
||||
{
|
||||
return n + n->next;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace view
|
||||
} // namespace detail
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
@@ -1,63 +0,0 @@
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
// Macros of json_view.hpp and its detail headers. json.hpp undefines its own
|
||||
// macros at its end (macro_unscope.hpp), so the view defines the few it needs
|
||||
// under its own prefix; json_view.hpp undefines them all at its end
|
||||
// (detail/view/macro_unscope.hpp). Configuration that json.hpp undefines is
|
||||
// read from detail::abi_config instead.
|
||||
|
||||
#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
|
||||
#define NLOHMANN_VIEW_HAS_CPP_17 1
|
||||
#else
|
||||
#define NLOHMANN_VIEW_HAS_CPP_17 0
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#define NLOHMANN_VIEW_LIKELY(x) __builtin_expect(!!(x), 1)
|
||||
#define NLOHMANN_VIEW_UNLIKELY(x) __builtin_expect(!!(x), 0)
|
||||
#define NLOHMANN_VIEW_ALWAYS_INLINE inline __attribute__((always_inline))
|
||||
#define NLOHMANN_VIEW_NOINLINE __attribute__((noinline))
|
||||
#elif defined(_MSC_VER)
|
||||
#define NLOHMANN_VIEW_LIKELY(x) (x)
|
||||
#define NLOHMANN_VIEW_UNLIKELY(x) (x)
|
||||
#define NLOHMANN_VIEW_ALWAYS_INLINE __forceinline
|
||||
#define NLOHMANN_VIEW_NOINLINE __declspec(noinline)
|
||||
#else
|
||||
#define NLOHMANN_VIEW_LIKELY(x) (x)
|
||||
#define NLOHMANN_VIEW_UNLIKELY(x) (x)
|
||||
#define NLOHMANN_VIEW_ALWAYS_INLINE inline
|
||||
#define NLOHMANN_VIEW_NOINLINE
|
||||
#endif
|
||||
|
||||
// exceptions as in json.hpp (JSON_NOEXCEPTION, JSON_THROW_USER)
|
||||
#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION)
|
||||
#define NLOHMANN_VIEW_THROW(exception) throw exception
|
||||
#else
|
||||
#include <cstdlib>
|
||||
// (the exception is built first, so that the arguments of the throwing
|
||||
// helpers count as used; the program ends anyway)
|
||||
#define NLOHMANN_VIEW_THROW(exception) (static_cast<void>(exception), std::abort())
|
||||
#endif
|
||||
#if defined(JSON_THROW_USER)
|
||||
#undef NLOHMANN_VIEW_THROW
|
||||
#define NLOHMANN_VIEW_THROW JSON_THROW_USER
|
||||
#endif
|
||||
|
||||
// the parser stores a node's first word at once where the layout of `node` is
|
||||
// known to be little-endian (MSVC targets are); elsewhere field by field
|
||||
#if (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || defined(_MSC_VER)
|
||||
#define NLOHMANN_VIEW_LITTLE_ENDIAN 1
|
||||
#else
|
||||
#define NLOHMANN_VIEW_LITTLE_ENDIAN 0
|
||||
#endif
|
||||
|
||||
/// sixteen checks at fixed offsets 0..15
|
||||
#define NLOHMANN_VIEW_REPEAT16(X) X(0) X(1) X(2) X(3) X(4) X(5) X(6) X(7) X(8) X(9) X(10) X(11) X(12) X(13) X(14) X(15)
|
||||
@@ -1,20 +0,0 @@
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
// undefine the macros of detail/view/macro_scope.hpp (at the end of json_view.hpp)
|
||||
|
||||
#undef NLOHMANN_VIEW_HAS_CPP_17
|
||||
#undef NLOHMANN_VIEW_LIKELY
|
||||
#undef NLOHMANN_VIEW_UNLIKELY
|
||||
#undef NLOHMANN_VIEW_ALWAYS_INLINE
|
||||
#undef NLOHMANN_VIEW_NOINLINE
|
||||
#undef NLOHMANN_VIEW_THROW
|
||||
#undef NLOHMANN_VIEW_LITTLE_ENDIAN
|
||||
#undef NLOHMANN_VIEW_REPEAT16
|
||||
@@ -1,97 +0,0 @@
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef> // size_t
|
||||
#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t
|
||||
#include <cstring> // memcpy
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <nlohmann/detail/view/macro_scope.hpp>
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
namespace detail
|
||||
{
|
||||
namespace view
|
||||
{
|
||||
|
||||
// the node kinds are value_t values; the tests of is_container() and of the
|
||||
// number kinds depend on this numbering
|
||||
static_assert(static_cast<std::uint8_t>(value_t::null) == 0 && static_cast<std::uint8_t>(value_t::object) == 1
|
||||
&& static_cast<std::uint8_t>(value_t::array) == 2 && static_cast<std::uint8_t>(value_t::string) == 3
|
||||
&& static_cast<std::uint8_t>(value_t::boolean) == 4 && static_cast<std::uint8_t>(value_t::number_integer) == 5
|
||||
&& static_cast<std::uint8_t>(value_t::number_unsigned) == 6 && static_cast<std::uint8_t>(value_t::number_float) == 7,
|
||||
"the node format depends on the numbering of value_t");
|
||||
|
||||
/// node flags
|
||||
struct node_flags
|
||||
{
|
||||
static constexpr std::uint8_t escaped = 1; ///< string payload lives in the decode arena, not the source
|
||||
static constexpr std::uint8_t storage = 3; ///< mask: where a string or number token lives (index into document_data::base)
|
||||
static constexpr std::uint8_t is_true = 4; ///< boolean value
|
||||
};
|
||||
|
||||
/// One entry of the flat index, in document order. An object's members are
|
||||
/// stored as key node followed by the value's subtree. Integers keep their
|
||||
/// converted 64-bit value in the len/next bytes (the node after a scalar is
|
||||
/// always the next one, and the token length follows from `extra`).
|
||||
struct node
|
||||
{
|
||||
std::uint8_t kind; ///< value_t
|
||||
std::uint8_t flags; ///< node_flags
|
||||
std::uint16_t extra; ///< numbers: integer digits (low byte) and fraction digits (high byte), 255 = "many"; otherwise 0
|
||||
std::uint32_t off; ///< source offset (string content, number token, literal, bracket); arena offset if node_flags::escaped
|
||||
std::uint32_t len; ///< string: decoded bytes; float: token bytes; array/object: element count
|
||||
std::uint32_t next; ///< array/object: number of nodes of the subtree (its extent in the enclosing sequence)
|
||||
};
|
||||
static_assert(sizeof(node) == 16, "node must stay 16 bytes");
|
||||
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE bool is_container(const node& n) noexcept
|
||||
{
|
||||
return static_cast<unsigned>(n.kind) - 1u <= 1u;
|
||||
}
|
||||
|
||||
/// the converted value of an integer node (stored in len/next)
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE std::uint64_t integer_bits(const node& n) noexcept
|
||||
{
|
||||
std::uint64_t v = 0;
|
||||
std::memcpy(&v, reinterpret_cast<const unsigned char*>(&n) + 8, 8); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
|
||||
return v;
|
||||
}
|
||||
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE void set_integer_bits(node& n, std::uint64_t v) noexcept
|
||||
{
|
||||
std::memcpy(reinterpret_cast<unsigned char*>(&n) + 8, &v, 8); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
|
||||
}
|
||||
|
||||
/// token length of a number node
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE std::uint32_t number_length(const node& n) noexcept
|
||||
{
|
||||
return n.kind == static_cast<std::uint8_t>(value_t::number_float) ? n.len
|
||||
: (n.extra & 0xFFu) + (n.kind == static_cast<std::uint8_t>(value_t::number_integer) ? 1u : 0u);
|
||||
}
|
||||
|
||||
/// estimated number of nodes for an input of `size` bytes (one node per ~12
|
||||
/// bytes covers typical documents without regrowth)
|
||||
inline std::size_t estimate_nodes(std::size_t size) noexcept
|
||||
{
|
||||
return (size / 12) + 16;
|
||||
}
|
||||
|
||||
/// estimated number of nodes for the input [src, src + size): pretty-printed
|
||||
/// input (whitespace after the first byte) needs about a node per 12 bytes,
|
||||
/// minified input up to one per 4 (yyjson tells the two apart the same way)
|
||||
inline std::size_t estimate_nodes(const char* src, std::size_t size) noexcept
|
||||
{
|
||||
return size >= 2 && (src[1] == ' ' || src[1] == '\n' || src[1] == '\r' || src[1] == '\t') ? estimate_nodes(size) : (size / 4) + 16;
|
||||
}
|
||||
|
||||
} // namespace view
|
||||
} // namespace detail
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
@@ -1,189 +0,0 @@
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-FileCopyrightText: 2020 YaoYuan <https://github.com/ibireme/yyjson>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array> // array
|
||||
#include <cstddef> // size_t
|
||||
#include <cstdint> // uint8_t, uint16_t, uint64_t
|
||||
#include <cstring> // memcpy
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <nlohmann/detail/view/macro_scope.hpp>
|
||||
|
||||
// Scanning primitives of the view's parser. The unrolled checks at fixed
|
||||
// offsets follow yyjson (https://github.com/ibireme/yyjson, MIT license): the
|
||||
// loads do not depend on each other, so the CPU can run ahead. Words are read
|
||||
// with read_eight_bytes(), so nothing here depends on the byte order.
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
namespace detail
|
||||
{
|
||||
namespace view
|
||||
{
|
||||
|
||||
/// 1 for bytes that may appear verbatim in a string: 0x20..0x7F except '"' and '\\'
|
||||
inline const std::uint8_t* string_plain() noexcept
|
||||
{
|
||||
static const std::array<std::uint8_t, 256> table =
|
||||
{
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x00..0x1F
|
||||
1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x20..0x3F ('"')
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 0x40..0x5F ('\\')
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x60..0x7F
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x80..0x9F
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xA0..0xBF
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xC0..0xDF
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xE0..0xFF
|
||||
}
|
||||
};
|
||||
return table.data();
|
||||
}
|
||||
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE bool is_digit(unsigned char c) noexcept
|
||||
{
|
||||
return static_cast<unsigned char>(c - '0') <= 9;
|
||||
}
|
||||
|
||||
/// two bytes as they are in memory (only compared with byte-symmetric patterns)
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE std::uint16_t load16(const unsigned char* p) noexcept
|
||||
{
|
||||
std::uint16_t w = 0;
|
||||
std::memcpy(&w, p, 2);
|
||||
return w;
|
||||
}
|
||||
|
||||
/// Advance over plain string bytes and well-formed UTF-8. Stops at a quote,
|
||||
/// a backslash, a control character, ill-formed UTF-8, or the end. The first
|
||||
/// 16 bytes are checked one by one, so that the position advances by
|
||||
/// constants in predicted branches (most strings are short); longer runs
|
||||
/// continue eight bytes at a time.
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE const unsigned char* scan_string_run(const unsigned char* p, const unsigned char* e) noexcept
|
||||
{
|
||||
const std::uint8_t* plain = string_plain();
|
||||
for (;;)
|
||||
{
|
||||
if (e - p >= 16)
|
||||
{
|
||||
#define NLOHMANN_VIEW_STEP(i) if (NLOHMANN_VIEW_LIKELY(plain[p[i]] != 0)) {} else { p += (i); goto stop; }
|
||||
NLOHMANN_VIEW_REPEAT16(NLOHMANN_VIEW_STEP)
|
||||
#undef NLOHMANN_VIEW_STEP
|
||||
p += 16;
|
||||
while (e - p >= 8)
|
||||
{
|
||||
const std::uint64_t special = swar_string_special(read_eight_bytes(p));
|
||||
if (special != 0)
|
||||
{
|
||||
p += count_trailing_zeros(special) / 8;
|
||||
goto stop;
|
||||
}
|
||||
p += 8;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
while (p != e && plain[*p] != 0)
|
||||
{
|
||||
++p;
|
||||
}
|
||||
if (p == e)
|
||||
{
|
||||
return p;
|
||||
}
|
||||
stop:
|
||||
if (*p < 0x80)
|
||||
{
|
||||
return p; // quote, backslash, or control character
|
||||
}
|
||||
// non-ASCII: a run of well-formed sequences (the library's check, so
|
||||
// that exactly what json::parse accepts is accepted)
|
||||
do
|
||||
{
|
||||
const std::size_t n = validate_one_utf8(p, static_cast<std::size_t>(e - p));
|
||||
if (n == 0)
|
||||
{
|
||||
return p;
|
||||
}
|
||||
p += n;
|
||||
}
|
||||
while (p != e && *p >= 0x80);
|
||||
}
|
||||
}
|
||||
|
||||
/// advance over ASCII digits
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE const unsigned char* skip_digits(const unsigned char* p, const unsigned char* e) noexcept
|
||||
{
|
||||
while (e - p >= 16)
|
||||
{
|
||||
#define NLOHMANN_VIEW_STEP(i) if (NLOHMANN_VIEW_LIKELY(is_digit(p[i]))) {} else { return p + (i); }
|
||||
NLOHMANN_VIEW_REPEAT16(NLOHMANN_VIEW_STEP)
|
||||
#undef NLOHMANN_VIEW_STEP
|
||||
p += 16;
|
||||
}
|
||||
while (p != e && is_digit(*p))
|
||||
{
|
||||
++p;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/// powers of ten up to 10^19 as integers
|
||||
inline std::uint64_t int_pow10(unsigned k) noexcept
|
||||
{
|
||||
static const std::array<std::uint64_t, 20> table =
|
||||
{
|
||||
{
|
||||
1u, 10u, 100u, 1000u, 10000u, 100000u, 1000000u, 10000000u, 100000000u, 1000000000u,
|
||||
10000000000u, 100000000000u, 1000000000000u, 10000000000000u, 100000000000000u, 1000000000000000u,
|
||||
10000000000000000u, 100000000000000000u, 1000000000000000000u, 10000000000000000000u
|
||||
}
|
||||
};
|
||||
return table[k];
|
||||
}
|
||||
|
||||
/// value of 0 < k < 8 digits at p in one step if [p, p + 8) lies below
|
||||
/// limit, else one digit at a time (whole blocks of eight digits are read by
|
||||
/// parse_upto19() directly)
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE std::uint64_t parse_upto8(const unsigned char* p, unsigned k, const unsigned char* limit) noexcept
|
||||
{
|
||||
if (NLOHMANN_VIEW_LIKELY(limit - p >= 8))
|
||||
{
|
||||
// move the k digits to the top and pad the vacated low bytes with '0'
|
||||
const unsigned shift = 8 * (8 - k);
|
||||
return parse_eight_digits((read_eight_bytes(p) << shift) | (0x3030303030303030u >> (8 * k)));
|
||||
}
|
||||
std::uint64_t v = 0;
|
||||
for (unsigned i = 0; i < k; ++i)
|
||||
{
|
||||
v = (v * 10) + static_cast<std::uint64_t>(p[i] - '0');
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
/// value of k <= 19 digits at p
|
||||
NLOHMANN_VIEW_ALWAYS_INLINE std::uint64_t parse_upto19(const unsigned char* p, unsigned k, const unsigned char* limit) noexcept
|
||||
{
|
||||
std::uint64_t w = 0;
|
||||
while (k >= 8)
|
||||
{
|
||||
// (eight digits of the token: they lie below limit)
|
||||
w = (w * 100000000u) + parse_eight_digits(read_eight_bytes(p));
|
||||
p += 8;
|
||||
k -= 8;
|
||||
}
|
||||
if (k != 0)
|
||||
{
|
||||
w = (w * int_pow10(k)) + parse_upto8(p, k, limit);
|
||||
}
|
||||
return w;
|
||||
}
|
||||
|
||||
} // namespace view
|
||||
} // namespace detail
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
@@ -1,111 +0,0 @@
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm> // min
|
||||
#include <cstddef> // size_t
|
||||
#include <cstring> // memcmp, strlen
|
||||
#include <string> // basic_string
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <nlohmann/detail/view/macro_scope.hpp>
|
||||
|
||||
#if NLOHMANN_VIEW_HAS_CPP_17
|
||||
#include <string_view> // string_view
|
||||
#endif
|
||||
#ifndef JSON_NO_IO
|
||||
#include <ostream> // ostream
|
||||
#endif
|
||||
|
||||
NLOHMANN_JSON_NAMESPACE_BEGIN
|
||||
namespace detail
|
||||
{
|
||||
namespace view
|
||||
{
|
||||
|
||||
#if NLOHMANN_VIEW_HAS_CPP_17
|
||||
using string_ref = std::string_view;
|
||||
#else
|
||||
/// minimal C++11 stand-in for std::string_view
|
||||
class string_ref
|
||||
{
|
||||
public:
|
||||
using size_type = std::size_t;
|
||||
using const_iterator = const char*;
|
||||
|
||||
string_ref() noexcept = default;
|
||||
string_ref(const char* s) : m_data(s), m_size(std::strlen(s)) {} // NOLINT(google-explicit-constructor,hicpp-explicit-conversions)
|
||||
string_ref(const char* s, std::size_t n) noexcept : m_data(s), m_size(n) {}
|
||||
template<typename Traits, typename Alloc>
|
||||
string_ref(const std::basic_string<char, Traits, Alloc>& s) noexcept : m_data(s.data()), m_size(s.size()) {} // NOLINT(google-explicit-constructor,hicpp-explicit-conversions)
|
||||
|
||||
const char* data() const noexcept
|
||||
{
|
||||
return m_data;
|
||||
}
|
||||
std::size_t size() const noexcept
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
std::size_t length() const noexcept
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
bool empty() const noexcept
|
||||
{
|
||||
return m_size == 0;
|
||||
}
|
||||
const char* begin() const noexcept
|
||||
{
|
||||
return m_data;
|
||||
}
|
||||
const char* end() const noexcept
|
||||
{
|
||||
return m_data + m_size;
|
||||
}
|
||||
char operator[](std::size_t i) const noexcept
|
||||
{
|
||||
return m_data[i];
|
||||
}
|
||||
|
||||
template<typename Traits, typename Alloc>
|
||||
explicit operator std::basic_string<char, Traits, Alloc>() const
|
||||
{
|
||||
return std::basic_string<char, Traits, Alloc>(m_data, m_size);
|
||||
}
|
||||
|
||||
friend bool operator==(string_ref a, string_ref b) noexcept
|
||||
{
|
||||
return a.m_size == b.m_size && (a.m_size == 0 || std::memcmp(a.m_data, b.m_data, a.m_size) == 0);
|
||||
}
|
||||
friend bool operator!=(string_ref a, string_ref b) noexcept
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
||||
friend bool operator<(string_ref a, string_ref b) noexcept
|
||||
{
|
||||
const int c = std::memcmp(a.m_data, b.m_data, (std::min)(a.m_size, b.m_size));
|
||||
return c != 0 ? c < 0 : a.m_size < b.m_size;
|
||||
}
|
||||
#ifndef JSON_NO_IO
|
||||
friend std::ostream& operator<<(std::ostream& o, string_ref s)
|
||||
{
|
||||
return o.write(s.m_data, static_cast<std::streamsize>(s.m_size));
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
const char* m_data = "";
|
||||
std::size_t m_size = 0;
|
||||
};
|
||||
#endif
|
||||
|
||||
} // namespace view
|
||||
} // namespace detail
|
||||
NLOHMANN_JSON_NAMESPACE_END
|
||||
@@ -43,7 +43,6 @@
|
||||
|
||||
#include <nlohmann/adl_serializer.hpp>
|
||||
#include <nlohmann/byte_container_with_subtype.hpp>
|
||||
#include <nlohmann/detail/abi_config.hpp>
|
||||
#include <nlohmann/detail/conversions/from_json.hpp>
|
||||
#include <nlohmann/detail/conversions/to_json.hpp>
|
||||
#include <nlohmann/detail/exceptions.hpp>
|
||||
|
||||
@@ -279,10 +279,6 @@ if(json_32bit_test_only)
|
||||
elseif(NOT json_32bit_test)
|
||||
list(FILTER files EXCLUDE REGEX src/unit-32bit.cpp)
|
||||
endif()
|
||||
if(NOT JSON_MultipleHeaders)
|
||||
# the internal headers of json_view are not part of a single header yet
|
||||
list(FILTER files EXCLUDE REGEX src/unit-json_view_builder.cpp)
|
||||
endif()
|
||||
|
||||
foreach(file ${files})
|
||||
json_test_add_test_for(${file} MAIN test_main CXX_STANDARDS ${test_cxx_standards} ${test_force})
|
||||
|
||||
|
Before Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 26 KiB |
@@ -1,10 +0,0 @@
|
||||
<table style="font-family: 'Trebuchet MS', 'Tahoma', 'Arial', 'Helvetica'">
|
||||
<tr><td style="width: 18ex"><b>Banner:</b></td><td>fuzz</td></tr>
|
||||
<tr><td><b>Directory:</b></td><td>fuzz-testing/out</td></tr>
|
||||
<tr><td><b>Generated on:</b></td><td>Mo 29 Aug 2016 22:14:22 CEST</td></tr>
|
||||
</table>
|
||||
<p>
|
||||
<img src="high_freq.png" width=1000 height=300><p>
|
||||
<img src="low_freq.png" width=1000 height=200><p>
|
||||
<img src="exec_speed.png" width=1000 height=200>
|
||||
|
||||
|
Before Width: | Height: | Size: 12 KiB |
@@ -1,31 +0,0 @@
|
||||
Results of the latest benchmark from <https://github.com/miloyip/nativejson-benchmark>.
|
||||
|
||||
See <https://github.com/nlohmann/json/issues/307> for discussion.
|
||||
|
||||
Original post at 2016-09-09 to <json@yahoogroups.com>:
|
||||
|
||||
> Hi,
|
||||
>
|
||||
> This benchmark evaluated conformance, parse/stringify speed/memory, and
|
||||
> code size. It can also be viewed as a long list of open source C/C++ JSON
|
||||
> libraries.
|
||||
>
|
||||
> You can run the benchmark on your own machine by checkout this project.
|
||||
>
|
||||
> https://github.com/miloyip/nativejson-benchmark
|
||||
>
|
||||
> You can also view some sample results here:
|
||||
>
|
||||
> https://rawgit.com/miloyip/nativejson-benchmark/master/sample/conformance.html
|
||||
> https://rawgit.com/miloyip/nativejson-benchmark/master/sample/performance_Corei7-4980HQ@2.80GHz_mac64_clang7.0.html
|
||||
>
|
||||
> If you make a new library, you may use this for testing conformance and
|
||||
> performance. Afterwards, please submit a pull request.
|
||||
>
|
||||
> Enjoy!
|
||||
>
|
||||
> --
|
||||
> Milo Yip
|
||||
>
|
||||
> https://github.com/miloyip/
|
||||
> http://twitter.com/miloyip/
|
||||
@@ -1,670 +0,0 @@
|
||||
|
||||
|
||||
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" class="">
|
||||
<head prefix="og: http://ogp.me/ns# fb: http://ogp.me/ns/fb# object: http://ogp.me/ns/object# article: http://ogp.me/ns/article# profile: http://ogp.me/ns/profile#">
|
||||
<meta charset='utf-8'>
|
||||
|
||||
|
||||
<link crossorigin="anonymous" href="https://assets-cdn.github.com/assets/frameworks-3a71f36dec04358c4f2f42280fb2cf5c38856f935a3f609eab0a1ae31b1d635a.css" media="all" rel="stylesheet" />
|
||||
<link crossorigin="anonymous" href="https://assets-cdn.github.com/assets/github-5c885e880e980dc7f119393287b84906d930ccaff83f6bff8ae2c086b87ca4d8.css" media="all" rel="stylesheet" />
|
||||
|
||||
|
||||
<link crossorigin="anonymous" href="https://assets-cdn.github.com/assets/site-4ef7bbe907458c89cb1f7f5c5e6c4cd87e03acf66b1817325e644920d2a83330.css" media="all" rel="stylesheet" />
|
||||
|
||||
|
||||
<link as="script" href="https://assets-cdn.github.com/assets/frameworks-88471af1fec40ff9418efbe2ddd15b6896af8d772f8179004c254dffc25ea490.js" rel="preload" />
|
||||
|
||||
<link as="script" href="https://assets-cdn.github.com/assets/github-e18e11a943ff2eb9394c72d4ec8b76592c454915b5839ae177d422777a046e29.js" rel="preload" />
|
||||
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta http-equiv="Content-Language" content="en">
|
||||
<meta name="viewport" content="width=device-width">
|
||||
|
||||
<title>nativejson-benchmark/conformance_Nlohmann (C++11).md at master · miloyip/nativejson-benchmark · GitHub</title>
|
||||
<link rel="search" type="application/opensearchdescription+xml" href="/opensearch.xml" title="GitHub">
|
||||
<link rel="fluid-icon" href="https://github.com/fluidicon.png" title="GitHub">
|
||||
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
|
||||
<link rel="apple-touch-icon" sizes="57x57" href="/apple-touch-icon-57x57.png">
|
||||
<link rel="apple-touch-icon" sizes="60x60" href="/apple-touch-icon-60x60.png">
|
||||
<link rel="apple-touch-icon" sizes="72x72" href="/apple-touch-icon-72x72.png">
|
||||
<link rel="apple-touch-icon" sizes="76x76" href="/apple-touch-icon-76x76.png">
|
||||
<link rel="apple-touch-icon" sizes="114x114" href="/apple-touch-icon-114x114.png">
|
||||
<link rel="apple-touch-icon" sizes="120x120" href="/apple-touch-icon-120x120.png">
|
||||
<link rel="apple-touch-icon" sizes="144x144" href="/apple-touch-icon-144x144.png">
|
||||
<link rel="apple-touch-icon" sizes="152x152" href="/apple-touch-icon-152x152.png">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon-180x180.png">
|
||||
<meta property="fb:app_id" content="1401488693436528">
|
||||
|
||||
<meta content="https://avatars2.githubusercontent.com/u/1195774?v=3&s=400" name="twitter:image:src" /><meta content="@github" name="twitter:site" /><meta content="summary" name="twitter:card" /><meta content="miloyip/nativejson-benchmark" name="twitter:title" /><meta content="nativejson-benchmark - C/C++ JSON parser/generator benchmark" name="twitter:description" />
|
||||
<meta content="https://avatars2.githubusercontent.com/u/1195774?v=3&s=400" property="og:image" /><meta content="GitHub" property="og:site_name" /><meta content="object" property="og:type" /><meta content="miloyip/nativejson-benchmark" property="og:title" /><meta content="https://github.com/miloyip/nativejson-benchmark" property="og:url" /><meta content="nativejson-benchmark - C/C++ JSON parser/generator benchmark" property="og:description" />
|
||||
<meta name="browser-stats-url" content="https://api.github.com/_private/browser/stats">
|
||||
<meta name="browser-errors-url" content="https://api.github.com/_private/browser/errors">
|
||||
<link rel="assets" href="https://assets-cdn.github.com/">
|
||||
|
||||
<meta name="pjax-timeout" content="1000">
|
||||
|
||||
<meta name="request-id" content="D4563DA7:75ED:525C921:57D6FEBB" data-pjax-transient>
|
||||
|
||||
<meta name="msapplication-TileImage" content="/windows-tile.png">
|
||||
<meta name="msapplication-TileColor" content="#ffffff">
|
||||
<meta name="selected-link" value="repo_source" data-pjax-transient>
|
||||
|
||||
<meta name="google-site-verification" content="KT5gs8h0wvaagLKAVWq8bbeNwnZZK1r1XQysX3xurLU">
|
||||
<meta name="google-site-verification" content="ZzhVyEFwb7w3e0-uOTltm8Jsck2F5StVihD0exw2fsA">
|
||||
<meta name="google-analytics" content="UA-3769691-2">
|
||||
|
||||
<meta content="collector.githubapp.com" name="octolytics-host" /><meta content="github" name="octolytics-app-id" /><meta content="D4563DA7:75ED:525C921:57D6FEBB" name="octolytics-dimension-request_id" />
|
||||
<meta content="/<user-name>/<repo-name>/blob/show" data-pjax-transient="true" name="analytics-location" />
|
||||
|
||||
|
||||
|
||||
<meta class="js-ga-set" name="dimension1" content="Logged Out">
|
||||
|
||||
|
||||
|
||||
<meta name="hostname" content="github.com">
|
||||
<meta name="user-login" content="">
|
||||
|
||||
<meta name="expected-hostname" content="github.com">
|
||||
<meta name="js-proxy-site-detection-payload" content="N2RkMmY1ZjE1MTA4MzRhYTA5NDNkMjliNDU3OTA3ZTdlMGNmNDZjN2QyODBiZjM3MmYzMjFjNzY1ZjIwNjY4NHx7InJlbW90ZV9hZGRyZXNzIjoiMjEyLjg2LjYxLjE2NyIsInJlcXVlc3RfaWQiOiJENDU2M0RBNzo3NUVEOjUyNUM5MjE6NTdENkZFQkIiLCJ0aW1lc3RhbXAiOjE0NzM3MDc3MDh9">
|
||||
|
||||
|
||||
<link rel="mask-icon" href="https://assets-cdn.github.com/pinned-octocat.svg" color="#4078c0">
|
||||
<link rel="icon" type="image/x-icon" href="https://assets-cdn.github.com/favicon.ico">
|
||||
|
||||
<meta name="html-safe-nonce" content="deea0f406df2fb95709865c5ee80a255d8c47fa9">
|
||||
<meta content="736eea9d74cf34fe850d2180e8a5f0a1cc7bc0be" name="form-nonce" />
|
||||
|
||||
<meta http-equiv="x-pjax-version" content="f302977937abe3fe1c9a4d4bed913565">
|
||||
|
||||
|
||||
|
||||
<meta name="description" content="nativejson-benchmark - C/C++ JSON parser/generator benchmark">
|
||||
<meta name="go-import" content="github.com/miloyip/nativejson-benchmark git https://github.com/miloyip/nativejson-benchmark.git">
|
||||
|
||||
<meta content="1195774" name="octolytics-dimension-user_id" /><meta content="miloyip" name="octolytics-dimension-user_login" /><meta content="22976798" name="octolytics-dimension-repository_id" /><meta content="miloyip/nativejson-benchmark" name="octolytics-dimension-repository_nwo" /><meta content="true" name="octolytics-dimension-repository_public" /><meta content="false" name="octolytics-dimension-repository_is_fork" /><meta content="22976798" name="octolytics-dimension-repository_network_root_id" /><meta content="miloyip/nativejson-benchmark" name="octolytics-dimension-repository_network_root_nwo" />
|
||||
<link href="https://github.com/miloyip/nativejson-benchmark/commits/master.atom" rel="alternate" title="Recent Commits to nativejson-benchmark:master" type="application/atom+xml">
|
||||
|
||||
|
||||
<link rel="canonical" href="https://github.com/miloyip/nativejson-benchmark/blob/master/sample/conformance_Nlohmann%20(C%2B%2B11).md" data-pjax-transient>
|
||||
</head>
|
||||
|
||||
|
||||
<body class="logged-out env-production vis-public page-blob">
|
||||
<div id="js-pjax-loader-bar" class="pjax-loader-bar"><div class="progress"></div></div>
|
||||
<a href="#start-of-content" tabindex="1" class="accessibility-aid js-skip-to-content">Skip to content</a>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<header class="site-header js-details-container" role="banner">
|
||||
<div class="container-responsive">
|
||||
<a class="header-logo-invertocat" href="https://github.com/" aria-label="Homepage" data-ga-click="(Logged out) Header, go to homepage, icon:logo-wordmark">
|
||||
<svg aria-hidden="true" class="octicon octicon-mark-github" height="32" version="1.1" viewBox="0 0 16 16" width="32"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z"></path></svg>
|
||||
</a>
|
||||
|
||||
<button class="btn-link float-right site-header-toggle js-details-target" type="button" aria-label="Toggle navigation">
|
||||
<svg aria-hidden="true" class="octicon octicon-three-bars" height="24" version="1.1" viewBox="0 0 12 16" width="18"><path d="M11.41 9H.59C0 9 0 8.59 0 8c0-.59 0-1 .59-1H11.4c.59 0 .59.41.59 1 0 .59 0 1-.59 1h.01zm0-4H.59C0 5 0 4.59 0 4c0-.59 0-1 .59-1H11.4c.59 0 .59.41.59 1 0 .59 0 1-.59 1h.01zM.59 11H11.4c.59 0 .59.41.59 1 0 .59 0 1-.59 1H.59C0 13 0 12.59 0 12c0-.59 0-1 .59-1z"></path></svg>
|
||||
</button>
|
||||
|
||||
<div class="site-header-menu">
|
||||
<nav class="site-header-nav site-header-nav-main">
|
||||
<a href="/personal" class="js-selected-navigation-item nav-item nav-item-personal" data-ga-click="Header, click, Nav menu - item:personal" data-selected-links="/personal /personal">
|
||||
Personal
|
||||
</a> <a href="/open-source" class="js-selected-navigation-item nav-item nav-item-opensource" data-ga-click="Header, click, Nav menu - item:opensource" data-selected-links="/open-source /open-source">
|
||||
Open source
|
||||
</a> <a href="/business" class="js-selected-navigation-item nav-item nav-item-business" data-ga-click="Header, click, Nav menu - item:business" data-selected-links="/business /business/partners /business/features /business/customers /business">
|
||||
Business
|
||||
</a> <a href="/explore" class="js-selected-navigation-item nav-item nav-item-explore" data-ga-click="Header, click, Nav menu - item:explore" data-selected-links="/explore /trending /trending/developers /integrations /integrations/feature/code /integrations/feature/collaborate /integrations/feature/ship /explore">
|
||||
Explore
|
||||
</a> </nav>
|
||||
|
||||
<div class="site-header-actions">
|
||||
<a class="btn btn-primary site-header-actions-btn" href="/join?source=header-repo" data-ga-click="(Logged out) Header, clicked Sign up, text:sign-up">Sign up</a>
|
||||
<a class="btn site-header-actions-btn mr-2" href="/login?return_to=%2Fmiloyip%2Fnativejson-benchmark%2Fblob%2Fmaster%2Fsample%2Fconformance_Nlohmann%2520%28C%252B%252B11%29.md" data-ga-click="(Logged out) Header, clicked Sign in, text:sign-in">Sign in</a>
|
||||
</div>
|
||||
|
||||
<nav class="site-header-nav site-header-nav-secondary">
|
||||
<a class="nav-item" href="/pricing">Pricing</a>
|
||||
<a class="nav-item" href="/blog">Blog</a>
|
||||
<a class="nav-item" href="https://help.github.com">Support</a>
|
||||
<a class="nav-item header-search-link" href="https://github.com/search">Search GitHub</a>
|
||||
<div class="header-search scoped-search site-scoped-search js-site-search" role="search">
|
||||
<!-- </textarea> --><!-- '"` --><form accept-charset="UTF-8" action="/miloyip/nativejson-benchmark/search" class="js-site-search-form" data-scoped-search-url="/miloyip/nativejson-benchmark/search" data-unscoped-search-url="/search" method="get"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="✓" /></div>
|
||||
<label class="form-control header-search-wrapper js-chromeless-input-container">
|
||||
<div class="header-search-scope">This repository</div>
|
||||
<input type="text"
|
||||
class="form-control header-search-input js-site-search-focus js-site-search-field is-clearable"
|
||||
data-hotkey="s"
|
||||
name="q"
|
||||
placeholder="Search"
|
||||
aria-label="Search this repository"
|
||||
data-unscoped-placeholder="Search GitHub"
|
||||
data-scoped-placeholder="Search"
|
||||
autocapitalize="off">
|
||||
</label>
|
||||
</form></div>
|
||||
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
|
||||
|
||||
<div id="start-of-content" class="accessibility-aid"></div>
|
||||
|
||||
<div id="js-flash-container">
|
||||
</div>
|
||||
|
||||
|
||||
<div role="main">
|
||||
<div itemscope itemtype="http://schema.org/SoftwareSourceCode">
|
||||
<div id="js-repo-pjax-container" data-pjax-container>
|
||||
|
||||
<div class="pagehead repohead instapaper_ignore readability-menu experiment-repo-nav">
|
||||
<div class="container repohead-details-container">
|
||||
|
||||
|
||||
|
||||
<ul class="pagehead-actions">
|
||||
|
||||
<li>
|
||||
<a href="/login?return_to=%2Fmiloyip%2Fnativejson-benchmark"
|
||||
class="btn btn-sm btn-with-count tooltipped tooltipped-n"
|
||||
aria-label="You must be signed in to watch a repository" rel="nofollow">
|
||||
<svg aria-hidden="true" class="octicon octicon-eye" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M8.06 2C3 2 0 8 0 8s3 6 8.06 6C13 14 16 8 16 8s-3-6-7.94-6zM8 12c-2.2 0-4-1.78-4-4 0-2.2 1.8-4 4-4 2.22 0 4 1.8 4 4 0 2.22-1.78 4-4 4zm2-4c0 1.11-.89 2-2 2-1.11 0-2-.89-2-2 0-1.11.89-2 2-2 1.11 0 2 .89 2 2z"></path></svg>
|
||||
Watch
|
||||
</a>
|
||||
<a class="social-count" href="/miloyip/nativejson-benchmark/watchers"
|
||||
aria-label="40 users are watching this repository">
|
||||
40
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="/login?return_to=%2Fmiloyip%2Fnativejson-benchmark"
|
||||
class="btn btn-sm btn-with-count tooltipped tooltipped-n"
|
||||
aria-label="You must be signed in to star a repository" rel="nofollow">
|
||||
<svg aria-hidden="true" class="octicon octicon-star" height="16" version="1.1" viewBox="0 0 14 16" width="14"><path d="M14 6l-4.9-.64L7 1 4.9 5.36 0 6l3.6 3.26L2.67 14 7 11.67 11.33 14l-.93-4.74z"></path></svg>
|
||||
Star
|
||||
</a>
|
||||
|
||||
<a class="social-count js-social-count" href="/miloyip/nativejson-benchmark/stargazers"
|
||||
aria-label="352 users starred this repository">
|
||||
352
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="/login?return_to=%2Fmiloyip%2Fnativejson-benchmark"
|
||||
class="btn btn-sm btn-with-count tooltipped tooltipped-n"
|
||||
aria-label="You must be signed in to fork a repository" rel="nofollow">
|
||||
<svg aria-hidden="true" class="octicon octicon-repo-forked" height="16" version="1.1" viewBox="0 0 10 16" width="10"><path d="M8 1a1.993 1.993 0 0 0-1 3.72V6L5 8 3 6V4.72A1.993 1.993 0 0 0 2 1a1.993 1.993 0 0 0-1 3.72V6.5l3 3v1.78A1.993 1.993 0 0 0 5 15a1.993 1.993 0 0 0 1-3.72V9.5l3-3V4.72A1.993 1.993 0 0 0 8 1zM2 4.2C1.34 4.2.8 3.65.8 3c0-.65.55-1.2 1.2-1.2.65 0 1.2.55 1.2 1.2 0 .65-.55 1.2-1.2 1.2zm3 10c-.66 0-1.2-.55-1.2-1.2 0-.65.55-1.2 1.2-1.2.65 0 1.2.55 1.2 1.2 0 .65-.55 1.2-1.2 1.2zm3-10c-.66 0-1.2-.55-1.2-1.2 0-.65.55-1.2 1.2-1.2.65 0 1.2.55 1.2 1.2 0 .65-.55 1.2-1.2 1.2z"></path></svg>
|
||||
Fork
|
||||
</a>
|
||||
|
||||
<a href="/miloyip/nativejson-benchmark/network" class="social-count"
|
||||
aria-label="59 users are forked this repository">
|
||||
59
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h1 class="public ">
|
||||
<svg aria-hidden="true" class="octicon octicon-repo" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M4 9H3V8h1v1zm0-3H3v1h1V6zm0-2H3v1h1V4zm0-2H3v1h1V2zm8-1v12c0 .55-.45 1-1 1H6v2l-1.5-1.5L3 16v-2H1c-.55 0-1-.45-1-1V1c0-.55.45-1 1-1h10c.55 0 1 .45 1 1zm-1 10H1v2h2v-1h3v1h5v-2zm0-10H2v9h9V1z"></path></svg>
|
||||
<span class="author" itemprop="author"><a href="/miloyip" class="url fn" rel="author">miloyip</a></span><!--
|
||||
--><span class="path-divider">/</span><!--
|
||||
--><strong itemprop="name"><a href="/miloyip/nativejson-benchmark" data-pjax="#js-repo-pjax-container">nativejson-benchmark</a></strong>
|
||||
|
||||
</h1>
|
||||
|
||||
</div>
|
||||
<div class="container">
|
||||
|
||||
<nav class="reponav js-repo-nav js-sidenav-container-pjax"
|
||||
itemscope
|
||||
itemtype="http://schema.org/BreadcrumbList"
|
||||
role="navigation"
|
||||
data-pjax="#js-repo-pjax-container">
|
||||
|
||||
<span itemscope itemtype="http://schema.org/ListItem" itemprop="itemListElement">
|
||||
<a href="/miloyip/nativejson-benchmark" aria-selected="true" class="js-selected-navigation-item selected reponav-item" data-hotkey="g c" data-selected-links="repo_source repo_downloads repo_commits repo_releases repo_tags repo_branches /miloyip/nativejson-benchmark" itemprop="url">
|
||||
<svg aria-hidden="true" class="octicon octicon-code" height="16" version="1.1" viewBox="0 0 14 16" width="14"><path d="M9.5 3L8 4.5 11.5 8 8 11.5 9.5 13 14 8 9.5 3zm-5 0L0 8l4.5 5L6 11.5 2.5 8 6 4.5 4.5 3z"></path></svg>
|
||||
<span itemprop="name">Code</span>
|
||||
<meta itemprop="position" content="1">
|
||||
</a> </span>
|
||||
|
||||
<span itemscope itemtype="http://schema.org/ListItem" itemprop="itemListElement">
|
||||
<a href="/miloyip/nativejson-benchmark/issues" class="js-selected-navigation-item reponav-item" data-hotkey="g i" data-selected-links="repo_issues repo_labels repo_milestones /miloyip/nativejson-benchmark/issues" itemprop="url">
|
||||
<svg aria-hidden="true" class="octicon octicon-issue-opened" height="16" version="1.1" viewBox="0 0 14 16" width="14"><path d="M7 2.3c3.14 0 5.7 2.56 5.7 5.7s-2.56 5.7-5.7 5.7A5.71 5.71 0 0 1 1.3 8c0-3.14 2.56-5.7 5.7-5.7zM7 1C3.14 1 0 4.14 0 8s3.14 7 7 7 7-3.14 7-7-3.14-7-7-7zm1 3H6v5h2V4zm0 6H6v2h2v-2z"></path></svg>
|
||||
<span itemprop="name">Issues</span>
|
||||
<span class="counter">8</span>
|
||||
<meta itemprop="position" content="2">
|
||||
</a> </span>
|
||||
|
||||
<span itemscope itemtype="http://schema.org/ListItem" itemprop="itemListElement">
|
||||
<a href="/miloyip/nativejson-benchmark/pulls" class="js-selected-navigation-item reponav-item" data-hotkey="g p" data-selected-links="repo_pulls /miloyip/nativejson-benchmark/pulls" itemprop="url">
|
||||
<svg aria-hidden="true" class="octicon octicon-git-pull-request" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M11 11.28V5c-.03-.78-.34-1.47-.94-2.06C9.46 2.35 8.78 2.03 8 2H7V0L4 3l3 3V4h1c.27.02.48.11.69.31.21.2.3.42.31.69v6.28A1.993 1.993 0 0 0 10 15a1.993 1.993 0 0 0 1-3.72zm-1 2.92c-.66 0-1.2-.55-1.2-1.2 0-.65.55-1.2 1.2-1.2.65 0 1.2.55 1.2 1.2 0 .65-.55 1.2-1.2 1.2zM4 3c0-1.11-.89-2-2-2a1.993 1.993 0 0 0-1 3.72v6.56A1.993 1.993 0 0 0 2 15a1.993 1.993 0 0 0 1-3.72V4.72c.59-.34 1-.98 1-1.72zm-.8 10c0 .66-.55 1.2-1.2 1.2-.65 0-1.2-.55-1.2-1.2 0-.65.55-1.2 1.2-1.2.65 0 1.2.55 1.2 1.2zM2 4.2C1.34 4.2.8 3.65.8 3c0-.65.55-1.2 1.2-1.2.65 0 1.2.55 1.2 1.2 0 .65-.55 1.2-1.2 1.2z"></path></svg>
|
||||
<span itemprop="name">Pull requests</span>
|
||||
<span class="counter">1</span>
|
||||
<meta itemprop="position" content="3">
|
||||
</a> </span>
|
||||
|
||||
|
||||
|
||||
|
||||
<a href="/miloyip/nativejson-benchmark/pulse" class="js-selected-navigation-item reponav-item" data-selected-links="pulse /miloyip/nativejson-benchmark/pulse">
|
||||
<svg aria-hidden="true" class="octicon octicon-pulse" height="16" version="1.1" viewBox="0 0 14 16" width="14"><path d="M11.5 8L8.8 5.4 6.6 8.5 5.5 1.6 2.38 8H0v2h3.6l.9-1.8.9 5.4L9 8.5l1.6 1.5H14V8z"></path></svg>
|
||||
Pulse
|
||||
</a>
|
||||
<a href="/miloyip/nativejson-benchmark/graphs" class="js-selected-navigation-item reponav-item" data-selected-links="repo_graphs repo_contributors /miloyip/nativejson-benchmark/graphs">
|
||||
<svg aria-hidden="true" class="octicon octicon-graph" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M16 14v1H0V0h1v14h15zM5 13H3V8h2v5zm4 0H7V3h2v10zm4 0h-2V6h2v7z"></path></svg>
|
||||
Graphs
|
||||
</a>
|
||||
|
||||
</nav>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="container new-discussion-timeline experiment-repo-nav">
|
||||
<div class="repository-content">
|
||||
|
||||
|
||||
|
||||
<a href="/miloyip/nativejson-benchmark/blob/95f27ebcf9a96c7ca4cee26467ed5420140090fb/sample/conformance_Nlohmann%20(C%2B%2B11).md" class="d-none js-permalink-shortcut" data-hotkey="y">Permalink</a>
|
||||
|
||||
<!-- blob contrib key: blob_contributors:v21:0bf9e3593dedd91db6c9dc69e13b7f95 -->
|
||||
|
||||
<div class="file-navigation js-zeroclipboard-container">
|
||||
|
||||
<div class="select-menu branch-select-menu js-menu-container js-select-menu float-left">
|
||||
<button class="btn btn-sm select-menu-button js-menu-target css-truncate" data-hotkey="w"
|
||||
|
||||
type="button" aria-label="Switch branches or tags" tabindex="0" aria-haspopup="true">
|
||||
<i>Branch:</i>
|
||||
<span class="js-select-button css-truncate-target">master</span>
|
||||
</button>
|
||||
|
||||
<div class="select-menu-modal-holder js-menu-content js-navigation-container" data-pjax aria-hidden="true">
|
||||
|
||||
<div class="select-menu-modal">
|
||||
<div class="select-menu-header">
|
||||
<svg aria-label="Close" class="octicon octicon-x js-menu-close" height="16" role="img" version="1.1" viewBox="0 0 12 16" width="12"><path d="M7.48 8l3.75 3.75-1.48 1.48L6 9.48l-3.75 3.75-1.48-1.48L4.52 8 .77 4.25l1.48-1.48L6 6.52l3.75-3.75 1.48 1.48z"></path></svg>
|
||||
<span class="select-menu-title">Switch branches/tags</span>
|
||||
</div>
|
||||
|
||||
<div class="select-menu-filters">
|
||||
<div class="select-menu-text-filter">
|
||||
<input type="text" aria-label="Filter branches/tags" id="context-commitish-filter-field" class="form-control js-filterable-field js-navigation-enable" placeholder="Filter branches/tags">
|
||||
</div>
|
||||
<div class="select-menu-tabs">
|
||||
<ul>
|
||||
<li class="select-menu-tab">
|
||||
<a href="#" data-tab-filter="branches" data-filter-placeholder="Filter branches/tags" class="js-select-menu-tab" role="tab">Branches</a>
|
||||
</li>
|
||||
<li class="select-menu-tab">
|
||||
<a href="#" data-tab-filter="tags" data-filter-placeholder="Find a tag…" class="js-select-menu-tab" role="tab">Tags</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="select-menu-list select-menu-tab-bucket js-select-menu-tab-bucket" data-tab-filter="branches" role="menu">
|
||||
|
||||
<div data-filterable-for="context-commitish-filter-field" data-filterable-type="substring">
|
||||
|
||||
|
||||
<a class="select-menu-item js-navigation-item js-navigation-open "
|
||||
href="/miloyip/nativejson-benchmark/blob/Stixjson/sample/conformance_Nlohmann%20(C++11).md"
|
||||
data-name="Stixjson"
|
||||
data-skip-pjax="true"
|
||||
rel="nofollow">
|
||||
<svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M12 5l-8 8-4-4 1.5-1.5L4 10l6.5-6.5z"></path></svg>
|
||||
<span class="select-menu-item-text css-truncate-target js-select-menu-filter-text">
|
||||
Stixjson
|
||||
</span>
|
||||
</a>
|
||||
<a class="select-menu-item js-navigation-item js-navigation-open "
|
||||
href="/miloyip/nativejson-benchmark/blob/ccan/sample/conformance_Nlohmann%20(C++11).md"
|
||||
data-name="ccan"
|
||||
data-skip-pjax="true"
|
||||
rel="nofollow">
|
||||
<svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M12 5l-8 8-4-4 1.5-1.5L4 10l6.5-6.5z"></path></svg>
|
||||
<span class="select-menu-item-text css-truncate-target js-select-menu-filter-text">
|
||||
ccan
|
||||
</span>
|
||||
</a>
|
||||
<a class="select-menu-item js-navigation-item js-navigation-open "
|
||||
href="/miloyip/nativejson-benchmark/blob/jbson/sample/conformance_Nlohmann%20(C++11).md"
|
||||
data-name="jbson"
|
||||
data-skip-pjax="true"
|
||||
rel="nofollow">
|
||||
<svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M12 5l-8 8-4-4 1.5-1.5L4 10l6.5-6.5z"></path></svg>
|
||||
<span class="select-menu-item-text css-truncate-target js-select-menu-filter-text">
|
||||
jbson
|
||||
</span>
|
||||
</a>
|
||||
<a class="select-menu-item js-navigation-item js-navigation-open "
|
||||
href="/miloyip/nativejson-benchmark/blob/jute/sample/conformance_Nlohmann%20(C++11).md"
|
||||
data-name="jute"
|
||||
data-skip-pjax="true"
|
||||
rel="nofollow">
|
||||
<svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M12 5l-8 8-4-4 1.5-1.5L4 10l6.5-6.5z"></path></svg>
|
||||
<span class="select-menu-item-text css-truncate-target js-select-menu-filter-text">
|
||||
jute
|
||||
</span>
|
||||
</a>
|
||||
<a class="select-menu-item js-navigation-item js-navigation-open "
|
||||
href="/miloyip/nativejson-benchmark/blob/lastjson/sample/conformance_Nlohmann%20(C++11).md"
|
||||
data-name="lastjson"
|
||||
data-skip-pjax="true"
|
||||
rel="nofollow">
|
||||
<svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M12 5l-8 8-4-4 1.5-1.5L4 10l6.5-6.5z"></path></svg>
|
||||
<span class="select-menu-item-text css-truncate-target js-select-menu-filter-text">
|
||||
lastjson
|
||||
</span>
|
||||
</a>
|
||||
<a class="select-menu-item js-navigation-item js-navigation-open "
|
||||
href="/miloyip/nativejson-benchmark/blob/libjson/sample/conformance_Nlohmann%20(C++11).md"
|
||||
data-name="libjson"
|
||||
data-skip-pjax="true"
|
||||
rel="nofollow">
|
||||
<svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M12 5l-8 8-4-4 1.5-1.5L4 10l6.5-6.5z"></path></svg>
|
||||
<span class="select-menu-item-text css-truncate-target js-select-menu-filter-text">
|
||||
libjson
|
||||
</span>
|
||||
</a>
|
||||
<a class="select-menu-item js-navigation-item js-navigation-open selected"
|
||||
href="/miloyip/nativejson-benchmark/blob/master/sample/conformance_Nlohmann%20(C++11).md"
|
||||
data-name="master"
|
||||
data-skip-pjax="true"
|
||||
rel="nofollow">
|
||||
<svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M12 5l-8 8-4-4 1.5-1.5L4 10l6.5-6.5z"></path></svg>
|
||||
<span class="select-menu-item-text css-truncate-target js-select-menu-filter-text">
|
||||
master
|
||||
</span>
|
||||
</a>
|
||||
<a class="select-menu-item js-navigation-item js-navigation-open "
|
||||
href="/miloyip/nativejson-benchmark/blob/qt/sample/conformance_Nlohmann%20(C++11).md"
|
||||
data-name="qt"
|
||||
data-skip-pjax="true"
|
||||
rel="nofollow">
|
||||
<svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M12 5l-8 8-4-4 1.5-1.5L4 10l6.5-6.5z"></path></svg>
|
||||
<span class="select-menu-item-text css-truncate-target js-select-menu-filter-text">
|
||||
qt
|
||||
</span>
|
||||
</a>
|
||||
<a class="select-menu-item js-navigation-item js-navigation-open "
|
||||
href="/miloyip/nativejson-benchmark/blob/tunnuz/sample/conformance_Nlohmann%20(C++11).md"
|
||||
data-name="tunnuz"
|
||||
data-skip-pjax="true"
|
||||
rel="nofollow">
|
||||
<svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M12 5l-8 8-4-4 1.5-1.5L4 10l6.5-6.5z"></path></svg>
|
||||
<span class="select-menu-item-text css-truncate-target js-select-menu-filter-text">
|
||||
tunnuz
|
||||
</span>
|
||||
</a>
|
||||
<a class="select-menu-item js-navigation-item js-navigation-open "
|
||||
href="/miloyip/nativejson-benchmark/blob/ujson/sample/conformance_Nlohmann%20(C++11).md"
|
||||
data-name="ujson"
|
||||
data-skip-pjax="true"
|
||||
rel="nofollow">
|
||||
<svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M12 5l-8 8-4-4 1.5-1.5L4 10l6.5-6.5z"></path></svg>
|
||||
<span class="select-menu-item-text css-truncate-target js-select-menu-filter-text">
|
||||
ujson
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="select-menu-no-results">Nothing to show</div>
|
||||
</div>
|
||||
|
||||
<div class="select-menu-list select-menu-tab-bucket js-select-menu-tab-bucket" data-tab-filter="tags">
|
||||
<div data-filterable-for="context-commitish-filter-field" data-filterable-type="substring">
|
||||
|
||||
|
||||
<a class="select-menu-item js-navigation-item js-navigation-open "
|
||||
href="/miloyip/nativejson-benchmark/tree/v1.0.0/sample/conformance_Nlohmann%20(C%2B%2B11).md"
|
||||
data-name="v1.0.0"
|
||||
data-skip-pjax="true"
|
||||
rel="nofollow">
|
||||
<svg aria-hidden="true" class="octicon octicon-check select-menu-item-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M12 5l-8 8-4-4 1.5-1.5L4 10l6.5-6.5z"></path></svg>
|
||||
<span class="select-menu-item-text css-truncate-target" title="v1.0.0">
|
||||
v1.0.0
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="select-menu-no-results">Nothing to show</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="btn-group float-right">
|
||||
<a href="/miloyip/nativejson-benchmark/find/master"
|
||||
class="js-pjax-capture-input btn btn-sm"
|
||||
data-pjax
|
||||
data-hotkey="t">
|
||||
Find file
|
||||
</a>
|
||||
<button aria-label="Copy file path to clipboard" class="js-zeroclipboard btn btn-sm zeroclipboard-button tooltipped tooltipped-s" data-copied-hint="Copied!" type="button">Copy path</button>
|
||||
</div>
|
||||
<div class="breadcrumb js-zeroclipboard-target">
|
||||
<span class="repo-root js-repo-root"><span class="js-path-segment"><a href="/miloyip/nativejson-benchmark"><span>nativejson-benchmark</span></a></span></span><span class="separator">/</span><span class="js-path-segment"><a href="/miloyip/nativejson-benchmark/tree/master/sample"><span>sample</span></a></span><span class="separator">/</span><strong class="final-path">conformance_Nlohmann (C++11).md</strong>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="commit-tease">
|
||||
<span class="float-right">
|
||||
<a class="commit-tease-sha" href="/miloyip/nativejson-benchmark/commit/a4a9f10f41c515d6abb0f019ab9f5d021ed4bb9e" data-pjax>
|
||||
a4a9f10
|
||||
</a>
|
||||
<relative-time datetime="2016-09-09T03:15:21Z">Sep 9, 2016</relative-time>
|
||||
</span>
|
||||
<div>
|
||||
<img alt="@miloyip" class="avatar" height="20" src="https://avatars3.githubusercontent.com/u/1195774?v=3&s=40" width="20" />
|
||||
<a href="/miloyip" class="user-mention" rel="author">miloyip</a>
|
||||
<a href="/miloyip/nativejson-benchmark/commit/a4a9f10f41c515d6abb0f019ab9f5d021ed4bb9e" class="message" data-pjax="true" title="Update sample result for 41 libraries
|
||||
|
||||
Fixed #43">Update sample result for 41 libraries</a>
|
||||
</div>
|
||||
|
||||
<div class="commit-tease-contributors">
|
||||
<button type="button" class="btn-link muted-link contributors-toggle" data-facebox="#blob_contributors_box">
|
||||
<strong>1</strong>
|
||||
contributor
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="blob_contributors_box" style="display:none">
|
||||
<h2 class="facebox-header" data-facebox-id="facebox-header">Users who have contributed to this file</h2>
|
||||
<ul class="facebox-user-list" data-facebox-id="facebox-description">
|
||||
<li class="facebox-user-list-item">
|
||||
<img alt="@miloyip" height="24" src="https://avatars1.githubusercontent.com/u/1195774?v=3&s=48" width="24" />
|
||||
<a href="/miloyip">miloyip</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="file">
|
||||
<div class="file-header">
|
||||
<div class="file-actions">
|
||||
|
||||
<div class="btn-group">
|
||||
<a href="/miloyip/nativejson-benchmark/raw/master/sample/conformance_Nlohmann%20(C%2B%2B11).md" class="btn btn-sm " id="raw-url">Raw</a>
|
||||
<a href="/miloyip/nativejson-benchmark/blame/master/sample/conformance_Nlohmann%20(C%2B%2B11).md" class="btn btn-sm js-update-url-with-hash">Blame</a>
|
||||
<a href="/miloyip/nativejson-benchmark/commits/master/sample/conformance_Nlohmann%20(C%2B%2B11).md" class="btn btn-sm " rel="nofollow">History</a>
|
||||
</div>
|
||||
|
||||
|
||||
<button type="button" class="btn-octicon disabled tooltipped tooltipped-nw"
|
||||
aria-label="You must be signed in to make or propose changes">
|
||||
<svg aria-hidden="true" class="octicon octicon-pencil" height="16" version="1.1" viewBox="0 0 14 16" width="14"><path d="M0 12v3h3l8-8-3-3-8 8zm3 2H1v-2h1v1h1v1zm10.3-9.3L12 6 9 3l1.3-1.3a.996.996 0 0 1 1.41 0l1.59 1.59c.39.39.39 1.02 0 1.41z"></path></svg>
|
||||
</button>
|
||||
<button type="button" class="btn-octicon btn-octicon-danger disabled tooltipped tooltipped-nw"
|
||||
aria-label="You must be signed in to make or propose changes">
|
||||
<svg aria-hidden="true" class="octicon octicon-trashcan" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M11 2H9c0-.55-.45-1-1-1H5c-.55 0-1 .45-1 1H2c-.55 0-1 .45-1 1v1c0 .55.45 1 1 1v9c0 .55.45 1 1 1h7c.55 0 1-.45 1-1V5c.55 0 1-.45 1-1V3c0-.55-.45-1-1-1zm-1 12H3V5h1v8h1V5h1v8h1V5h1v8h1V5h1v9zm1-10H2V3h9v1z"></path></svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="file-info">
|
||||
59 lines (37 sloc)
|
||||
<span class="file-info-divider"></span>
|
||||
545 Bytes
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="readme" class="readme blob instapaper_body">
|
||||
<article class="markdown-body entry-content" itemprop="text"><h1><a id="user-content-conformance-of-nlohmann-c11" class="anchor" href="#conformance-of-nlohmann-c11" aria-hidden="true"><svg aria-hidden="true" class="octicon octicon-link" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>Conformance of Nlohmann (C++11)</h1>
|
||||
|
||||
<h2><a id="user-content-1-parse-validation" class="anchor" href="#1-parse-validation" aria-hidden="true"><svg aria-hidden="true" class="octicon octicon-link" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>1. Parse Validation</h2>
|
||||
|
||||
<p>Summary: 34 of 34 are correct.</p>
|
||||
|
||||
<h2><a id="user-content-2-parse-double" class="anchor" href="#2-parse-double" aria-hidden="true"><svg aria-hidden="true" class="octicon octicon-link" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>2. Parse Double</h2>
|
||||
|
||||
<p>Summary: 66 of 66 are correct.</p>
|
||||
|
||||
<h2><a id="user-content-3-parse-string" class="anchor" href="#3-parse-string" aria-hidden="true"><svg aria-hidden="true" class="octicon octicon-link" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>3. Parse String</h2>
|
||||
|
||||
<p>Summary: 9 of 9 are correct.</p>
|
||||
|
||||
<h2><a id="user-content-4-roundtrip" class="anchor" href="#4-roundtrip" aria-hidden="true"><svg aria-hidden="true" class="octicon octicon-link" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"></path></svg></a>4. Roundtrip</h2>
|
||||
|
||||
<ul>
|
||||
<li>Fail:</li>
|
||||
</ul>
|
||||
|
||||
<div class="highlight highlight-source-js"><pre>[<span class="pl-c1">5e-324</span>]</pre></div>
|
||||
|
||||
<div class="highlight highlight-source-js"><pre>[<span class="pl-c1">4.94065645841247e-324</span>]</pre></div>
|
||||
|
||||
<ul>
|
||||
<li>Fail:</li>
|
||||
</ul>
|
||||
|
||||
<div class="highlight highlight-source-js"><pre>[<span class="pl-c1">2.225073858507201e-308</span>]</pre></div>
|
||||
|
||||
<div class="highlight highlight-source-js"><pre>[<span class="pl-c1">2.2250738585072e-308</span>]</pre></div>
|
||||
|
||||
<ul>
|
||||
<li>Fail:</li>
|
||||
</ul>
|
||||
|
||||
<div class="highlight highlight-source-js"><pre>[<span class="pl-c1">2.2250738585072014e-308</span>]</pre></div>
|
||||
|
||||
<div class="highlight highlight-source-js"><pre>[<span class="pl-c1">2.2250738585072e-308</span>]</pre></div>
|
||||
|
||||
<ul>
|
||||
<li>Fail:</li>
|
||||
</ul>
|
||||
|
||||
<div class="highlight highlight-source-js"><pre>[<span class="pl-c1">1.7976931348623157e308</span>]</pre></div>
|
||||
|
||||
<div class="highlight highlight-source-js"><pre>[<span class="pl-c1">1.79769313486232e+308</span>]</pre></div>
|
||||
|
||||
<p>Summary: 23 of 27 are correct.</p>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<button type="button" data-facebox="#jump-to-line" data-facebox-class="linejump" data-hotkey="l" class="d-none">Jump to Line</button>
|
||||
<div id="jump-to-line" style="display:none">
|
||||
<!-- </textarea> --><!-- '"` --><form accept-charset="UTF-8" action="" class="js-jump-to-line-form" method="get"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="✓" /></div>
|
||||
<input class="form-control linejump-input js-jump-to-line-field" type="text" placeholder="Jump to line…" aria-label="Jump to line" autofocus>
|
||||
<button type="submit" class="btn">Go</button>
|
||||
</form></div>
|
||||
|
||||
</div>
|
||||
<div class="modal-backdrop js-touch-events"></div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="container site-footer-container">
|
||||
<div class="site-footer" role="contentinfo">
|
||||
<ul class="site-footer-links float-right">
|
||||
<li><a href="https://github.com/contact" data-ga-click="Footer, go to contact, text:contact">Contact GitHub</a></li>
|
||||
<li><a href="https://developer.github.com" data-ga-click="Footer, go to api, text:api">API</a></li>
|
||||
<li><a href="https://training.github.com" data-ga-click="Footer, go to training, text:training">Training</a></li>
|
||||
<li><a href="https://shop.github.com" data-ga-click="Footer, go to shop, text:shop">Shop</a></li>
|
||||
<li><a href="https://github.com/blog" data-ga-click="Footer, go to blog, text:blog">Blog</a></li>
|
||||
<li><a href="https://github.com/about" data-ga-click="Footer, go to about, text:about">About</a></li>
|
||||
|
||||
</ul>
|
||||
|
||||
<a href="https://github.com" aria-label="Homepage" class="site-footer-mark" title="GitHub">
|
||||
<svg aria-hidden="true" class="octicon octicon-mark-github" height="24" version="1.1" viewBox="0 0 16 16" width="24"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z"></path></svg>
|
||||
</a>
|
||||
<ul class="site-footer-links">
|
||||
<li>© 2016 <span title="0.18611s from github-fe151-cp1-prd.iad.github.net">GitHub</span>, Inc.</li>
|
||||
<li><a href="https://github.com/site/terms" data-ga-click="Footer, go to terms, text:terms">Terms</a></li>
|
||||
<li><a href="https://github.com/site/privacy" data-ga-click="Footer, go to privacy, text:privacy">Privacy</a></li>
|
||||
<li><a href="https://github.com/security" data-ga-click="Footer, go to security, text:security">Security</a></li>
|
||||
<li><a href="https://status.github.com/" data-ga-click="Footer, go to status, text:status">Status</a></li>
|
||||
<li><a href="https://help.github.com" data-ga-click="Footer, go to help, text:help">Help</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div id="ajax-error-message" class="ajax-error-message flash flash-error">
|
||||
<svg aria-hidden="true" class="octicon octicon-alert" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M8.865 1.52c-.18-.31-.51-.5-.87-.5s-.69.19-.87.5L.275 13.5c-.18.31-.18.69 0 1 .19.31.52.5.87.5h13.7c.36 0 .69-.19.86-.5.17-.31.18-.69.01-1L8.865 1.52zM8.995 13h-2v-2h2v2zm0-3h-2V6h2v4z"></path></svg>
|
||||
<button type="button" class="flash-close js-flash-close js-ajax-error-dismiss" aria-label="Dismiss error">
|
||||
<svg aria-hidden="true" class="octicon octicon-x" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M7.48 8l3.75 3.75-1.48 1.48L6 9.48l-3.75 3.75-1.48-1.48L4.52 8 .77 4.25l1.48-1.48L6 6.52l3.75-3.75 1.48 1.48z"></path></svg>
|
||||
</button>
|
||||
You can't perform that action at this time.
|
||||
</div>
|
||||
|
||||
|
||||
<script crossorigin="anonymous" src="https://assets-cdn.github.com/assets/compat-40e365359d1c4db1e36a55be458e60f2b7c24d58b5a00ae13398480e7ba768e0.js"></script>
|
||||
<script crossorigin="anonymous" src="https://assets-cdn.github.com/assets/frameworks-88471af1fec40ff9418efbe2ddd15b6896af8d772f8179004c254dffc25ea490.js"></script>
|
||||
<script async="async" crossorigin="anonymous" src="https://assets-cdn.github.com/assets/github-e18e11a943ff2eb9394c72d4ec8b76592c454915b5839ae177d422777a046e29.js"></script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="js-stale-session-flash stale-session-flash flash flash-warn flash-banner d-none">
|
||||
<svg aria-hidden="true" class="octicon octicon-alert" height="16" version="1.1" viewBox="0 0 16 16" width="16"><path d="M8.865 1.52c-.18-.31-.51-.5-.87-.5s-.69.19-.87.5L.275 13.5c-.18.31-.18.69 0 1 .19.31.52.5.87.5h13.7c.36 0 .69-.19.86-.5.17-.31.18-.69.01-1L8.865 1.52zM8.995 13h-2v-2h2v2zm0-3h-2V6h2v4z"></path></svg>
|
||||
<span class="signed-in-tab-flash">You signed in with another tab or window. <a href="">Reload</a> to refresh your session.</span>
|
||||
<span class="signed-out-tab-flash">You signed out in another tab or window. <a href="">Reload</a> to refresh your session.</span>
|
||||
</div>
|
||||
<div class="facebox" id="facebox" style="display:none;">
|
||||
<div class="facebox-popup">
|
||||
<div class="facebox-content" role="dialog" aria-labelledby="facebox-header" aria-describedby="facebox-description">
|
||||
</div>
|
||||
<button type="button" class="facebox-close js-facebox-close" aria-label="Close modal">
|
||||
<svg aria-hidden="true" class="octicon octicon-x" height="16" version="1.1" viewBox="0 0 12 16" width="12"><path d="M7.48 8l3.75 3.75-1.48 1.48L6 9.48l-3.75 3.75-1.48-1.48L4.52 8 .77 4.25l1.48-1.48L6 6.52l3.75-3.75 1.48 1.48z"></path></svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
Before Width: | Height: | Size: 166 KiB |
|
Before Width: | Height: | Size: 192 KiB |
|
Before Width: | Height: | Size: 146 KiB |
|
Before Width: | Height: | Size: 136 KiB |
|
Before Width: | Height: | Size: 98 KiB |
|
Before Width: | Height: | Size: 182 KiB |
|
Before Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 22 KiB |
@@ -1,10 +0,0 @@
|
||||
<table style="font-family: 'Trebuchet MS', 'Tahoma', 'Arial', 'Helvetica'">
|
||||
<tr><td style="width: 18ex"><b>Banner:</b></td><td>fuzz</td></tr>
|
||||
<tr><td><b>Directory:</b></td><td>fuzz-testing/out</td></tr>
|
||||
<tr><td><b>Generated on:</b></td><td>Sun Oct 2 08:51:02 CEST 2016</td></tr>
|
||||
</table>
|
||||
<p>
|
||||
<img src="high_freq.png" width=1000 height=300><p>
|
||||
<img src="low_freq.png" width=1000 height=200><p>
|
||||
<img src="exec_speed.png" width=1000 height=200>
|
||||
|
||||
|
Before Width: | Height: | Size: 14 KiB |
@@ -0,0 +1,99 @@
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++ (supporting code)
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
namespace utils
|
||||
{
|
||||
/// a SAX event consumer that stops accepting events after a fixed count,
|
||||
/// used by the binary-format tests to check behavior when the SAX consumer
|
||||
/// rejects an event partway through parsing
|
||||
class SaxCountdown
|
||||
{
|
||||
public:
|
||||
using json = nlohmann::json;
|
||||
|
||||
explicit SaxCountdown(const int count) : events_left(count)
|
||||
{}
|
||||
|
||||
bool null()
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool boolean(bool /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool number_integer(json::number_integer_t /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool number_unsigned(json::number_unsigned_t /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool number_float(json::number_float_t /*unused*/, const std::string& /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool string(std::string& /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool binary(std::vector<std::uint8_t>& /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool start_object(std::size_t /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool key(std::string& /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool end_object()
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool start_array(std::size_t /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool end_array()
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const json::exception& /*unused*/) // NOLINT(readability-convert-member-functions-to-static)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
int events_left = 0;
|
||||
};
|
||||
} // namespace utils
|
||||
@@ -12,80 +12,11 @@
|
||||
using nlohmann::json;
|
||||
|
||||
#include <climits> // SIZE_MAX
|
||||
#include <limits> // numeric_limits
|
||||
|
||||
template <typename OfType, typename T, bool MinInRange, bool MaxInRange>
|
||||
struct trait_test_arg
|
||||
{
|
||||
using of_type = OfType;
|
||||
using type = T;
|
||||
static constexpr bool min_in_range = MinInRange;
|
||||
static constexpr bool max_in_range = MaxInRange;
|
||||
};
|
||||
|
||||
TEST_CASE_TEMPLATE_DEFINE("value_in_range_of trait", T, value_in_range_of_test) // NOLINT(readability-math-missing-parentheses)
|
||||
{
|
||||
using nlohmann::detail::value_in_range_of;
|
||||
|
||||
using of_type = typename T::of_type;
|
||||
using type = typename T::type;
|
||||
constexpr bool min_in_range = T::min_in_range;
|
||||
constexpr bool max_in_range = T::max_in_range;
|
||||
|
||||
type const val_min = std::numeric_limits<type>::min();
|
||||
type const val_min2 = val_min + 1;
|
||||
type const val_max = std::numeric_limits<type>::max();
|
||||
type const val_max2 = val_max - 1;
|
||||
|
||||
REQUIRE(CHAR_BIT == 8);
|
||||
|
||||
std::string of_type_str;
|
||||
if (std::is_unsigned<of_type>::value)
|
||||
{
|
||||
of_type_str += "u";
|
||||
}
|
||||
of_type_str += "int";
|
||||
of_type_str += std::to_string(sizeof(of_type) * 8);
|
||||
|
||||
INFO("of_type := ", of_type_str);
|
||||
|
||||
std::string type_str;
|
||||
if (std::is_unsigned<type>::value)
|
||||
{
|
||||
type_str += "u";
|
||||
}
|
||||
type_str += "int";
|
||||
type_str += std::to_string(sizeof(type) * 8);
|
||||
|
||||
INFO("type := ", type_str);
|
||||
|
||||
CAPTURE(val_min);
|
||||
CAPTURE(min_in_range);
|
||||
CAPTURE(val_max);
|
||||
CAPTURE(max_in_range);
|
||||
|
||||
if (min_in_range)
|
||||
{
|
||||
CHECK(value_in_range_of<of_type>(val_min));
|
||||
CHECK(value_in_range_of<of_type>(val_min2));
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK_FALSE(value_in_range_of<of_type>(val_min));
|
||||
CHECK_FALSE(value_in_range_of<of_type>(val_min2));
|
||||
}
|
||||
|
||||
if (max_in_range)
|
||||
{
|
||||
CHECK(value_in_range_of<of_type>(val_max));
|
||||
CHECK(value_in_range_of<of_type>(val_max2));
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK_FALSE(value_in_range_of<of_type>(val_max));
|
||||
CHECK_FALSE(value_in_range_of<of_type>(val_max2));
|
||||
}
|
||||
}
|
||||
// JSON_32bitTest=ONLY builds only this file, so it must keep its own
|
||||
// include of the shared trait/TEST_CASE_TEMPLATE_DEFINE rather than relying
|
||||
// on unit-bjdata.cpp to provide it
|
||||
#include "value_in_range_of_test.hpp"
|
||||
|
||||
TEST_CASE("32bit")
|
||||
{
|
||||
|
||||
@@ -21,158 +21,13 @@ using nlohmann::json;
|
||||
#include "make_test_data_available.hpp"
|
||||
#include "round_trip_corpus.hpp"
|
||||
#include "test_utils.hpp"
|
||||
#include "sax_countdown.hpp"
|
||||
using utils::SaxCountdown;
|
||||
|
||||
namespace
|
||||
{
|
||||
class SaxCountdown
|
||||
{
|
||||
public:
|
||||
explicit SaxCountdown(const int count) : events_left(count)
|
||||
{}
|
||||
|
||||
bool null()
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool boolean(bool /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool number_integer(json::number_integer_t /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool number_unsigned(json::number_unsigned_t /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool number_float(json::number_float_t /*unused*/, const std::string& /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool string(std::string& /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool binary(std::vector<std::uint8_t>& /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool start_object(std::size_t /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool key(std::string& /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool end_object()
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool start_array(std::size_t /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool end_array()
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const json::exception& /*unused*/) // NOLINT(readability-convert-member-functions-to-static)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
int events_left = 0;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
// at some point in the future, a unit test dedicated to type traits might be a good idea
|
||||
template <typename OfType, typename T, bool MinInRange, bool MaxInRange>
|
||||
struct trait_test_arg
|
||||
{
|
||||
using of_type = OfType;
|
||||
using type = T;
|
||||
static constexpr bool min_in_range = MinInRange;
|
||||
static constexpr bool max_in_range = MaxInRange;
|
||||
};
|
||||
|
||||
TEST_CASE_TEMPLATE_DEFINE("value_in_range_of trait", T, value_in_range_of_test) // NOLINT(readability-math-missing-parentheses)
|
||||
{
|
||||
using nlohmann::detail::value_in_range_of;
|
||||
|
||||
using of_type = typename T::of_type;
|
||||
using type = typename T::type;
|
||||
constexpr bool min_in_range = T::min_in_range;
|
||||
constexpr bool max_in_range = T::max_in_range;
|
||||
|
||||
type const val_min = std::numeric_limits<type>::min();
|
||||
type const val_min2 = val_min + 1;
|
||||
type const val_max = std::numeric_limits<type>::max();
|
||||
type const val_max2 = val_max - 1;
|
||||
|
||||
REQUIRE(CHAR_BIT == 8);
|
||||
|
||||
std::string of_type_str;
|
||||
if (std::is_unsigned<of_type>::value)
|
||||
{
|
||||
of_type_str += "u";
|
||||
}
|
||||
of_type_str += "int";
|
||||
of_type_str += std::to_string(sizeof(of_type) * 8);
|
||||
|
||||
INFO("of_type := ", of_type_str);
|
||||
|
||||
std::string type_str;
|
||||
if (std::is_unsigned<type>::value)
|
||||
{
|
||||
type_str += "u";
|
||||
}
|
||||
type_str += "int";
|
||||
type_str += std::to_string(sizeof(type) * 8);
|
||||
|
||||
INFO("type := ", type_str);
|
||||
|
||||
CAPTURE(val_min);
|
||||
CAPTURE(min_in_range);
|
||||
CAPTURE(val_max);
|
||||
CAPTURE(max_in_range);
|
||||
|
||||
if (min_in_range)
|
||||
{
|
||||
CHECK(value_in_range_of<of_type>(val_min));
|
||||
CHECK(value_in_range_of<of_type>(val_min2));
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK_FALSE(value_in_range_of<of_type>(val_min));
|
||||
CHECK_FALSE(value_in_range_of<of_type>(val_min2));
|
||||
}
|
||||
|
||||
if (max_in_range)
|
||||
{
|
||||
CHECK(value_in_range_of<of_type>(val_max));
|
||||
CHECK(value_in_range_of<of_type>(val_max2));
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK_FALSE(value_in_range_of<of_type>(val_max));
|
||||
CHECK_FALSE(value_in_range_of<of_type>(val_max2));
|
||||
}
|
||||
}
|
||||
// trait_test_arg and the "value_in_range_of trait" TEST_CASE_TEMPLATE_DEFINE
|
||||
// are shared with unit-32bit.cpp
|
||||
#include "value_in_range_of_test.hpp"
|
||||
|
||||
// NOLINTNEXTLINE(bugprone-throwing-static-initialization)
|
||||
TEST_CASE_TEMPLATE_INVOKE(value_in_range_of_test, \
|
||||
|
||||
@@ -22,84 +22,11 @@ using nlohmann::json;
|
||||
#include <vector>
|
||||
#include "make_test_data_available.hpp"
|
||||
#include "test_utils.hpp"
|
||||
#include "sax_countdown.hpp"
|
||||
using utils::SaxCountdown;
|
||||
|
||||
namespace
|
||||
{
|
||||
class SaxCountdown
|
||||
{
|
||||
public:
|
||||
explicit SaxCountdown(const int count) : events_left(count)
|
||||
{}
|
||||
|
||||
bool null()
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool boolean(bool /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool number_integer(json::number_integer_t /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool number_unsigned(json::number_unsigned_t /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool number_float(json::number_float_t /*unused*/, const std::string& /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool string(std::string& /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool binary(std::vector<std::uint8_t>& /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool start_object(std::size_t /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool key(std::string& /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool end_object()
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool start_array(std::size_t /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool end_array()
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const json::exception& /*unused*/) // NOLINT(readability-convert-member-functions-to-static)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
int events_left = 0;
|
||||
};
|
||||
|
||||
using bytes = std::vector<std::uint8_t>;
|
||||
|
||||
/// @return the string with the given bytes
|
||||
|
||||
@@ -18,6 +18,8 @@ using nlohmann::json;
|
||||
#include <vector>
|
||||
#include "make_test_data_available.hpp"
|
||||
#include "test_utils.hpp"
|
||||
#include "sax_countdown.hpp"
|
||||
using utils::SaxCountdown;
|
||||
|
||||
namespace
|
||||
{
|
||||
@@ -857,83 +859,6 @@ TEST_CASE("BSON input/output_adapters")
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
class SaxCountdown
|
||||
{
|
||||
public:
|
||||
explicit SaxCountdown(const int count) : events_left(count)
|
||||
{}
|
||||
|
||||
bool null()
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool boolean(bool /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool number_integer(json::number_integer_t /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool number_unsigned(json::number_unsigned_t /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool number_float(json::number_float_t /*unused*/, const std::string& /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool string(std::string& /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool binary(std::vector<std::uint8_t>& /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool start_object(std::size_t /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool key(std::string& /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool end_object()
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool start_array(std::size_t /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool end_array()
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const json::exception& /*unused*/) // NOLINT(readability-convert-member-functions-to-static)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
int events_left = 0;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("Incomplete BSON Input")
|
||||
{
|
||||
|
||||
@@ -19,84 +19,9 @@ using nlohmann::json;
|
||||
#include <set>
|
||||
#include "make_test_data_available.hpp"
|
||||
#include "test_utils.hpp"
|
||||
#include "sax_countdown.hpp"
|
||||
using utils::SaxCountdown;
|
||||
|
||||
namespace
|
||||
{
|
||||
class SaxCountdown
|
||||
{
|
||||
public:
|
||||
explicit SaxCountdown(const int count) : events_left(count)
|
||||
{}
|
||||
|
||||
bool null()
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool boolean(bool /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool number_integer(json::number_integer_t /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool number_unsigned(json::number_unsigned_t /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool number_float(json::number_float_t /*unused*/, const std::string& /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool string(std::string& /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool binary(std::vector<std::uint8_t>& /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool start_object(std::size_t /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool key(std::string& /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool end_object()
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool start_array(std::size_t /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool end_array()
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const json::exception& /*unused*/) // NOLINT(readability-convert-member-functions-to-static)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
int events_left = 0;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("CBOR")
|
||||
{
|
||||
@@ -2774,33 +2699,21 @@ TEST_CASE("examples from RFC 8949 Appendix A")
|
||||
CHECK(json::to_cbor(json::parse("1.1")) == std::vector<uint8_t>({0xfb, 0x3f, 0xf1, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9a}));
|
||||
CHECK(json::parse("1.1") == json::from_cbor(std::vector<uint8_t>({0xfb, 0x3f, 0xf1, 0x99, 0x99, 0x99, 0x99, 0x99, 0x9a})));
|
||||
|
||||
// half-precision float
|
||||
//CHECK(json::to_cbor(json::parse("1.5")) == std::vector<uint8_t>({0xf9, 0x3e, 0x00}));
|
||||
// the writer never emits half-precision floats, so these can only be decoded, not encoded
|
||||
CHECK(json::parse("1.5") == json::from_cbor(std::vector<uint8_t>({0xf9, 0x3e, 0x00})));
|
||||
|
||||
// half-precision float
|
||||
//CHECK(json::to_cbor(json::parse("65504.0")) == std::vector<uint8_t>({0xf9, 0x7b, 0xff}));
|
||||
CHECK(json::parse("65504.0") == json::from_cbor(std::vector<uint8_t>({0xf9, 0x7b, 0xff})));
|
||||
|
||||
//CHECK(json::to_cbor(json::parse("100000.0")) == std::vector<uint8_t>({0xfa, 0x47, 0xc3, 0x50, 0x00}));
|
||||
CHECK(json::to_cbor(json::parse("100000.0")) == std::vector<uint8_t>({0xfa, 0x47, 0xc3, 0x50, 0x00}));
|
||||
CHECK(json::parse("100000.0") == json::from_cbor(std::vector<uint8_t>({0xfa, 0x47, 0xc3, 0x50, 0x00})));
|
||||
|
||||
//CHECK(json::to_cbor(json::parse("3.4028234663852886e+38")) == std::vector<uint8_t>({0xfa, 0x7f, 0x7f, 0xff, 0xff}));
|
||||
CHECK(json::to_cbor(json::parse("3.4028234663852886e+38")) == std::vector<uint8_t>({0xfa, 0x7f, 0x7f, 0xff, 0xff}));
|
||||
CHECK(json::parse("3.4028234663852886e+38") == json::from_cbor(std::vector<uint8_t>({0xfa, 0x7f, 0x7f, 0xff, 0xff})));
|
||||
|
||||
CHECK(json::to_cbor(json::parse("1.0e+300")) == std::vector<uint8_t>({0xfb, 0x7e, 0x37, 0xe4, 0x3c, 0x88, 0x00, 0x75, 0x9c}));
|
||||
CHECK(json::parse("1.0e+300") == json::from_cbor(std::vector<uint8_t>({0xfb, 0x7e, 0x37, 0xe4, 0x3c, 0x88, 0x00, 0x75, 0x9c})));
|
||||
|
||||
// half-precision float
|
||||
//CHECK(json::to_cbor(json::parse("5.960464477539063e-8")) == std::vector<uint8_t>({0xf9, 0x00, 0x01}));
|
||||
CHECK(json::parse("-4.0") == json::from_cbor(std::vector<uint8_t>({0xf9, 0xc4, 0x00})));
|
||||
|
||||
// half-precision float
|
||||
//CHECK(json::to_cbor(json::parse("0.00006103515625")) == std::vector<uint8_t>({0xf9, 0x04, 0x00}));
|
||||
CHECK(json::parse("-4.0") == json::from_cbor(std::vector<uint8_t>({0xf9, 0xc4, 0x00})));
|
||||
|
||||
// half-precision float
|
||||
//CHECK(json::to_cbor(json::parse("-4.0")) == std::vector<uint8_t>({0xf9, 0xc4, 0x00}));
|
||||
CHECK(json::parse("5.960464477539063e-8") == json::from_cbor(std::vector<uint8_t>({0xf9, 0x00, 0x01})));
|
||||
CHECK(json::parse("0.00006103515625") == json::from_cbor(std::vector<uint8_t>({0xf9, 0x04, 0x00})));
|
||||
CHECK(json::parse("-4.0") == json::from_cbor(std::vector<uint8_t>({0xf9, 0xc4, 0x00})));
|
||||
|
||||
CHECK(json::to_cbor(json::parse("-4.1")) == std::vector<uint8_t>({0xfb, 0xc0, 0x10, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66}));
|
||||
|
||||
@@ -12,15 +12,10 @@
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
|
||||
#include <array> // array
|
||||
#include <cfloat> // FLT_EVAL_METHOD
|
||||
#include <cstdint> // uint32_t, uint64_t
|
||||
#include <cstdlib> // strtod
|
||||
#include <cstring> // memcpy
|
||||
#include <random> // mt19937
|
||||
#include <sstream> // stringstream
|
||||
#include <string> // string
|
||||
#include <utility> // pair
|
||||
#include <vector> // vector
|
||||
|
||||
namespace
|
||||
@@ -664,184 +659,6 @@ TEST_CASE("lexer string fast path")
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("lexer escape fast path")
|
||||
{
|
||||
// json::accept() never throws, so this section stays covered without
|
||||
// exceptions; it pins which of the cases below are valid/invalid and
|
||||
// checks the contiguous and streaming paths agree on that classification.
|
||||
SECTION("accept() parity")
|
||||
{
|
||||
const std::vector<std::pair<std::string, bool>> cases =
|
||||
{
|
||||
{"\\u0041", true}, {"\\u00e4", true}, {"\\u00E4", true},
|
||||
{"\\uD83D\\uDE00", true},
|
||||
{"\\u12", false}, {"\\u12G4", false}, {"\\uXYZW", false},
|
||||
{"\\uD800", false}, {"\\uD800A", false}, {"\\uD800\\u0041", false},
|
||||
{"\\uDC00", false}, {"\\u", false}
|
||||
};
|
||||
|
||||
for (const auto& c : cases)
|
||||
{
|
||||
for (const std::size_t offset :
|
||||
{
|
||||
std::size_t{0}, std::size_t{9}
|
||||
})
|
||||
{
|
||||
const std::string doc = "[\"" + std::string(offset, 'a') + c.first + "\"]";
|
||||
CAPTURE(doc);
|
||||
CHECK(json::accept(doc) == c.second);
|
||||
std::stringstream ss(doc);
|
||||
CHECK(json::accept(ss) == c.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(JSON_NOEXCEPTION)
|
||||
// the full outcome of parsing @a doc: the parsed value, or the exact
|
||||
// error message, so a mismatch in either is caught
|
||||
const auto outcome = [](const std::string & doc, bool streaming) -> std::string
|
||||
{
|
||||
try
|
||||
{
|
||||
if (streaming)
|
||||
{
|
||||
std::stringstream ss(doc);
|
||||
const json j = json::parse(ss);
|
||||
return j.dump();
|
||||
}
|
||||
const json j = json::parse(doc);
|
||||
return j.dump();
|
||||
}
|
||||
catch (const json::exception& e)
|
||||
{
|
||||
return {e.what()};
|
||||
}
|
||||
};
|
||||
|
||||
SECTION("contiguous vs streaming parity")
|
||||
{
|
||||
const std::vector<std::string> escapes =
|
||||
{
|
||||
"\\u0041", // "A"
|
||||
"\\u00e4", // "ä" (lowercase hex)
|
||||
"\\u00E4", // "ä" (uppercase hex)
|
||||
"\\uD83D\\uDE00", // valid surrogate pair (an emoji)
|
||||
"\\u12", // truncated: only 2 hex digits before the closing quote
|
||||
"\\u12G4", // invalid hex digit at the 3rd position
|
||||
"\\uXYZW", // all 4 bytes invalid
|
||||
"\\uD800", // lone high surrogate, string ends right after
|
||||
"\\uD800A", // high surrogate not followed by another \u escape
|
||||
"\\uD800\\u0041", // high surrogate followed by \u, but not a low surrogate
|
||||
"\\uDC00", // lone low surrogate
|
||||
"\\u", // '\u' with nothing after (closing quote right away)
|
||||
};
|
||||
|
||||
// once at the start of the string and once past the first 8-byte SWAR
|
||||
// word of the outer string_bulk_run, so the escape is reached both
|
||||
// right after the opening quote and mid-run
|
||||
for (const auto& escape : escapes)
|
||||
{
|
||||
for (const std::size_t offset :
|
||||
{
|
||||
std::size_t{0}, std::size_t{9}
|
||||
})
|
||||
{
|
||||
const std::string doc = "[\"" + std::string(offset, 'a') + escape + "\"]";
|
||||
CAPTURE(doc);
|
||||
CHECK(outcome(doc, false) == outcome(doc, true));
|
||||
}
|
||||
|
||||
// the escape is the last thing before end of input: no closing
|
||||
// quote at all
|
||||
const std::string truncated_doc = "[\"" + escape;
|
||||
CAPTURE(truncated_doc);
|
||||
CHECK(outcome(truncated_doc, false) == outcome(truncated_doc, true));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("truncated \\u escape at every distance from the end of input")
|
||||
{
|
||||
// ia.bulk_remaining() must correctly report fewer than 4 bytes for
|
||||
// every possible count of trailing hex-looking bytes (0, 1, 2, or 3)
|
||||
// before end of input, so the fast path declines and the byte path
|
||||
// alone reports the "must be followed by 4 hex digits" error, at the
|
||||
// same position, in every case
|
||||
for (const std::string& tail :
|
||||
{
|
||||
std::string{}, std::string("1"), std::string("12"), std::string("123")
|
||||
})
|
||||
{
|
||||
const std::string doc = "[\"\\u" + tail;
|
||||
CAPTURE(doc);
|
||||
CHECK(outcome(doc, false) == outcome(doc, true));
|
||||
CHECK(outcome(doc, false).find("must be followed by 4 hex digits") != std::string::npos);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("invalid hex digit at every position of the 4")
|
||||
{
|
||||
// the fast path must decline for *any* invalid byte among the 4, not
|
||||
// just the first, and the byte path must then stop at exactly that
|
||||
// position - same as it always has
|
||||
for (std::size_t bad_pos = 0; bad_pos < 4; ++bad_pos)
|
||||
{
|
||||
std::string digits = "1234";
|
||||
digits[bad_pos] = 'g'; // not a hex digit
|
||||
const std::string doc = "[\"\\u" + digits + "\"]";
|
||||
CAPTURE(doc);
|
||||
CHECK(outcome(doc, false) == outcome(doc, true));
|
||||
CHECK(outcome(doc, false).find("must be followed by 4 hex digits") != std::string::npos);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("random escapes")
|
||||
{
|
||||
// A seeded PRNG builds the 4 bytes following `\u` from a mix of hex
|
||||
// digits and non-hex bytes, at varying distances from the start of
|
||||
// the string, to compare the two scanners on many more shapes than
|
||||
// are practical to enumerate by hand.
|
||||
std::mt19937 gen(7654321); // NOLINT(cert-msc32-c,cert-msc51-cpp)
|
||||
const std::string hex_alphabet = "0123456789AaBbCcDdEeFf";
|
||||
std::uniform_int_distribution<std::size_t> pick_hex(0, hex_alphabet.size() - 1);
|
||||
std::uniform_int_distribution<int> pick_byte(1, 255); // never NUL
|
||||
std::uniform_int_distribution<int> pick_is_hex(0, 4); // 4-in-5 chance of a hex digit
|
||||
std::uniform_int_distribution<std::size_t> pick_offset(0, 12);
|
||||
|
||||
std::vector<std::string> mismatches;
|
||||
for (int iter = 0; iter < 3000; ++iter)
|
||||
{
|
||||
std::string digits;
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
if (pick_is_hex(gen) != 0)
|
||||
{
|
||||
digits += hex_alphabet[pick_hex(gen)];
|
||||
}
|
||||
else
|
||||
{
|
||||
char c = static_cast<char>(pick_byte(gen));
|
||||
if (c == '"' || c == '\\')
|
||||
{
|
||||
// keep the string well-formed apart from the escape
|
||||
// itself, so any mismatch is attributable to the \u
|
||||
// handling and not to an unrelated quote/escape
|
||||
c = 'z';
|
||||
}
|
||||
digits += c;
|
||||
}
|
||||
}
|
||||
const std::string doc = "[\"" + std::string(pick_offset(gen), 'a') + "\\u" + digits + "\"]";
|
||||
if (outcome(doc, false) != outcome(doc, true))
|
||||
{
|
||||
mismatches.push_back(doc);
|
||||
}
|
||||
}
|
||||
CAPTURE(mismatches);
|
||||
CHECK(mismatches.empty());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("parse_float_fast declines what it cannot convert exactly")
|
||||
{
|
||||
// The lexer only hands well-formed numbers to parse_float_fast, so the
|
||||
@@ -883,715 +700,3 @@ TEST_CASE("parse_float_fast declines what it cannot convert exactly")
|
||||
CHECK_FALSE(fast("1e23", out));
|
||||
CHECK_FALSE(fast("1e-23", out));
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
// arbitrary-precision unsigned integers, just enough to recompute the table of
|
||||
// powers of five (little-endian 32-bit limbs)
|
||||
using big_uint = std::vector<std::uint32_t>;
|
||||
|
||||
void big_trim(big_uint& a)
|
||||
{
|
||||
while (!a.empty() && a.back() == 0)
|
||||
{
|
||||
a.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
big_uint big_from(std::uint64_t high, std::uint64_t low)
|
||||
{
|
||||
big_uint a = {static_cast<std::uint32_t>(low), static_cast<std::uint32_t>(low >> 32u),
|
||||
static_cast<std::uint32_t>(high), static_cast<std::uint32_t>(high >> 32u)
|
||||
};
|
||||
big_trim(a);
|
||||
return a;
|
||||
}
|
||||
|
||||
big_uint big_mul(const big_uint& a, const big_uint& b)
|
||||
{
|
||||
big_uint r(a.size() + b.size(), 0);
|
||||
for (std::size_t i = 0; i < a.size(); ++i)
|
||||
{
|
||||
std::uint64_t carry = 0;
|
||||
for (std::size_t j = 0; j < b.size(); ++j)
|
||||
{
|
||||
const std::uint64_t t = (static_cast<std::uint64_t>(a[i]) * b[j]) + r[i + j] + carry;
|
||||
r[i + j] = static_cast<std::uint32_t>(t);
|
||||
carry = t >> 32u;
|
||||
}
|
||||
r[i + b.size()] = static_cast<std::uint32_t>(carry);
|
||||
}
|
||||
big_trim(r);
|
||||
return r;
|
||||
}
|
||||
|
||||
big_uint big_shl(const big_uint& a, std::size_t s)
|
||||
{
|
||||
big_uint r(s / 32, 0);
|
||||
std::uint32_t carry = 0;
|
||||
for (const std::uint32_t x : a)
|
||||
{
|
||||
const std::uint64_t t = static_cast<std::uint64_t>(x) << (s % 32);
|
||||
r.push_back(static_cast<std::uint32_t>(t) | carry);
|
||||
carry = static_cast<std::uint32_t>(t >> 32u);
|
||||
}
|
||||
r.push_back(carry);
|
||||
big_trim(r);
|
||||
return r;
|
||||
}
|
||||
|
||||
// a + 1 (add) or a - 1 (!add, a > 0)
|
||||
big_uint big_step(big_uint a, bool add)
|
||||
{
|
||||
for (auto& x : a)
|
||||
{
|
||||
const std::uint32_t old = x;
|
||||
x = add ? x + 1 : x - 1;
|
||||
if ((add && x > old) || (!add && x < old))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (add && (a.empty() || a.back() == 0))
|
||||
{
|
||||
a.push_back(1);
|
||||
}
|
||||
big_trim(a);
|
||||
return a;
|
||||
}
|
||||
|
||||
bool big_less_equal(const big_uint& a, const big_uint& b)
|
||||
{
|
||||
if (a.size() != b.size())
|
||||
{
|
||||
return a.size() < b.size();
|
||||
}
|
||||
for (std::size_t i = a.size(); i-- > 0;)
|
||||
{
|
||||
if (a[i] != b[i])
|
||||
{
|
||||
return a[i] < b[i];
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::size_t big_bit_length(const big_uint& a)
|
||||
{
|
||||
std::size_t n = a.size() * 32;
|
||||
for (std::uint32_t top = a.back(); (top & 0x80000000u) == 0; top <<= 1u)
|
||||
{
|
||||
--n;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
std::uint64_t bits_of(double d)
|
||||
{
|
||||
std::uint64_t b = 0;
|
||||
std::memcpy(&b, &d, sizeof(b));
|
||||
return b;
|
||||
}
|
||||
|
||||
bool eisel_lemire(const std::string& s, double& out)
|
||||
{
|
||||
return nlohmann::detail::parse_float_eisel_lemire(s.data(), s.data() + s.size(), out);
|
||||
}
|
||||
|
||||
// significant digits of a token, without trailing zeros
|
||||
std::size_t significant_digits(const std::string& s)
|
||||
{
|
||||
std::string digits;
|
||||
for (const char c : s)
|
||||
{
|
||||
if (c == 'e' || c == 'E')
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (c >= '0' && c <= '9' && !(digits.empty() && c == '0'))
|
||||
{
|
||||
digits += c;
|
||||
}
|
||||
}
|
||||
while (!digits.empty() && digits.back() == '0')
|
||||
{
|
||||
digits.pop_back();
|
||||
}
|
||||
return digits.size();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("Eisel-Lemire float conversion")
|
||||
{
|
||||
SECTION("the table of powers of five")
|
||||
{
|
||||
// Recompute every entry the way fast_float's table_generation.py
|
||||
// defines it, using only multiplications and comparisons: for q >= 0
|
||||
// the most significant 128 bits of 5^q; for q < 0 floor(2^b / 5^-q) + 1
|
||||
// for b = z + 127 (q >= -27), or that value for b = 2z + 128 cut to
|
||||
// its most significant 128 bits (q < -27), where z is the bit length
|
||||
// of 5^-q.
|
||||
const auto& table = nlohmann::detail::pow5_128();
|
||||
big_uint power5 = {1};
|
||||
for (std::int64_t q = 0; q <= nlohmann::detail::pow5_128_largest_power; ++q)
|
||||
{
|
||||
const auto index = static_cast<std::size_t>(2 * (q - nlohmann::detail::pow5_128_smallest_power));
|
||||
const big_uint entry = big_from(table[index], table[index + 1]);
|
||||
const std::size_t bits = big_bit_length(power5);
|
||||
if (bits <= 128)
|
||||
{
|
||||
CHECK(entry == big_shl(power5, 128 - bits));
|
||||
}
|
||||
else
|
||||
{
|
||||
// floor(5^q / 2^(bits - 128))
|
||||
CHECK(big_less_equal(big_shl(entry, bits - 128), power5));
|
||||
CHECK_FALSE(big_less_equal(big_shl(big_step(entry, true), bits - 128), power5));
|
||||
}
|
||||
power5 = big_mul(power5, {5});
|
||||
}
|
||||
|
||||
power5 = {5};
|
||||
for (std::int64_t q = -1; q >= nlohmann::detail::pow5_128_smallest_power; --q)
|
||||
{
|
||||
const auto index = static_cast<std::size_t>(2 * (q - nlohmann::detail::pow5_128_smallest_power));
|
||||
const big_uint entry = big_from(table[index], table[index + 1]);
|
||||
CHECK(big_bit_length(entry) == 128);
|
||||
const std::size_t z = big_bit_length(power5);
|
||||
const big_uint two_b = big_shl({1}, q >= -27 ? z + 127 : (2 * z) + 128);
|
||||
// c = floor(2^b / p) + 1, stored as floor(c / 2^s):
|
||||
// (entry * 2^s - 1) * p <= 2^b < ((entry + 1) * 2^s - 1) * p
|
||||
const std::size_t s = q >= -27 ? 0 : z + 1;
|
||||
CHECK(big_less_equal(big_mul(big_step(big_shl(entry, s), false), power5), two_b));
|
||||
CHECK_FALSE(big_less_equal(big_mul(big_step(big_shl(big_step(entry, true), s), false), power5), two_b));
|
||||
power5 = big_mul(power5, {5});
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("128-bit products and leading zeros")
|
||||
{
|
||||
// whichever implementation the compiler gets (with or without a
|
||||
// 128-bit integer type or a builtin)
|
||||
std::uint64_t state = 42;
|
||||
for (int i = 0; i < 10000; ++i)
|
||||
{
|
||||
state ^= state << 13u;
|
||||
state ^= state >> 7u;
|
||||
state ^= state << 17u;
|
||||
const std::uint64_t a = state;
|
||||
const std::uint64_t b = (state * 0x9E3779B97F4A7C15u) >> (i % 64);
|
||||
const auto product = nlohmann::detail::full_multiplication(a, b);
|
||||
CHECK(big_from(product.high, product.low) == big_mul(big_from(0, a), big_from(0, b)));
|
||||
|
||||
const int k = i % 64;
|
||||
const std::uint64_t x = (std::uint64_t{1} << k) | (a & ((std::uint64_t{1} << k) - 1));
|
||||
CHECK(nlohmann::detail::count_leading_zeros(x) == 63 - k);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("known values")
|
||||
{
|
||||
// Generated with Python, whose float() is correctly rounded:
|
||||
// cases = [<hard cases>, 2**53 + 2k + 1, 2**54 + 4k + 2, and exact midpoints
|
||||
// between neighbouring doubles, also 1e-60 above and below them]
|
||||
// print('{"%s", 0x%016xu},' % (s, struct.unpack('<Q', struct.pack('<d', float(s)))[0]))
|
||||
const std::vector<std::pair<std::string, std::uint64_t>> known =
|
||||
{
|
||||
{"0", 0x0000000000000000u},
|
||||
{"-0", 0x8000000000000000u},
|
||||
{"0.0", 0x0000000000000000u},
|
||||
{"-0.0", 0x8000000000000000u},
|
||||
{"0e5", 0x0000000000000000u},
|
||||
{"0.000e-9", 0x0000000000000000u},
|
||||
{"1", 0x3ff0000000000000u},
|
||||
{"-1", 0xbff0000000000000u},
|
||||
{"0.1", 0x3fb999999999999au},
|
||||
{"0.3", 0x3fd3333333333333u},
|
||||
{"1.5", 0x3ff8000000000000u},
|
||||
{"-2.5e-3", 0xbf647ae147ae147bu},
|
||||
{"1e23", 0x44b52d02c7e14af6u},
|
||||
{"1e22", 0x4480f0cf064dd592u},
|
||||
{"8.98846567431158e307", 0x7fe0000000000000u},
|
||||
{"2.2250738585072011e-308", 0x000fffffffffffffu},
|
||||
{"2.2250738585072012e-308", 0x0010000000000000u},
|
||||
{"2.2250738585072014e-308", 0x0010000000000000u},
|
||||
{"4.9406564584124654e-324", 0x0000000000000001u},
|
||||
{"2.4703282292062327e-324", 0x0000000000000000u},
|
||||
{"2.4703282292062328e-324", 0x0000000000000001u},
|
||||
{"1e-324", 0x0000000000000000u},
|
||||
{"3e-324", 0x0000000000000001u},
|
||||
{"1.7976931348623157e308", 0x7fefffffffffffffu},
|
||||
{"1.7976931348623158e308", 0x7fefffffffffffffu},
|
||||
{"1.7976931348623159e308", 0x7ff0000000000000u},
|
||||
{"1e308", 0x7fe1ccf385ebc8a0u},
|
||||
{"1e309", 0x7ff0000000000000u},
|
||||
{"-1e400", 0xfff0000000000000u},
|
||||
{"1e-400", 0x0000000000000000u},
|
||||
{"9007199254740991", 0x433fffffffffffffu},
|
||||
{"9007199254740992", 0x4340000000000000u},
|
||||
{"9007199254740993", 0x4340000000000000u},
|
||||
{"9007199254740995", 0x4340000000000002u},
|
||||
{"18014398509481986", 0x4350000000000000u},
|
||||
{"18014398509481990", 0x4350000000000002u},
|
||||
{"7.2057594037927933e16", 0x4370000000000000u},
|
||||
{"123456789012345678901234567890", 0x45f8ee90ff6c373eu},
|
||||
{"1.000000000000000111", 0x3ff0000000000000u},
|
||||
{"1.0000000000000001110223", 0x3ff0000000000000u},
|
||||
{"1.00000000000000011102230246251565404236316680908203125", 0x3ff0000000000000u},
|
||||
{"1.00000000000000011102230246251565404236316680908203126", 0x3ff0000000000001u},
|
||||
{"0.00000000000000000000000000000000000000000000000000000000000001", 0x3310747ddddf22a8u},
|
||||
{"100000000000000000000000000000000000000000000", 0x4911efc659cf7d4cu},
|
||||
{"1234567890123456789", 0x43b12210f47de981u},
|
||||
{"12345678901234567890", 0x43e56a95319d63e1u},
|
||||
{"1234567890123456789.5", 0x43b12210f47de981u},
|
||||
{"0.1234567890123456789012345", 0x3fbf9add3746f65fu},
|
||||
{"4.4501477170144023e-308", 0x001fffffffffffffu},
|
||||
{"2.4406961166466664e-309", 0x0001c14ae5310a48u},
|
||||
{"5e-324", 0x0000000000000001u},
|
||||
{"1.0e-307", 0x0031fa182c40c60du},
|
||||
{"179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368", 0x7fefffffffffffffu},
|
||||
{"4.9e-324", 0x0000000000000001u},
|
||||
{"9007199254740993", 0x4340000000000000u},
|
||||
{"18014398509481986", 0x4350000000000000u},
|
||||
{"9007199254740995", 0x4340000000000002u},
|
||||
{"18014398509481990", 0x4350000000000002u},
|
||||
{"9007199254740997", 0x4340000000000002u},
|
||||
{"18014398509481994", 0x4350000000000002u},
|
||||
{"9007199254740999", 0x4340000000000004u},
|
||||
{"18014398509481998", 0x4350000000000004u},
|
||||
{"9007199254741001", 0x4340000000000004u},
|
||||
{"18014398509482002", 0x4350000000000004u},
|
||||
{"9007199254741003", 0x4340000000000006u},
|
||||
{"18014398509482006", 0x4350000000000006u},
|
||||
{"9007199254741005", 0x4340000000000006u},
|
||||
{"18014398509482010", 0x4350000000000006u},
|
||||
{"9007199254741007", 0x4340000000000008u},
|
||||
{"18014398509482014", 0x4350000000000008u},
|
||||
{"9007199254741009", 0x4340000000000008u},
|
||||
{"18014398509482018", 0x4350000000000008u},
|
||||
{"9007199254741011", 0x434000000000000au},
|
||||
{"18014398509482022", 0x435000000000000au},
|
||||
{"9007199254741013", 0x434000000000000au},
|
||||
{"18014398509482026", 0x435000000000000au},
|
||||
{"9007199254741015", 0x434000000000000cu},
|
||||
{"18014398509482030", 0x435000000000000cu},
|
||||
{"9007199254741017", 0x434000000000000cu},
|
||||
{"18014398509482034", 0x435000000000000cu},
|
||||
{"9007199254741019", 0x434000000000000eu},
|
||||
{"18014398509482038", 0x435000000000000eu},
|
||||
{"9007199254741021", 0x434000000000000eu},
|
||||
{"18014398509482042", 0x435000000000000eu},
|
||||
{"9007199254741023", 0x4340000000000010u},
|
||||
{"18014398509482046", 0x4350000000000010u},
|
||||
{"9007199254741025", 0x4340000000000010u},
|
||||
{"18014398509482050", 0x4350000000000010u},
|
||||
{"9007199254741027", 0x4340000000000012u},
|
||||
{"18014398509482054", 0x4350000000000012u},
|
||||
{"9007199254741029", 0x4340000000000012u},
|
||||
{"18014398509482058", 0x4350000000000012u},
|
||||
{"9007199254741031", 0x4340000000000014u},
|
||||
{"18014398509482062", 0x4350000000000014u},
|
||||
{"9007199254741033", 0x4340000000000014u},
|
||||
{"18014398509482066", 0x4350000000000014u},
|
||||
{"9007199254741035", 0x4340000000000016u},
|
||||
{"18014398509482070", 0x4350000000000016u},
|
||||
{"9007199254741037", 0x4340000000000016u},
|
||||
{"18014398509482074", 0x4350000000000016u},
|
||||
{"9007199254741039", 0x4340000000000018u},
|
||||
{"18014398509482078", 0x4350000000000018u},
|
||||
{"9007199254741041", 0x4340000000000018u},
|
||||
{"18014398509482082", 0x4350000000000018u},
|
||||
{"9007199254741043", 0x434000000000001au},
|
||||
{"18014398509482086", 0x435000000000001au},
|
||||
{"9007199254741045", 0x434000000000001au},
|
||||
{"18014398509482090", 0x435000000000001au},
|
||||
{"9007199254741047", 0x434000000000001cu},
|
||||
{"18014398509482094", 0x435000000000001cu},
|
||||
{"9007199254741049", 0x434000000000001cu},
|
||||
{"18014398509482098", 0x435000000000001cu},
|
||||
{"9007199254741051", 0x434000000000001eu},
|
||||
{"18014398509482102", 0x435000000000001eu},
|
||||
{"9007199254741053", 0x434000000000001eu},
|
||||
{"18014398509482106", 0x435000000000001eu},
|
||||
{"9007199254741055", 0x4340000000000020u},
|
||||
{"18014398509482110", 0x4350000000000020u},
|
||||
{"9007199254741057", 0x4340000000000020u},
|
||||
{"18014398509482114", 0x4350000000000020u},
|
||||
{"9007199254741059", 0x4340000000000022u},
|
||||
{"18014398509482118", 0x4350000000000022u},
|
||||
{"9007199254741061", 0x4340000000000022u},
|
||||
{"18014398509482122", 0x4350000000000022u},
|
||||
{"9007199254741063", 0x4340000000000024u},
|
||||
{"18014398509482126", 0x4350000000000024u},
|
||||
{"9007199254741065", 0x4340000000000024u},
|
||||
{"18014398509482130", 0x4350000000000024u},
|
||||
{"9007199254741067", 0x4340000000000026u},
|
||||
{"18014398509482134", 0x4350000000000026u},
|
||||
{"9007199254741069", 0x4340000000000026u},
|
||||
{"18014398509482138", 0x4350000000000026u},
|
||||
{"9007199254741071", 0x4340000000000028u},
|
||||
{"18014398509482142", 0x4350000000000028u},
|
||||
{"0.00000000000000000142055942108419951085063380808124102279024543292671443374397544090470546507276594638824462890625", 0x3c3a3466f662d406u},
|
||||
{"0.000000000000000001420559421084199510850633808081241022790245432926714433743975440904705465072765946388244628906251", 0x3c3a3466f662d407u},
|
||||
{"0.00000000000000000142055942108419951085063380808124102279024543292671443374397444090470546507276594638824462890625", 0x3c3a3466f662d406u},
|
||||
{"8656.5250079159513916238211095333099365234375", 0x40c0e84333759a94u},
|
||||
{"8656.52500791595139162382110953330993652343751", 0x40c0e84333759a94u},
|
||||
{"8656.525007915951391623821109533309936523437499999999999999999", 0x40c0e84333759a93u},
|
||||
{"13.07696731650454946560557800694368779659271240234375", 0x402a276842967ef0u},
|
||||
{"13.076967316504549465605578006943687796592712402343751", 0x402a276842967ef0u},
|
||||
{"13.07696731650454946560557800694368779659271240234374999999999", 0x402a276842967eefu},
|
||||
{"74708253715391928", 0x437096ac2cc7ee5cu},
|
||||
{"747082537153919281", 0x43a4bc5737f9e9f2u},
|
||||
{"74708253715391927.99999999999999999999999999999999999999999999", 0x437096ac2cc7ee5bu},
|
||||
{"1809802988.27203977108001708984375", 0x41daf7d9bb11691au},
|
||||
{"1809802988.272039771080017089843751", 0x41daf7d9bb11691au},
|
||||
{"1809802988.272039771080017089843749999999999999999999999999999", 0x41daf7d9bb116919u},
|
||||
{"51.390809684186766759239617385901510715484619140625", 0x4049b2060d3e4568u},
|
||||
{"51.3908096841867667592396173859015107154846191406251", 0x4049b2060d3e4569u},
|
||||
{"51.39080968418676675923961738590151071548461914062499999999999", 0x4049b2060d3e4568u},
|
||||
{"9999807412.59738445281982421875", 0x4202a0479da4c772u},
|
||||
{"9999807412.597384452819824218751", 0x4202a0479da4c772u},
|
||||
{"9999807412.597384452819824218749999999999999999999999999999999", 0x4202a0479da4c771u},
|
||||
{"0.00000000023260971767101600534534272272645127367651785021962496102787554264068603515625", 0x3deff83a135dec10u},
|
||||
{"0.000000000232609717671016005345342722726451273676517850219624961027875542640686035156251", 0x3deff83a135dec11u},
|
||||
{"0.00000000023260971767101600534534272272645127367651785021962496102787544264068603515625", 0x3deff83a135dec10u},
|
||||
{"0.000000000497610482021202508216234789619066523902457532813059515319764614105224609375", 0x3e01190730d1ec48u},
|
||||
{"0.0000000004976104820212025082162347896190665239024575328130595153197646141052246093751", 0x3e01190730d1ec48u},
|
||||
{"0.000000000497610482021202508216234789619066523902457532813059515319764514105224609375", 0x3e01190730d1ec47u},
|
||||
{"0.0000000000291336422596533830691676779231223432149733287843673679162748157978057861328125", 0x3dc004321559736eu},
|
||||
{"0.00000000002913364225965338306916767792312234321497332878436736791627481579780578613281251", 0x3dc004321559736fu},
|
||||
{"0.0000000000291336422596533830691676779231223432149733287843673679162748057978057861328125", 0x3dc004321559736eu},
|
||||
{"0.000000000000000039237155154865396441907405399546892080260012902422940561653064150959835387766361236572265625", 0x3c869e61cfa3b8a4u},
|
||||
{"0.0000000000000000392371551548653964419074053995468920802600129024229405616530641509598353877663612365722656251", 0x3c869e61cfa3b8a5u},
|
||||
{"0.000000000000000039237155154865396441907405399546892080260012902422940561653054150959835387766361236572265625", 0x3c869e61cfa3b8a4u},
|
||||
{"0.00000000000000006496592863767266414092845207857846208631635335985395063307379359685000963509082794189453125", 0x3c92b9a3b219ee84u},
|
||||
{"0.000000000000000064965928637672664140928452078578462086316353359853950633073793596850009635090827941894531251", 0x3c92b9a3b219ee85u},
|
||||
{"0.00000000000000006496592863767266414092845207857846208631635335985395063307378359685000963509082794189453125", 0x3c92b9a3b219ee84u},
|
||||
{"0.0000000000448169607439179753541822628688597626549217078917308754171244800090789794921875", 0x3dc8a36d2e8094dau},
|
||||
{"0.00000000004481696074391797535418226286885976265492170789173087541712448000907897949218751", 0x3dc8a36d2e8094dau},
|
||||
{"0.0000000000448169607439179753541822628688597626549217078917308754171244700090789794921875", 0x3dc8a36d2e8094d9u},
|
||||
{"1800873890234250.875", 0x4319978a820cfe2cu},
|
||||
{"1800873890234250.8751", 0x4319978a820cfe2cu},
|
||||
{"1800873890234250.874999999999999999999999999999999999999999999", 0x4319978a820cfe2bu},
|
||||
{"0.000023941132739153309216405436654628857695570331998169422149658203125", 0x3ef91aa61d42e0e0u},
|
||||
{"0.0000239411327391533092164054366546288576955703319981694221496582031251", 0x3ef91aa61d42e0e1u},
|
||||
{"0.000023941132739153309216405436654628857695570331998169422149658193125", 0x3ef91aa61d42e0e0u},
|
||||
{"8339818978785937.5", 0x433da1056bb8ba92u},
|
||||
{"8339818978785937.51", 0x433da1056bb8ba92u},
|
||||
{"8339818978785937.499999999999999999999999999999999999999999999", 0x433da1056bb8ba91u},
|
||||
{"283649145986385328", 0x438f7dcb29dae42eu},
|
||||
{"2836491459863853281", 0x43c3ae9efa28ce9cu},
|
||||
{"283649145986385327.9999999999999999999999999999999999999999999", 0x438f7dcb29dae42du},
|
||||
{"0.0000000000000000004203729478287971874304476341685497759528753070014375965192388040492232903488911688327789306640625", 0x3c1f049ed78cb8a2u},
|
||||
{"0.00000000000000000042037294782879718743044763416854977595287530700143759651923880404922329034889116883277893066406251", 0x3c1f049ed78cb8a3u},
|
||||
{"0.0000000000000000004203729478287971874304476341685497759528753070014375965192387040492232903488911688327789306640625", 0x3c1f049ed78cb8a2u},
|
||||
{"340031.78635183119331486523151397705078125", 0x4114c0ff25396a18u},
|
||||
{"340031.786351831193314865231513977050781251", 0x4114c0ff25396a19u},
|
||||
{"340031.7863518311933148652315139770507812499999999999999999999", 0x4114c0ff25396a18u},
|
||||
{"0.0000000004543709717853330820053712055931242029538363880192264332436025142669677734375", 0x3dff3960f070bf76u},
|
||||
{"0.00000000045437097178533308200537120559312420295383638801922643324360251426696777343751", 0x3dff3960f070bf76u},
|
||||
{"0.0000000004543709717853330820053712055931242029538363880192264332436024142669677734375", 0x3dff3960f070bf75u},
|
||||
{"0.0000000000007937958898451257082591244100968761704503924570008877026339177973568439483642578125", 0x3d6bede0b40e37c2u},
|
||||
{"0.00000000000079379588984512570825912441009687617045039245700088770263391779735684394836425781251", 0x3d6bede0b40e37c3u},
|
||||
{"0.0000000000007937958898451257082591244100968761704503924570008877026339176973568439483642578125", 0x3d6bede0b40e37c2u},
|
||||
{"0.00000000000000068304843500200357021582520000166071595321259251644419041582523277611471712589263916015625", 0x3cc89c02848f8654u},
|
||||
{"0.000000000000000683048435002003570215825200001660715953212592516444190415825232776114717125892639160156251", 0x3cc89c02848f8655u},
|
||||
{"0.00000000000000068304843500200357021582520000166071595321259251644419041582513277611471712589263916015625", 0x3cc89c02848f8654u},
|
||||
{"0.00000000147705080029041786940146712084494760863773166192913777194917201995849609375", 0x3e1960235bc34d06u},
|
||||
{"0.000000001477050800290417869401467120844947608637731661929137771949172019958496093751", 0x3e1960235bc34d06u},
|
||||
{"0.00000000147705080029041786940146712084494760863773166192913777194917101995849609375", 0x3e1960235bc34d05u},
|
||||
{"2164972979236447104", 0x43be0b87743fb524u},
|
||||
{"21649729792364471041", 0x43f2c734a8a7d136u},
|
||||
{"2164972979236447103.999999999999999999999999999999999999999999", 0x43be0b87743fb523u},
|
||||
{"13124633159586767", 0x4347506464a469e8u},
|
||||
{"131246331595867671", 0x437d247d7dcd8461u},
|
||||
{"13124633159586766.99999999999999999999999999999999999999999999", 0x4347506464a469e7u},
|
||||
{"0.000000000000027605165650764659887597286048864477738779108113853499872902830247767269611358642578125", 0x3d1f14a5b417cb08u},
|
||||
{"0.0000000000000276051656507646598875972860488644777387791081138534998729028302477672696113586425781251", 0x3d1f14a5b417cb09u},
|
||||
{"0.000000000000027605165650764659887597286048864477738779108113853499872902820247767269611358642578125", 0x3d1f14a5b417cb08u},
|
||||
{"0.01727792833395616796388072344825559412129223346710205078125", 0x3f91b14e248c42c8u},
|
||||
{"0.017277928333956167963880723448255594121292233467102050781251", 0x3f91b14e248c42c9u},
|
||||
{"0.01727792833395616796388072344825559412129223346710205078124999", 0x3f91b14e248c42c8u},
|
||||
{"0.00000000000003096211381890547702500862566064822950373937142376501441276559489779174327850341796875", 0x3d216e1c61130b22u},
|
||||
{"0.000000000000030962113818905477025008625660648229503739371423765014412765594897791743278503417968751", 0x3d216e1c61130b22u},
|
||||
{"0.00000000000003096211381890547702500862566064822950373937142376501441276558489779174327850341796875", 0x3d216e1c61130b21u},
|
||||
{"0.0000000000000683414954481284270259359974108983284531919182025472281338807079009711742401123046875", 0x3d333c86137e5170u},
|
||||
{"0.00000000000006834149544812842702593599741089832845319191820254722813388070790097117424011230468751", 0x3d333c86137e5170u},
|
||||
{"0.0000000000000683414954481284270259359974108983284531919182025472281338806979009711742401123046875", 0x3d333c86137e516fu},
|
||||
{"3237539054990129.75", 0x4327010c9aa36664u},
|
||||
{"3237539054990129.751", 0x4327010c9aa36664u},
|
||||
{"3237539054990129.749999999999999999999999999999999999999999999", 0x4327010c9aa36663u},
|
||||
{"0.0000000000000105429301486355911969397173440055240907798901443814809653076736140064895153045654296875", 0x3d07bd95dfb8a1eeu},
|
||||
{"0.00000000000001054293014863559119693971734400552409077989014438148096530767361400648951530456542968751", 0x3d07bd95dfb8a1eeu},
|
||||
{"0.0000000000000105429301486355911969397173440055240907798901443814809653076636140064895153045654296875", 0x3d07bd95dfb8a1edu},
|
||||
{"9460.2061893763575426419265568256378173828125", 0x40c27a1a6469da1eu},
|
||||
{"9460.20618937635754264192655682563781738281251", 0x40c27a1a6469da1fu},
|
||||
{"9460.206189376357542641926556825637817382812499999999999999999", 0x40c27a1a6469da1eu},
|
||||
{"465000373656610.53125", 0x42fa6ea56179c228u},
|
||||
{"465000373656610.531251", 0x42fa6ea56179c229u},
|
||||
{"465000373656610.5312499999999999999999999999999999999999999999", 0x42fa6ea56179c228u},
|
||||
{"0.000000000107709773707743713401260815383950956818093214195641849073581397533416748046875", 0x3ddd9b66c974bb14u},
|
||||
{"0.0000000001077097737077437134012608153839509568180932141956418490735813975334167480468751", 0x3ddd9b66c974bb14u},
|
||||
{"0.000000000107709773707743713401260815383950956818093214195641849073581297533416748046875", 0x3ddd9b66c974bb13u},
|
||||
{"0.012083347821554271152300064073870089487172663211822509765625", 0x3f88bf277dc215f4u},
|
||||
{"0.0120833478215542711523000640738700894871726632118225097656251", 0x3f88bf277dc215f5u},
|
||||
{"0.01208334782155427115230006407387008948717266321182250976562499", 0x3f88bf277dc215f4u},
|
||||
{"2309804058391724800", 0x43c0070946d098e2u},
|
||||
{"23098040583917248001", 0x43f408cb9884bf1au},
|
||||
{"2309804058391724799.999999999999999999999999999999999999999999", 0x43c0070946d098e1u},
|
||||
{"0.000000000078286047058220682019445698291671103911937290575906445155851542949676513671875", 0x3dd584e40ca80638u},
|
||||
{"0.0000000000782860470582206820194456982916711039119372905759064451558515429496765136718751", 0x3dd584e40ca80638u},
|
||||
{"0.000000000078286047058220682019445698291671103911937290575906445155851532949676513671875", 0x3dd584e40ca80637u},
|
||||
{"2940024994425.709228515625", 0x4285643929d3cdacu},
|
||||
{"2940024994425.7092285156251", 0x4285643929d3cdadu},
|
||||
{"2940024994425.709228515624999999999999999999999999999999999999", 0x4285643929d3cdacu},
|
||||
{"9503358.427352792583405971527099609375", 0x4162204fcdacdfc4u},
|
||||
{"9503358.4273527925834059715270996093751", 0x4162204fcdacdfc4u},
|
||||
{"9503358.427352792583405971527099609374999999999999999999999999", 0x4162204fcdacdfc3u},
|
||||
{"0.00005589147834433423614399101542193903924271580763161182403564453125", 0x3f0d4da092aa5d6au},
|
||||
{"0.000055891478344334236143991015421939039242715807631611824035644531251", 0x3f0d4da092aa5d6bu},
|
||||
{"0.00005589147834433423614399101542193903924271580763161182403564452125", 0x3f0d4da092aa5d6au},
|
||||
{"0.0000000164797038506435664295103900420409737126448135313694365322589874267578125", 0x3e51b1e8107bd640u},
|
||||
{"0.00000001647970385064356642951039004204097371264481353136943653225898742675781251", 0x3e51b1e8107bd641u},
|
||||
{"0.0000000164797038506435664295103900420409737126448135313694365322589774267578125", 0x3e51b1e8107bd640u},
|
||||
{"73055.7873927834807545877993106842041015625", 0x40f1d5fc99292ce2u},
|
||||
{"73055.78739278348075458779931068420410156251", 0x40f1d5fc99292ce3u},
|
||||
{"73055.78739278348075458779931068420410156249999999999999999999", 0x40f1d5fc99292ce2u},
|
||||
{"0.00000000002558172364455232122427880575336067736115508441940846751094795763492584228515625", 0x3dbc209d7509115au},
|
||||
{"0.000000000025581723644552321224278805753360677361155084419408467510947957634925842285156251", 0x3dbc209d7509115bu},
|
||||
{"0.00000000002558172364455232122427880575336067736115508441940846751094794763492584228515625", 0x3dbc209d7509115au},
|
||||
{"0.000000000854497507560657937804791333430312443020238077906469698064029216766357421875", 0x3e0d5c3d540cc0d2u},
|
||||
{"0.0000000008544975075606579378047913334303124430202380779064696980640292167663574218751", 0x3e0d5c3d540cc0d2u},
|
||||
{"0.000000000854497507560657937804791333430312443020238077906469698064029116766357421875", 0x3e0d5c3d540cc0d1u},
|
||||
{"26671499731071461376", 0x43f722433b19970eu},
|
||||
{"266714997310714613761", 0x442cead409dffcd2u},
|
||||
{"26671499731071461375.99999999999999999999999999999999999999999", 0x43f722433b19970eu},
|
||||
{"0.0000000002725195963972150049060368088050545186395989816219298518262803554534912109375", 0x3df2ba37271cf5f2u},
|
||||
{"0.00000000027251959639721500490603680880505451863959898162192985182628035545349121093751", 0x3df2ba37271cf5f2u},
|
||||
{"0.0000000002725195963972150049060368088050545186395989816219298518262802554534912109375", 0x3df2ba37271cf5f1u},
|
||||
{"0.0000000000377224663702246439557904325637937886957218314165629635681398212909698486328125", 0x3dc4bcf7157af68eu},
|
||||
{"0.00000000003772246637022464395579043256379378869572183141656296356813982129096984863281251", 0x3dc4bcf7157af68fu},
|
||||
{"0.0000000000377224663702246439557904325637937886957218314165629635681398112909698486328125", 0x3dc4bcf7157af68eu},
|
||||
{"0.00000000000000009977342762593364154535842258994910996905560208471673566688053824691451154649257659912109375", 0x3c9cc1fac312e2a6u},
|
||||
{"0.000000000000000099773427625933641545358422589949109969055602084716735666880538246914511546492576599121093751", 0x3c9cc1fac312e2a6u},
|
||||
{"0.00000000000000009977342762593364154535842258994910996905560208471673566688052824691451154649257659912109375", 0x3c9cc1fac312e2a5u},
|
||||
{"0.0000000003146248171139977444431948290159907662133509376189977047033607959747314453125", 0x3df59ef03588a228u},
|
||||
{"0.00000000031462481711399774444319482901599076621335093761899770470336079597473144531251", 0x3df59ef03588a229u},
|
||||
{"0.0000000003146248171139977444431948290159907662133509376189977047033606959747314453125", 0x3df59ef03588a228u},
|
||||
{"488899209263030304", 0x439b23acf64c5e80u},
|
||||
{"4888992092630303041", 0x43d0f64c19efbb10u},
|
||||
{"488899209263030303.9999999999999999999999999999999999999999999", 0x439b23acf64c5e80u},
|
||||
{"1.88357157350592807620870416940306313335895538330078125", 0x3ffe231bf23e21acu},
|
||||
{"1.883571573505928076208704169403063133358955383300781251", 0x3ffe231bf23e21adu},
|
||||
{"1.883571573505928076208704169403063133358955383300781249999999", 0x3ffe231bf23e21acu},
|
||||
{"0.0000000216458400594294836451424756990254139044083103726734407246112823486328125", 0x3e573df694e72fb8u},
|
||||
{"0.00000002164584005942948364514247569902541390440831037267344072461128234863281251", 0x3e573df694e72fb9u},
|
||||
{"0.0000000216458400594294836451424756990254139044083103726734407246112723486328125", 0x3e573df694e72fb8u},
|
||||
{"5107.79271041116453488939441740512847900390625", 0x40b3f3caef11cb26u},
|
||||
{"5107.792710411164534889394417405128479003906251", 0x40b3f3caef11cb27u},
|
||||
{"5107.792710411164534889394417405128479003906249999999999999999", 0x40b3f3caef11cb26u},
|
||||
{"734059.8035226609208621084690093994140625", 0x412666d79b67527cu},
|
||||
{"734059.80352266092086210846900939941406251", 0x412666d79b67527du},
|
||||
{"734059.8035226609208621084690093994140624999999999999999999999", 0x412666d79b67527cu},
|
||||
{"61431562016722684", 0x436b47f5c40021e0u},
|
||||
{"614315620167226841", 0x43a10cf99a80152cu},
|
||||
{"61431562016722683.99999999999999999999999999999999999999999999", 0x436b47f5c40021dfu},
|
||||
{"2.0060840449445034305853141631814651191234588623046875", 0x40000c75cab08326u},
|
||||
{"2.00608404494450343058531416318146511912345886230468751", 0x40000c75cab08326u},
|
||||
{"2.006084044944503430585314163181465119123458862304687499999999", 0x40000c75cab08325u},
|
||||
{"0.0000001760623599453036952716420489480075861621344301966018974781036376953125", 0x3e87a174e55262cau},
|
||||
{"0.00000017606235994530369527164204894800758616213443019660189747810363769531251", 0x3e87a174e55262cbu},
|
||||
{"0.0000001760623599453036952716420489480075861621344301966018974781035376953125", 0x3e87a174e55262cau},
|
||||
{"0.833085849636964581588216560703585855662822723388671875", 0x3feaa8a3a7de6fb6u},
|
||||
{"0.8330858496369645815882165607035858556628227233886718751", 0x3feaa8a3a7de6fb6u},
|
||||
{"0.8330858496369645815882165607035858556628227233886718749999999", 0x3feaa8a3a7de6fb5u},
|
||||
{"45031428.4182307310402393341064453125", 0x418579002358895au},
|
||||
{"45031428.41823073104023933410644531251", 0x418579002358895bu},
|
||||
{"45031428.41823073104023933410644531249999999999999999999999999", 0x418579002358895au},
|
||||
{"5003361733758455296", 0x43d15be0bf39dd24u},
|
||||
{"50033617337584552961", 0x4405b2d8ef08546cu},
|
||||
{"5003361733758455295.999999999999999999999999999999999999999999", 0x43d15be0bf39dd23u},
|
||||
};
|
||||
|
||||
for (const auto& c : known)
|
||||
{
|
||||
CAPTURE(c.first);
|
||||
double out = 0;
|
||||
if (eisel_lemire(c.first, out))
|
||||
{
|
||||
CHECK(bits_of(out) == c.second);
|
||||
}
|
||||
else
|
||||
{
|
||||
// only tokens with more than 19 significant digits are left to
|
||||
// strtod: those whose value lies too close to a tie
|
||||
CHECK(significant_digits(c.first) > 19);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("round trip")
|
||||
{
|
||||
// every double written by to_chars and read back, also with trailing
|
||||
// digits that make the token longer than 19 digits
|
||||
std::uint64_t state = 5295;
|
||||
std::size_t declined = 0;
|
||||
for (int i = 0; i < 200000; ++i)
|
||||
{
|
||||
state ^= state << 13u;
|
||||
state ^= state >> 7u;
|
||||
state ^= state << 17u;
|
||||
std::uint64_t b = state;
|
||||
if ((b & 0x7FF0000000000000u) == 0x7FF0000000000000u)
|
||||
{
|
||||
continue; // infinity or NaN
|
||||
}
|
||||
if (i % 4 == 0)
|
||||
{
|
||||
b &= 0x800FFFFFFFFFFFFFu; // subnormals
|
||||
}
|
||||
double d = 0;
|
||||
std::memcpy(&d, &b, sizeof(d));
|
||||
|
||||
std::array<char, 64> buffer{};
|
||||
const char* end = nlohmann::detail::to_chars(buffer.data(), buffer.data() + buffer.size(), d);
|
||||
const std::string token(buffer.data(), static_cast<std::size_t>(end - buffer.data()));
|
||||
CAPTURE(token);
|
||||
double out = 0;
|
||||
REQUIRE(eisel_lemire(token, out));
|
||||
CHECK(bits_of(out) == b);
|
||||
|
||||
// insert digits before the exponent: the value moves by far less
|
||||
// than the distance to the rounding boundary, so it must not change
|
||||
std::string longer = token;
|
||||
const std::size_t e = longer.find('e');
|
||||
const std::size_t dot = longer.find('.');
|
||||
const std::string extra = dot == std::string::npos ? ".000000000000000000001" : "000000000000000000001";
|
||||
longer.insert(e == std::string::npos ? longer.size() : e, extra);
|
||||
CAPTURE(longer);
|
||||
if (eisel_lemire(longer, out))
|
||||
{
|
||||
CHECK(bits_of(out) == b);
|
||||
}
|
||||
else
|
||||
{
|
||||
// w and w + 1 round differently: only when the value is very
|
||||
// close to a rounding boundary
|
||||
++declined;
|
||||
}
|
||||
}
|
||||
CHECK(declined < 1000); // 107 of the 200,000
|
||||
}
|
||||
|
||||
SECTION("used by the lexer")
|
||||
{
|
||||
// 17 significant digits: beyond Clinger's fast path
|
||||
CHECK(bits_of(json::parse("-65.613616999999977").get<double>()) == bits_of(-65.613616999999977));
|
||||
CHECK(bits_of(json::parse("2.2250738585072011e-308").get<double>()) == 0x000FFFFFFFFFFFFFu);
|
||||
CHECK(bits_of(json::parse("4.9406564584124654e-324").get<double>()) == 1u);
|
||||
json _;
|
||||
CHECK_THROWS_WITH_AS(_ = json::parse("1.7976931348623159e308"),
|
||||
"[json.exception.out_of_range.406] number overflow parsing '1.7976931348623159e308'", json::out_of_range&);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("string scanning kernels")
|
||||
{
|
||||
// the word-at-a-time kernels must stop exactly where a byte-by-byte scan
|
||||
// stops, for any content, length, and alignment
|
||||
const auto reference_special = [](const unsigned char* data, std::size_t n)
|
||||
{
|
||||
std::size_t i = 0;
|
||||
while (i < n && !nlohmann::detail::is_string_special(data[i]))
|
||||
{
|
||||
++i;
|
||||
}
|
||||
return i;
|
||||
};
|
||||
const auto reference_copyable = [](const unsigned char* data, std::size_t n)
|
||||
{
|
||||
std::size_t i = 0;
|
||||
while (i < n && nlohmann::detail::is_ascii_copyable(data[i]))
|
||||
{
|
||||
++i;
|
||||
}
|
||||
return i;
|
||||
};
|
||||
const auto reference_bulk_run = [](const unsigned char* data, std::size_t n)
|
||||
{
|
||||
std::size_t i = 0;
|
||||
while (i < n)
|
||||
{
|
||||
if (data[i] < 0x80u)
|
||||
{
|
||||
if (nlohmann::detail::is_string_special(data[i]))
|
||||
{
|
||||
break;
|
||||
}
|
||||
++i;
|
||||
continue;
|
||||
}
|
||||
const std::size_t seq = nlohmann::detail::validate_one_utf8(data + i, n - i);
|
||||
if (seq == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
i += seq;
|
||||
}
|
||||
return i;
|
||||
};
|
||||
|
||||
// pieces: ordinary ASCII, stops, DEL, well-formed sequences of every
|
||||
// length, and ill-formed or truncated ones
|
||||
const std::vector<std::string> pieces =
|
||||
{
|
||||
"a", "Z", " ", "~", "0123456789", "\"", "\\", std::string(1, '\0'), "\n", "\x1F", "\x7F",
|
||||
"\xC3\xA4", "\xE2\x82\xAC", "\xE6\x97\xA5\xE6\x9C\xAC", "\xF0\x9F\x98\x80", "\xED\x9F\xBF",
|
||||
"\x80", "\xC0\x80", "\xC3", "\xE2\x82", "\xED\xA0\x80", "\xF4\x90\x80\x80", "\xFF",
|
||||
};
|
||||
std::uint64_t state = 5295;
|
||||
const auto next = [&state]()
|
||||
{
|
||||
state ^= state << 13u;
|
||||
state ^= state >> 7u;
|
||||
state ^= state << 17u;
|
||||
return state;
|
||||
};
|
||||
// the upper half as a 32-bit value: converts to std::size_t implicitly on
|
||||
// every platform (a cast of std::uint64_t is useless where both are the
|
||||
// same type, and required where std::size_t is 32 bits wide)
|
||||
const auto next_small = [&next]()
|
||||
{
|
||||
return static_cast<std::uint32_t>(next() >> 32u);
|
||||
};
|
||||
for (int round = 0; round < 100000; ++round)
|
||||
{
|
||||
// mostly ordinary text, so that runs span several words
|
||||
std::string text(next_small() % 8u, '.');
|
||||
const std::size_t count = next_small() % 12u;
|
||||
for (std::size_t k = 0; k < count; ++k)
|
||||
{
|
||||
const std::size_t p = (next() % 4 == 0) ? next_small() % pieces.size() : 0;
|
||||
text += pieces[p];
|
||||
text += std::string(next_small() % 10u, 'x');
|
||||
}
|
||||
const auto* data = reinterpret_cast<const unsigned char*>(text.data()); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
|
||||
for (std::size_t offset = 0; offset < 3 && offset <= text.size(); ++offset)
|
||||
{
|
||||
const std::size_t n = text.size() - offset;
|
||||
CAPTURE(text);
|
||||
CAPTURE(offset);
|
||||
CHECK(nlohmann::detail::find_string_special(data + offset, n) == reference_special(data + offset, n));
|
||||
CHECK(nlohmann::detail::find_ascii_copyable_run(data + offset, n) == reference_copyable(data + offset, n));
|
||||
CHECK(nlohmann::detail::scalar_string_bulk_run(data + offset, n) == reference_bulk_run(data + offset, n));
|
||||
}
|
||||
}
|
||||
|
||||
// the trailing-zero count, whichever implementation the compiler gets
|
||||
for (int k = 0; k < 64; ++k)
|
||||
{
|
||||
const std::uint64_t bit = std::uint64_t{1} << k;
|
||||
CHECK(nlohmann::detail::count_trailing_zeros(bit) == k);
|
||||
CHECK(nlohmann::detail::count_trailing_zeros(bit | (bit << 1u) | 0x8000000000000000u) == k);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1372,21 +1372,22 @@ TEST_CASE("value conversion")
|
||||
|
||||
SECTION("std::map")
|
||||
{
|
||||
j1.get<std::map<std::string, int>>();
|
||||
j2.get<std::map<std::string, unsigned int>>();
|
||||
j3.get<std::map<std::string, double>>();
|
||||
j4.get<std::map<std::string, bool>>();
|
||||
j5.get<std::map<std::string, std::string>>();
|
||||
CHECK(j1.get<std::map<std::string, int>>() == (std::map<std::string, int> {{"one", 1}, {"two", 2}, {"three", 3}}));
|
||||
CHECK(j2.get<std::map<std::string, unsigned int>>() == (std::map<std::string, unsigned int> {{"one", 1u}, {"two", 2u}, {"three", 3u}}));
|
||||
CHECK(j3.get<std::map<std::string, double>>() == (std::map<std::string, double> {{"one", 1.1}, {"two", 2.2}, {"three", 3.3}}));
|
||||
CHECK(j4.get<std::map<std::string, bool>>() == (std::map<std::string, bool> {{"one", true}, {"two", false}, {"three", true}}));
|
||||
CHECK(j5.get<std::map<std::string, std::string>>() == (std::map<std::string, std::string> {{"one", "eins"}, {"two", "zwei"}, {"three", "drei"}}));
|
||||
}
|
||||
|
||||
SECTION("std::unordered_map")
|
||||
{
|
||||
j1.get<std::unordered_map<std::string, int>>();
|
||||
j2.get<std::unordered_map<std::string, unsigned int>>();
|
||||
j3.get<std::unordered_map<std::string, double>>();
|
||||
j4.get<std::unordered_map<std::string, bool>>();
|
||||
j5.get<std::unordered_map<std::string, std::string>>();
|
||||
// CHECK(m5["one"] == "eins");
|
||||
CHECK(j1.get<std::unordered_map<std::string, int>>() == (std::unordered_map<std::string, int> {{"one", 1}, {"two", 2}, {"three", 3}}));
|
||||
CHECK(j2.get<std::unordered_map<std::string, unsigned int>>() == (std::unordered_map<std::string, unsigned int> {{"one", 1u}, {"two", 2u}, {"three", 3u}}));
|
||||
CHECK(j3.get<std::unordered_map<std::string, double>>() == (std::unordered_map<std::string, double> {{"one", 1.1}, {"two", 2.2}, {"three", 3.3}}));
|
||||
CHECK(j4.get<std::unordered_map<std::string, bool>>() == (std::unordered_map<std::string, bool> {{"one", true}, {"two", false}, {"three", true}}));
|
||||
const auto m5 = j5.get<std::unordered_map<std::string, std::string>>();
|
||||
CHECK(m5 == (std::unordered_map<std::string, std::string> {{"one", "eins"}, {"two", "zwei"}, {"three", "drei"}}));
|
||||
CHECK(m5.at("one") == "eins");
|
||||
}
|
||||
|
||||
SECTION("reserve is called on containers that support it (#5406)")
|
||||
@@ -1422,22 +1423,24 @@ TEST_CASE("value conversion")
|
||||
|
||||
SECTION("std::multimap")
|
||||
{
|
||||
j1.get<std::multimap<std::string, int>>();
|
||||
j2.get<std::multimap<std::string, unsigned int>>();
|
||||
j3.get<std::multimap<std::string, double>>();
|
||||
j4.get<std::multimap<std::string, bool>>();
|
||||
j5.get<std::multimap<std::string, std::string>>();
|
||||
// CHECK(m5["one"] == "eins");
|
||||
CHECK(j1.get<std::multimap<std::string, int>>() == (std::multimap<std::string, int> {{"one", 1}, {"two", 2}, {"three", 3}}));
|
||||
CHECK(j2.get<std::multimap<std::string, unsigned int>>() == (std::multimap<std::string, unsigned int> {{"one", 1u}, {"two", 2u}, {"three", 3u}}));
|
||||
CHECK(j3.get<std::multimap<std::string, double>>() == (std::multimap<std::string, double> {{"one", 1.1}, {"two", 2.2}, {"three", 3.3}}));
|
||||
CHECK(j4.get<std::multimap<std::string, bool>>() == (std::multimap<std::string, bool> {{"one", true}, {"two", false}, {"three", true}}));
|
||||
const auto m5 = j5.get<std::multimap<std::string, std::string>>();
|
||||
CHECK(m5 == (std::multimap<std::string, std::string> {{"one", "eins"}, {"two", "zwei"}, {"three", "drei"}}));
|
||||
CHECK(m5.find("one")->second == "eins");
|
||||
}
|
||||
|
||||
SECTION("std::unordered_multimap")
|
||||
{
|
||||
j1.get<std::unordered_multimap<std::string, int>>();
|
||||
j2.get<std::unordered_multimap<std::string, unsigned int>>();
|
||||
j3.get<std::unordered_multimap<std::string, double>>();
|
||||
j4.get<std::unordered_multimap<std::string, bool>>();
|
||||
j5.get<std::unordered_multimap<std::string, std::string>>();
|
||||
// CHECK(m5["one"] == "eins");
|
||||
CHECK(j1.get<std::unordered_multimap<std::string, int>>() == (std::unordered_multimap<std::string, int> {{"one", 1}, {"two", 2}, {"three", 3}}));
|
||||
CHECK(j2.get<std::unordered_multimap<std::string, unsigned int>>() == (std::unordered_multimap<std::string, unsigned int> {{"one", 1u}, {"two", 2u}, {"three", 3u}}));
|
||||
CHECK(j3.get<std::unordered_multimap<std::string, double>>() == (std::unordered_multimap<std::string, double> {{"one", 1.1}, {"two", 2.2}, {"three", 3.3}}));
|
||||
CHECK(j4.get<std::unordered_multimap<std::string, bool>>() == (std::unordered_multimap<std::string, bool> {{"one", true}, {"two", false}, {"three", true}}));
|
||||
const auto m5 = j5.get<std::unordered_multimap<std::string, std::string>>();
|
||||
CHECK(m5 == (std::unordered_multimap<std::string, std::string> {{"one", "eins"}, {"two", "zwei"}, {"three", "drei"}}));
|
||||
CHECK(m5.find("one")->second == "eins");
|
||||
}
|
||||
|
||||
SECTION("exception in case of a non-object type")
|
||||
@@ -1458,29 +1461,30 @@ TEST_CASE("value conversion")
|
||||
|
||||
SECTION("std::list")
|
||||
{
|
||||
j1.get<std::list<int>>();
|
||||
j2.get<std::list<unsigned int>>();
|
||||
j3.get<std::list<double>>();
|
||||
j4.get<std::list<bool>>();
|
||||
j5.get<std::list<std::string>>();
|
||||
CHECK(j1.get<std::list<int>>() == (std::list<int> {1, 2, 3, 4}));
|
||||
CHECK(j2.get<std::list<unsigned int>>() == (std::list<unsigned int> {1u, 2u, 3u, 4u}));
|
||||
CHECK(j3.get<std::list<double>>() == (std::list<double> {1.2, 2.3, 3.4, 4.5}));
|
||||
CHECK(j4.get<std::list<bool>>() == (std::list<bool> {true, false, true}));
|
||||
CHECK(j5.get<std::list<std::string>>() == (std::list<std::string> {"one", "two", "three"}));
|
||||
}
|
||||
|
||||
SECTION("std::forward_list")
|
||||
{
|
||||
j1.get<std::forward_list<int>>();
|
||||
j2.get<std::forward_list<unsigned int>>();
|
||||
j3.get<std::forward_list<double>>();
|
||||
j4.get<std::forward_list<bool>>();
|
||||
j5.get<std::forward_list<std::string>>();
|
||||
CHECK(j1.get<std::forward_list<int>>() == (std::forward_list<int> {1, 2, 3, 4}));
|
||||
CHECK(j2.get<std::forward_list<unsigned int>>() == (std::forward_list<unsigned int> {1u, 2u, 3u, 4u}));
|
||||
CHECK(j3.get<std::forward_list<double>>() == (std::forward_list<double> {1.2, 2.3, 3.4, 4.5}));
|
||||
CHECK(j4.get<std::forward_list<bool>>() == (std::forward_list<bool> {true, false, true}));
|
||||
CHECK(j5.get<std::forward_list<std::string>>() == (std::forward_list<std::string> {"one", "two", "three"}));
|
||||
}
|
||||
|
||||
SECTION("std::array")
|
||||
{
|
||||
j1.get<std::array<int, 4>>();
|
||||
j2.get<std::array<unsigned int, 3>>();
|
||||
j3.get<std::array<double, 4>>();
|
||||
j4.get<std::array<bool, 3>>();
|
||||
j5.get<std::array<std::string, 3>>();
|
||||
CHECK(j1.get<std::array<int, 4>>() == (std::array<int, 4> {{1, 2, 3, 4}}));
|
||||
// only the first 3 elements of j2 are converted, since the target array is smaller
|
||||
CHECK(j2.get<std::array<unsigned int, 3>>() == (std::array<unsigned int, 3> {{1u, 2u, 3u}}));
|
||||
CHECK(j3.get<std::array<double, 4>>() == (std::array<double, 4> {{1.2, 2.3, 3.4, 4.5}}));
|
||||
CHECK(j4.get<std::array<bool, 3>>() == (std::array<bool, 3> {{true, false, true}}));
|
||||
CHECK(j5.get<std::array<std::string, 3>>() == (std::array<std::string, 3> {{"one", "two", "three"}}));
|
||||
|
||||
SECTION("std::array is larger than JSON")
|
||||
{
|
||||
@@ -1500,47 +1504,53 @@ TEST_CASE("value conversion")
|
||||
|
||||
SECTION("std::valarray")
|
||||
{
|
||||
j1.get<std::valarray<int>>();
|
||||
j2.get<std::valarray<unsigned int>>();
|
||||
j3.get<std::valarray<double>>();
|
||||
j4.get<std::valarray<bool>>();
|
||||
j5.get<std::valarray<std::string>>();
|
||||
// valarray has no operator== that returns bool, so compare via a vector copy
|
||||
const auto v1 = j1.get<std::valarray<int>>();
|
||||
CHECK((std::vector<int>(std::begin(v1), std::end(v1)) == std::vector<int> {1, 2, 3, 4}));
|
||||
const auto v2 = j2.get<std::valarray<unsigned int>>();
|
||||
CHECK((std::vector<unsigned int>(std::begin(v2), std::end(v2)) == std::vector<unsigned int> {1u, 2u, 3u, 4u}));
|
||||
const auto v3 = j3.get<std::valarray<double>>();
|
||||
CHECK((std::vector<double>(std::begin(v3), std::end(v3)) == std::vector<double> {1.2, 2.3, 3.4, 4.5}));
|
||||
const auto v4 = j4.get<std::valarray<bool>>();
|
||||
CHECK((std::vector<bool>(std::begin(v4), std::end(v4)) == std::vector<bool> {true, false, true}));
|
||||
const auto v5 = j5.get<std::valarray<std::string>>();
|
||||
CHECK((std::vector<std::string>(std::begin(v5), std::end(v5)) == std::vector<std::string> {"one", "two", "three"}));
|
||||
}
|
||||
|
||||
SECTION("std::vector")
|
||||
{
|
||||
j1.get<std::vector<int>>();
|
||||
j2.get<std::vector<unsigned int>>();
|
||||
j3.get<std::vector<double>>();
|
||||
j4.get<std::vector<bool>>();
|
||||
j5.get<std::vector<std::string>>();
|
||||
CHECK(j1.get<std::vector<int>>() == (std::vector<int> {1, 2, 3, 4}));
|
||||
CHECK(j2.get<std::vector<unsigned int>>() == (std::vector<unsigned int> {1u, 2u, 3u, 4u}));
|
||||
CHECK(j3.get<std::vector<double>>() == (std::vector<double> {1.2, 2.3, 3.4, 4.5}));
|
||||
CHECK(j4.get<std::vector<bool>>() == (std::vector<bool> {true, false, true}));
|
||||
CHECK(j5.get<std::vector<std::string>>() == (std::vector<std::string> {"one", "two", "three"}));
|
||||
}
|
||||
|
||||
SECTION("std::deque")
|
||||
{
|
||||
j1.get<std::deque<int>>();
|
||||
j2.get<std::deque<unsigned int>>();
|
||||
j2.get<std::deque<double>>();
|
||||
j4.get<std::deque<bool>>();
|
||||
j5.get<std::deque<std::string>>();
|
||||
CHECK(j1.get<std::deque<int>>() == (std::deque<int> {1, 2, 3, 4}));
|
||||
CHECK(j2.get<std::deque<unsigned int>>() == (std::deque<unsigned int> {1u, 2u, 3u, 4u}));
|
||||
CHECK(j3.get<std::deque<double>>() == (std::deque<double> {1.2, 2.3, 3.4, 4.5}));
|
||||
CHECK(j4.get<std::deque<bool>>() == (std::deque<bool> {true, false, true}));
|
||||
CHECK(j5.get<std::deque<std::string>>() == (std::deque<std::string> {"one", "two", "three"}));
|
||||
}
|
||||
|
||||
SECTION("std::set")
|
||||
{
|
||||
j1.get<std::set<int>>();
|
||||
j2.get<std::set<unsigned int>>();
|
||||
j3.get<std::set<double>>();
|
||||
j4.get<std::set<bool>>();
|
||||
j5.get<std::set<std::string>>();
|
||||
CHECK(j1.get<std::set<int>>() == (std::set<int> {1, 2, 3, 4}));
|
||||
CHECK(j2.get<std::set<unsigned int>>() == (std::set<unsigned int> {1u, 2u, 3u, 4u}));
|
||||
CHECK(j3.get<std::set<double>>() == (std::set<double> {1.2, 2.3, 3.4, 4.5}));
|
||||
CHECK(j4.get<std::set<bool>>() == (std::set<bool> {true, false, true}));
|
||||
CHECK(j5.get<std::set<std::string>>() == (std::set<std::string> {"one", "two", "three"}));
|
||||
}
|
||||
|
||||
SECTION("std::unordered_set")
|
||||
{
|
||||
j1.get<std::unordered_set<int>>();
|
||||
j2.get<std::unordered_set<unsigned int>>();
|
||||
j3.get<std::unordered_set<double>>();
|
||||
j4.get<std::unordered_set<bool>>();
|
||||
j5.get<std::unordered_set<std::string>>();
|
||||
CHECK(j1.get<std::unordered_set<int>>() == (std::unordered_set<int> {1, 2, 3, 4}));
|
||||
CHECK(j2.get<std::unordered_set<unsigned int>>() == (std::unordered_set<unsigned int> {1u, 2u, 3u, 4u}));
|
||||
CHECK(j3.get<std::unordered_set<double>>() == (std::unordered_set<double> {1.2, 2.3, 3.4, 4.5}));
|
||||
CHECK(j4.get<std::unordered_set<bool>>() == (std::unordered_set<bool> {true, false, true}));
|
||||
CHECK(j5.get<std::unordered_set<std::string>>() == (std::unordered_set<std::string> {"one", "two", "three"}));
|
||||
}
|
||||
|
||||
SECTION("std::map (array of pairs)")
|
||||
|
||||
@@ -893,8 +893,6 @@ TEST_CASE("iterators 2")
|
||||
CHECK(std::ranges::input_range<items_type>);
|
||||
}
|
||||
|
||||
// libstdc++ algorithms don't work with Clang 15 (04/2022)
|
||||
#if !DOCTEST_CLANG || (DOCTEST_CLANG && defined(__GLIBCXX__))
|
||||
SECTION("algorithms")
|
||||
{
|
||||
SECTION("copy")
|
||||
@@ -929,11 +927,7 @@ TEST_CASE("iterators 2")
|
||||
CHECK(*it == 2);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// libstdc++ views don't work with Clang 15 (04/2022)
|
||||
// libc++ hides limited ranges implementation behind guard macro
|
||||
#if !(DOCTEST_CLANG && (defined(__GLIBCXX__) || defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)))
|
||||
SECTION("views")
|
||||
{
|
||||
SECTION("reverse")
|
||||
@@ -966,7 +960,6 @@ TEST_CASE("iterators 2")
|
||||
CHECK(j_transformed == j_expected);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,366 +0,0 @@
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++ (supporting code)
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include "doctest_compatibility.h"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <nlohmann/detail/view/builder.hpp>
|
||||
#include <nlohmann/detail/view/string_ref.hpp>
|
||||
using nlohmann::json;
|
||||
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <random>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <test_data.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
using nlohmann::detail::view::document_data;
|
||||
using nlohmann::detail::view::node;
|
||||
|
||||
// the node index of a text; a vector input has no terminating NUL, so that
|
||||
// AddressSanitizer catches any read past the last byte
|
||||
struct built
|
||||
{
|
||||
std::unique_ptr<document_data, document_data::deleter> data{}; // NOLINT(readability-redundant-member-init)
|
||||
std::vector<char> copy{}; // NOLINT(readability-redundant-member-init)
|
||||
bool ok = false;
|
||||
nlohmann::detail::view::parse_failure failure{};
|
||||
};
|
||||
|
||||
built build(const std::string& text, bool comments, bool trailing_commas, bool sentinel)
|
||||
{
|
||||
built r;
|
||||
r.data.reset(document_data::create(nlohmann::detail::view::estimate_nodes(text.data(), text.size())));
|
||||
const char* src = text.c_str();
|
||||
if (!sentinel)
|
||||
{
|
||||
r.copy.assign(text.begin(), text.end());
|
||||
src = r.copy.data();
|
||||
}
|
||||
r.ok = nlohmann::detail::view::build < !nlohmann::detail::abi_config::strict_nul_handling > (*r.data, src, text.size(), comments, trailing_commas, sentinel, r.failure);
|
||||
r.data->src = src;
|
||||
r.data->base[0] = src;
|
||||
r.data->base[1] = r.data->arena.data();
|
||||
return r;
|
||||
}
|
||||
|
||||
// the value of a subtree, as json::parse would build it
|
||||
json value_of(const document_data& d, const node*& n)
|
||||
{
|
||||
const node& x = *n;
|
||||
++n;
|
||||
switch (static_cast<json::value_t>(x.kind))
|
||||
{
|
||||
case json::value_t::object:
|
||||
{
|
||||
json o = json::object();
|
||||
const node* const end = &x + x.next;
|
||||
while (n != end)
|
||||
{
|
||||
const std::string key(d.str(*n), n->len);
|
||||
++n;
|
||||
o[key] = value_of(d, n);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
case json::value_t::array:
|
||||
{
|
||||
json a = json::array();
|
||||
const node* const end = &x + x.next;
|
||||
while (n != end)
|
||||
{
|
||||
a.push_back(value_of(d, n));
|
||||
}
|
||||
return a;
|
||||
}
|
||||
case json::value_t::string:
|
||||
return std::string(d.str(x), x.len);
|
||||
case json::value_t::boolean:
|
||||
return (x.flags & nlohmann::detail::view::node_flags::is_true) != 0;
|
||||
case json::value_t::number_integer:
|
||||
return static_cast<std::int64_t>(nlohmann::detail::view::integer_bits(x));
|
||||
case json::value_t::number_unsigned:
|
||||
return nlohmann::detail::view::integer_bits(x);
|
||||
case json::value_t::number_float:
|
||||
return json::parse(std::string(d.src + x.off, x.len)).get<double>();
|
||||
case json::value_t::null:
|
||||
case json::value_t::binary:
|
||||
case json::value_t::discarded:
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
json value_of(const built& b)
|
||||
{
|
||||
const node* n = b.data->tape;
|
||||
json v = value_of(*b.data, n);
|
||||
CHECK(n == b.data->tape + b.data->tape_size);
|
||||
return v;
|
||||
}
|
||||
|
||||
// accept/reject and the value must match json::parse, for all options and
|
||||
// with and without a NUL after the text
|
||||
void check_same(const std::string& text)
|
||||
{
|
||||
CAPTURE(text);
|
||||
for (int options = 0; options < 4; ++options)
|
||||
{
|
||||
const bool comments = (options & 1) != 0;
|
||||
const bool trailing_commas = (options & 2) != 0;
|
||||
const bool accepted = json::accept(text, comments, trailing_commas);
|
||||
for (const bool sentinel :
|
||||
{
|
||||
true, false
|
||||
})
|
||||
{
|
||||
const built b = build(text, comments, trailing_commas, sentinel);
|
||||
CHECK(b.ok == accepted);
|
||||
if (b.ok && accepted)
|
||||
{
|
||||
CHECK(value_of(b) == json::parse(text, nullptr, true, comments, trailing_commas));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// a small deterministic generator of documents
|
||||
struct generator
|
||||
{
|
||||
std::mt19937 rng{5295}; // NOLINT(cert-msc32-c,cert-msc51-cpp,bugprone-random-generator-seed)
|
||||
|
||||
int r(int n)
|
||||
{
|
||||
return static_cast<int>(rng() % static_cast<unsigned>(n));
|
||||
}
|
||||
|
||||
void ws(std::string& o)
|
||||
{
|
||||
for (int n = r(4) == 0 ? r(12) : r(2); n > 0; --n)
|
||||
{
|
||||
o += " \n\t\r "[r(6)];
|
||||
}
|
||||
}
|
||||
|
||||
void str(std::string& o)
|
||||
{
|
||||
static const char* const pieces[] = {"a", "Z", " ", "~", "\\n", "\\\"", "\\\\", "\\/", "\\u00e9", "\\ud83d\\ude00", "\xc3\xa9", "\xe3\x81\x82", "\xf0\x9f\x98\x80", "\x7f", "\\u001f", "long enough text to leave the first 16 bytes"}; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
|
||||
o += '"';
|
||||
for (int n = r(3) == 0 ? r(20) : r(6); n > 0; --n)
|
||||
{
|
||||
o += pieces[r(16)];
|
||||
}
|
||||
o += '"';
|
||||
}
|
||||
|
||||
void num(std::string& o)
|
||||
{
|
||||
static const char* const numbers[] = {"0", "-0", "1", "-1", "12", "123456789", "1234567890123456789", "9223372036854775807", "-9223372036854775808", // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
|
||||
"9223372036854775808", "18446744073709551615", "18446744073709551616", "-9223372036854775809",
|
||||
"1.5", "-2.25e-3", "1e10", "1E+2", "0.000001", "3.141592653589793238462643", "1e308", "-1e-400", "123.456e7"
|
||||
};
|
||||
o += numbers[r(22)];
|
||||
}
|
||||
|
||||
void value(std::string& o, int depth)
|
||||
{
|
||||
ws(o);
|
||||
const int k = depth > 5 ? 2 + r(6) : r(8);
|
||||
if (k == 0 || k == 1)
|
||||
{
|
||||
const bool object = k == 0;
|
||||
o += object ? '{' : '[';
|
||||
for (int i = r(5); i > 0; --i)
|
||||
{
|
||||
ws(o);
|
||||
if (object)
|
||||
{
|
||||
str(o);
|
||||
ws(o);
|
||||
o += ':';
|
||||
}
|
||||
value(o, depth + 1);
|
||||
o += i > 1 ? "," : "";
|
||||
}
|
||||
ws(o);
|
||||
o += object ? '}' : ']';
|
||||
}
|
||||
else if (k < 4)
|
||||
{
|
||||
str(o);
|
||||
}
|
||||
else if (k < 6)
|
||||
{
|
||||
num(o);
|
||||
}
|
||||
else
|
||||
{
|
||||
static const char* const literals[] = {"true", "false", "null"}; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
|
||||
o += literals[r(3)];
|
||||
}
|
||||
ws(o);
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("json_view string_ref")
|
||||
{
|
||||
// std::string_view in C++17, a stand-in with the same members before
|
||||
using nlohmann::detail::view::string_ref;
|
||||
const std::string text = "abc";
|
||||
const string_ref r(text);
|
||||
CHECK(r.length() == 3);
|
||||
CHECK(std::string(r.begin(), r.end()) == "abc");
|
||||
CHECK(r[1] == 'b');
|
||||
CHECK(r != string_ref("abd"));
|
||||
CHECK_FALSE(r != string_ref("abcd", 3));
|
||||
std::ostringstream o;
|
||||
o << r;
|
||||
CHECK(o.str() == "abc");
|
||||
}
|
||||
|
||||
TEST_CASE("json_view builder")
|
||||
{
|
||||
SECTION("scalars and containers")
|
||||
{
|
||||
for (const char* text :
|
||||
{
|
||||
"null", "true", "false", "0", "-0", "42", "-42", "1.5", "\"\"", "\"abc\"", "[]", "{}", "[1,2,3]", "{\"a\":1,\"b\":[true,null]}", // NOLINT(modernize-raw-string-literal)
|
||||
" [ 1 , 2 ] ", "{\"a\" : {\"b\" : {}}}", "[[[]]]", "\"\\u00e4\\n\\ud83d\\ude00\"", "{\"a\":1,\"a\":2}", "18446744073709551616", // NOLINT(modernize-raw-string-literal)
|
||||
"-9223372036854775809", "123456789012345678901234567890", "1e400", "-1e400", "1.7976931348623157e308"
|
||||
})
|
||||
{
|
||||
check_same(text);
|
||||
}
|
||||
|
||||
// the midpoint between the largest double and 2^1024 rounds to
|
||||
// infinity (an overflow), one less to the largest double: with more
|
||||
// than 19 digits, the fast conversions cannot decide these, and the
|
||||
// overflow check falls back to strtod
|
||||
const std::string midpoint = "179769313486231580793728971405303415079934132710037826936173778980444968292764750946649017977587207096330286416692887910946555547851940402630657488671505820681908902000708383676273854845817711531764475730270069855571366959622842914819860834936475292719074168444365510704342711559699508093042880177904174497792";
|
||||
const std::string below = "179769313486231580793728971405303415079934132710037826936173778980444968292764750946649017977587207096330286416692887910946555547851940402630657488671505820681908902000708383676273854845817711531764475730270069855571366959622842914819860834936475292719074168444365510704342711559699508093042880177904174497791";
|
||||
check_same(midpoint);
|
||||
check_same("-" + midpoint);
|
||||
check_same(below);
|
||||
check_same("[" + below + "," + midpoint + "]");
|
||||
}
|
||||
|
||||
SECTION("malformed input")
|
||||
{
|
||||
for (const char* text :
|
||||
{
|
||||
"", " ", "[", "]", "{", "}", "[1,]", "{\"a\":1,}", "[1 2]", "{\"a\" 1}", "{1:2}", "tru", "nul", "fals", "truex", "-", "01", "1.", ".5", "1e", "1e+",
|
||||
"\"", "\"abc", "\"\\x\"", "\"\\u12\"", "\"\\u12G4\"", "\"\\ud800\"", "\"\\udc00\"", "\"\\ud800\\u0041\"", "\"\x01\"", "\"\xff\"", "\"\xc3\"", // NOLINT(modernize-raw-string-literal)
|
||||
"\"\xe0\x80\x80\"", "\"\xed\xa0\x80\"", "[1]x", "[1] [2]", "/", "/*", "/* */ 1", "// c\n1", "1 // c", "[1,/*c*/2]", "[1,2,]"
|
||||
})
|
||||
{
|
||||
check_same(text);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("NUL, BOM, and whitespace")
|
||||
{
|
||||
// a NUL inside a string is a control character, as for json::parse
|
||||
// (where a NUL ends the input, it does so only between values)
|
||||
for (const bool sentinel :
|
||||
{
|
||||
true, false
|
||||
})
|
||||
{
|
||||
const built b = build(std::string("[\"ab\0cd\"]", 9), false, false, sentinel);
|
||||
CHECK(!b.ok);
|
||||
CHECK(b.failure.code == nlohmann::detail::view::error_code::string_control_character);
|
||||
CHECK(b.failure.offset == 4);
|
||||
}
|
||||
check_same(std::string("[1]\0garbage", 11));
|
||||
check_same(std::string("[1\0]", 4));
|
||||
check_same(std::string("[1, // c\0\n2]", 12));
|
||||
check_same(std::string("[1, /* c\0 */ 2]", 15));
|
||||
check_same("\xEF\xBB\xBF[1]");
|
||||
check_same("\xEF\xBB[1]");
|
||||
check_same(" \t\r\n 7 \n");
|
||||
for (const char* text :
|
||||
{"[1]\r", "[1]\n", "[1]\r\n", "[1,\r2]", "[1,\r\n2]", "7\r", "\"x\"\r", "{\"a\":\r\n1}\r", "[\n 1,\n 2\n]", "{\n \"a\": [\n 1\n ]\n}"
|
||||
})
|
||||
{
|
||||
check_same(text);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("deep nesting")
|
||||
{
|
||||
// the open containers beyond 64 levels live on the heap
|
||||
for (const std::size_t depth :
|
||||
{
|
||||
63u, 64u, 65u, 1000u, 100000u
|
||||
})
|
||||
{
|
||||
const std::string arrays = std::string(depth, '[') + std::string(depth, ']');
|
||||
const built b = build(arrays, false, false, false);
|
||||
REQUIRE(b.ok);
|
||||
CHECK(b.data->tape_size == depth);
|
||||
CHECK(b.data->tape[0].next == depth);
|
||||
std::string objects;
|
||||
for (std::size_t i = 0; i < depth; ++i)
|
||||
{
|
||||
objects += "{\"a\":";
|
||||
}
|
||||
objects += '1' + std::string(depth, '}');
|
||||
const built o = build(objects, false, false, false);
|
||||
REQUIRE(o.ok);
|
||||
CHECK(o.data->tape_size == (2 * depth) + 1);
|
||||
CHECK(!build(std::string(depth, '[') + std::string(depth - 1, ']'), false, false, false).ok);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("generated documents and damaged copies")
|
||||
{
|
||||
generator g;
|
||||
for (int i = 0; i < 3000; ++i)
|
||||
{
|
||||
std::string text;
|
||||
g.value(text, 0);
|
||||
check_same(text);
|
||||
// damage: flip one byte, or cut the text
|
||||
std::string damaged = text;
|
||||
const auto at = static_cast<std::size_t>(g.r(static_cast<int>(damaged.size())));
|
||||
static const char replacements[] = {'x', '"', '\\', ',', ':', ']', '}', '[', '{', '1', '-', '.', 'e', '\0', '\n', '/'}; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
|
||||
damaged[at] = replacements[g.r(16)];
|
||||
check_same(damaged);
|
||||
check_same(text.substr(0, at));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("test files")
|
||||
{
|
||||
for (const char* name :
|
||||
{
|
||||
"/json.org/1.json", "/json.org/2.json", "/json.org/3.json", "/json.org/4.json", "/json.org/5.json",
|
||||
"/json_testsuite/sample.json", "/nativejson-benchmark/canada.json", "/nativejson-benchmark/citm_catalog.json",
|
||||
"/nativejson-benchmark/twitter.json", "/json_tests/pass1.json", "/json_tests/pass2.json", "/json_tests/pass3.json"
|
||||
})
|
||||
{
|
||||
CAPTURE(name);
|
||||
std::ifstream f(std::string(TEST_DATA_DIRECTORY) + name, std::ios::binary);
|
||||
std::stringstream ss;
|
||||
ss << f.rdbuf();
|
||||
const std::string text = ss.str();
|
||||
REQUIRE(!text.empty());
|
||||
const built b = build(text, false, false, true);
|
||||
REQUIRE(b.ok);
|
||||
CHECK(value_of(b) == json::parse(text));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,84 +22,9 @@ using nlohmann::json;
|
||||
#include <set>
|
||||
#include "make_test_data_available.hpp"
|
||||
#include "test_utils.hpp"
|
||||
#include "sax_countdown.hpp"
|
||||
using utils::SaxCountdown;
|
||||
|
||||
namespace
|
||||
{
|
||||
class SaxCountdown
|
||||
{
|
||||
public:
|
||||
explicit SaxCountdown(const int count) : events_left(count)
|
||||
{}
|
||||
|
||||
bool null()
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool boolean(bool /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool number_integer(json::number_integer_t /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool number_unsigned(json::number_unsigned_t /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool number_float(json::number_float_t /*unused*/, const std::string& /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool string(std::string& /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool binary(std::vector<std::uint8_t>& /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool start_object(std::size_t /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool key(std::string& /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool end_object()
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool start_array(std::size_t /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool end_array()
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const json::exception& /*unused*/) // NOLINT(readability-convert-member-functions-to-static)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
int events_left = 0;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("MessagePack")
|
||||
{
|
||||
|
||||
@@ -28,7 +28,7 @@ using nlohmann::json;
|
||||
DOCTEST_MSVC_SUPPRESS_WARNING_PUSH
|
||||
DOCTEST_MSVC_SUPPRESS_WARNING(4189)
|
||||
|
||||
TEST_CASE("README" * doctest::skip())
|
||||
TEST_CASE("README")
|
||||
{
|
||||
{
|
||||
// redirect std::cout for the README file
|
||||
|
||||
@@ -199,28 +199,6 @@ struct adl_serializer<NonDefaultConstructible>
|
||||
};
|
||||
} // namespace nlohmann
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// for #2824
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
class sax_no_exception : public nlohmann::detail::json_sax_dom_parser<json, nlohmann::detail::string_input_adapter_type>
|
||||
{
|
||||
public:
|
||||
explicit sax_no_exception(json& j)
|
||||
: nlohmann::detail::json_sax_dom_parser<json, nlohmann::detail::string_input_adapter_type>(j, false)
|
||||
{}
|
||||
|
||||
static bool parse_error(std::size_t /*position*/, const std::string& /*last_token*/, const json::exception& ex)
|
||||
{
|
||||
error_string = new std::string(ex.what()); // NOLINT(cppcoreguidelines-owning-memory)
|
||||
return false;
|
||||
}
|
||||
|
||||
static std::string* error_string;
|
||||
};
|
||||
|
||||
std::string* sax_no_exception::error_string = nullptr;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// for #2982
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
@@ -723,16 +701,6 @@ TEST_CASE("regression tests 2")
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("issue #2824 - encoding of json::exception::what()")
|
||||
{
|
||||
json j;
|
||||
sax_no_exception sax(j);
|
||||
|
||||
CHECK(!json::sax_parse("xyz", &sax));
|
||||
CHECK(*sax_no_exception::error_string == "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - invalid literal; last read: 'x'");
|
||||
delete sax_no_exception::error_string; // NOLINT(cppcoreguidelines-owning-memory)
|
||||
}
|
||||
|
||||
SECTION("issue #2825 - Properly constrain the basic_json conversion operator")
|
||||
{
|
||||
static_assert(std::is_copy_assignable<nlohmann::ordered_json>::value, "ordered_json must be copy assignable");
|
||||
|
||||
@@ -17,84 +17,9 @@ using nlohmann::json;
|
||||
#include "make_test_data_available.hpp"
|
||||
#include "round_trip_corpus.hpp"
|
||||
#include "test_utils.hpp"
|
||||
#include "sax_countdown.hpp"
|
||||
using utils::SaxCountdown;
|
||||
|
||||
namespace
|
||||
{
|
||||
class SaxCountdown
|
||||
{
|
||||
public:
|
||||
explicit SaxCountdown(const int count) : events_left(count)
|
||||
{}
|
||||
|
||||
bool null()
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool boolean(bool /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool number_integer(json::number_integer_t /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool number_unsigned(json::number_unsigned_t /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool number_float(json::number_float_t /*unused*/, const std::string& /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool string(std::string& /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool binary(std::vector<std::uint8_t>& /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool start_object(std::size_t /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool key(std::string& /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool end_object()
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool start_array(std::size_t /*unused*/)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool end_array()
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const json::exception& /*unused*/) // NOLINT(readability-convert-member-functions-to-static)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
int events_left = 0;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
TEST_CASE("UBJSON")
|
||||
{
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
// __ _____ _____ _____
|
||||
// __| | __| | | | JSON for Modern C++ (supporting code)
|
||||
// | | |__ | | | | | | version 3.12.0
|
||||
// |_____|_____|_____|_|___| https://github.com/nlohmann/json
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
// shared between unit-32bit.cpp (which must keep including this header,
|
||||
// because JSON_32bitTest=ONLY builds only that file) and unit-bjdata.cpp
|
||||
|
||||
#include <climits> // CHAR_BIT
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
template <typename OfType, typename T, bool MinInRange, bool MaxInRange>
|
||||
struct trait_test_arg
|
||||
{
|
||||
using of_type = OfType;
|
||||
using type = T;
|
||||
static constexpr bool min_in_range = MinInRange;
|
||||
static constexpr bool max_in_range = MaxInRange;
|
||||
};
|
||||
|
||||
TEST_CASE_TEMPLATE_DEFINE("value_in_range_of trait", T, value_in_range_of_test) // NOLINT(readability-math-missing-parentheses)
|
||||
{
|
||||
using nlohmann::detail::value_in_range_of;
|
||||
|
||||
using of_type = typename T::of_type;
|
||||
using type = typename T::type;
|
||||
constexpr bool min_in_range = T::min_in_range;
|
||||
constexpr bool max_in_range = T::max_in_range;
|
||||
|
||||
type const val_min = std::numeric_limits<type>::min();
|
||||
type const val_min2 = val_min + 1;
|
||||
type const val_max = std::numeric_limits<type>::max();
|
||||
type const val_max2 = val_max - 1;
|
||||
|
||||
REQUIRE(CHAR_BIT == 8);
|
||||
|
||||
std::string of_type_str;
|
||||
if (std::is_unsigned<of_type>::value)
|
||||
{
|
||||
of_type_str += "u";
|
||||
}
|
||||
of_type_str += "int";
|
||||
of_type_str += std::to_string(sizeof(of_type) * 8);
|
||||
|
||||
INFO("of_type := ", of_type_str);
|
||||
|
||||
std::string type_str;
|
||||
if (std::is_unsigned<type>::value)
|
||||
{
|
||||
type_str += "u";
|
||||
}
|
||||
type_str += "int";
|
||||
type_str += std::to_string(sizeof(type) * 8);
|
||||
|
||||
INFO("type := ", type_str);
|
||||
|
||||
CAPTURE(val_min);
|
||||
CAPTURE(min_in_range);
|
||||
CAPTURE(val_max);
|
||||
CAPTURE(max_in_range);
|
||||
|
||||
if (min_in_range)
|
||||
{
|
||||
CHECK(value_in_range_of<of_type>(val_min));
|
||||
CHECK(value_in_range_of<of_type>(val_min2));
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK_FALSE(value_in_range_of<of_type>(val_min));
|
||||
CHECK_FALSE(value_in_range_of<of_type>(val_min2));
|
||||
}
|
||||
|
||||
if (max_in_range)
|
||||
{
|
||||
CHECK(value_in_range_of<of_type>(val_max));
|
||||
CHECK(value_in_range_of<of_type>(val_max2));
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK_FALSE(value_in_range_of<of_type>(val_max));
|
||||
CHECK_FALSE(value_in_range_of<of_type>(val_max2));
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
set(LIBFUZZER_FLAGS_BASE "${CMAKE_CXX_FLAGS}")
|
||||
# Disable the coverage and sanitizer instrumentation for the fuzzer itself.
|
||||
set(CMAKE_CXX_FLAGS "${LIBFUZZER_FLAGS_BASE} -fno-sanitize-coverage=trace-pc-guard,edge,trace-cmp,indirect-calls,8bit-counters -Werror")
|
||||
if( LLVM_USE_SANITIZE_COVERAGE )
|
||||
if(NOT "${LLVM_USE_SANITIZER}" STREQUAL "Address")
|
||||
message(FATAL_ERROR
|
||||
"LibFuzzer and its tests require LLVM_USE_SANITIZER=Address and "
|
||||
"LLVM_USE_SANITIZE_COVERAGE=YES to be set."
|
||||
)
|
||||
endif()
|
||||
add_library(LLVMFuzzerNoMainObjects OBJECT
|
||||
FuzzerCrossOver.cpp
|
||||
FuzzerDriver.cpp
|
||||
FuzzerExtFunctionsDlsym.cpp
|
||||
FuzzerExtFunctionsWeak.cpp
|
||||
FuzzerExtFunctionsWeakAlias.cpp
|
||||
FuzzerIO.cpp
|
||||
FuzzerIOPosix.cpp
|
||||
FuzzerIOWindows.cpp
|
||||
FuzzerLoop.cpp
|
||||
FuzzerMerge.cpp
|
||||
FuzzerMutate.cpp
|
||||
FuzzerSHA1.cpp
|
||||
FuzzerTracePC.cpp
|
||||
FuzzerTraceState.cpp
|
||||
FuzzerUtil.cpp
|
||||
FuzzerUtilDarwin.cpp
|
||||
FuzzerUtilLinux.cpp
|
||||
FuzzerUtilPosix.cpp
|
||||
FuzzerUtilWindows.cpp
|
||||
)
|
||||
add_library(LLVMFuzzerNoMain STATIC
|
||||
$<TARGET_OBJECTS:LLVMFuzzerNoMainObjects>
|
||||
)
|
||||
target_link_libraries(LLVMFuzzerNoMain ${PTHREAD_LIB})
|
||||
add_library(LLVMFuzzer STATIC
|
||||
FuzzerMain.cpp
|
||||
$<TARGET_OBJECTS:LLVMFuzzerNoMainObjects>
|
||||
)
|
||||
target_link_libraries(LLVMFuzzer ${PTHREAD_LIB})
|
||||
|
||||
if( LLVM_INCLUDE_TESTS )
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
endif()
|
||||
@@ -1,217 +0,0 @@
|
||||
//===- FuzzerCorpus.h - Internal header for the Fuzzer ----------*- C++ -* ===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// fuzzer::InputCorpus
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_FUZZER_CORPUS
|
||||
#define LLVM_FUZZER_CORPUS
|
||||
|
||||
#include "FuzzerDefs.h"
|
||||
#include "FuzzerIO.h"
|
||||
#include "FuzzerRandom.h"
|
||||
#include "FuzzerSHA1.h"
|
||||
#include "FuzzerTracePC.h"
|
||||
#include <numeric>
|
||||
#include <random>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
struct InputInfo {
|
||||
Unit U; // The actual input data.
|
||||
uint8_t Sha1[kSHA1NumBytes]; // Checksum.
|
||||
// Number of features that this input has and no smaller input has.
|
||||
size_t NumFeatures = 0;
|
||||
size_t Tmp = 0; // Used by ValidateFeatureSet.
|
||||
// Stats.
|
||||
size_t NumExecutedMutations = 0;
|
||||
size_t NumSuccessfullMutations = 0;
|
||||
bool MayDeleteFile = false;
|
||||
};
|
||||
|
||||
class InputCorpus {
|
||||
public:
|
||||
static const size_t kFeatureSetSize = 1 << 16;
|
||||
InputCorpus(const std::string &OutputCorpus) : OutputCorpus(OutputCorpus) {
|
||||
memset(InputSizesPerFeature, 0, sizeof(InputSizesPerFeature));
|
||||
memset(SmallestElementPerFeature, 0, sizeof(SmallestElementPerFeature));
|
||||
}
|
||||
~InputCorpus() {
|
||||
for (auto II : Inputs)
|
||||
delete II;
|
||||
}
|
||||
size_t size() const { return Inputs.size(); }
|
||||
size_t SizeInBytes() const {
|
||||
size_t Res = 0;
|
||||
for (auto II : Inputs)
|
||||
Res += II->U.size();
|
||||
return Res;
|
||||
}
|
||||
size_t NumActiveUnits() const {
|
||||
size_t Res = 0;
|
||||
for (auto II : Inputs)
|
||||
Res += !II->U.empty();
|
||||
return Res;
|
||||
}
|
||||
bool empty() const { return Inputs.empty(); }
|
||||
const Unit &operator[] (size_t Idx) const { return Inputs[Idx]->U; }
|
||||
void AddToCorpus(const Unit &U, size_t NumFeatures, bool MayDeleteFile = false) {
|
||||
assert(!U.empty());
|
||||
uint8_t Hash[kSHA1NumBytes];
|
||||
if (FeatureDebug)
|
||||
Printf("ADD_TO_CORPUS %zd NF %zd\n", Inputs.size(), NumFeatures);
|
||||
ComputeSHA1(U.data(), U.size(), Hash);
|
||||
Hashes.insert(Sha1ToString(Hash));
|
||||
Inputs.push_back(new InputInfo());
|
||||
InputInfo &II = *Inputs.back();
|
||||
II.U = U;
|
||||
II.NumFeatures = NumFeatures;
|
||||
II.MayDeleteFile = MayDeleteFile;
|
||||
memcpy(II.Sha1, Hash, kSHA1NumBytes);
|
||||
UpdateCorpusDistribution();
|
||||
ValidateFeatureSet();
|
||||
}
|
||||
|
||||
bool HasUnit(const Unit &U) { return Hashes.count(Hash(U)); }
|
||||
bool HasUnit(const std::string &H) { return Hashes.count(H); }
|
||||
InputInfo &ChooseUnitToMutate(Random &Rand) {
|
||||
InputInfo &II = *Inputs[ChooseUnitIdxToMutate(Rand)];
|
||||
assert(!II.U.empty());
|
||||
return II;
|
||||
};
|
||||
|
||||
// Returns an index of random unit from the corpus to mutate.
|
||||
// Hypothesis: units added to the corpus last are more likely to be
|
||||
// interesting. This function gives more weight to the more recent units.
|
||||
size_t ChooseUnitIdxToMutate(Random &Rand) {
|
||||
size_t Idx = static_cast<size_t>(CorpusDistribution(Rand.Get_mt19937()));
|
||||
assert(Idx < Inputs.size());
|
||||
return Idx;
|
||||
}
|
||||
|
||||
void PrintStats() {
|
||||
for (size_t i = 0; i < Inputs.size(); i++) {
|
||||
const auto &II = *Inputs[i];
|
||||
Printf(" [%zd %s]\tsz: %zd\truns: %zd\tsucc: %zd\n", i,
|
||||
Sha1ToString(II.Sha1).c_str(), II.U.size(),
|
||||
II.NumExecutedMutations, II.NumSuccessfullMutations);
|
||||
}
|
||||
}
|
||||
|
||||
void PrintFeatureSet() {
|
||||
for (size_t i = 0; i < kFeatureSetSize; i++) {
|
||||
if(size_t Sz = GetFeature(i))
|
||||
Printf("[%zd: id %zd sz%zd] ", i, SmallestElementPerFeature[i], Sz);
|
||||
}
|
||||
Printf("\n\t");
|
||||
for (size_t i = 0; i < Inputs.size(); i++)
|
||||
if (size_t N = Inputs[i]->NumFeatures)
|
||||
Printf(" %zd=>%zd ", i, N);
|
||||
Printf("\n");
|
||||
}
|
||||
|
||||
void DeleteInput(size_t Idx) {
|
||||
InputInfo &II = *Inputs[Idx];
|
||||
if (!OutputCorpus.empty() && II.MayDeleteFile)
|
||||
RemoveFile(DirPlusFile(OutputCorpus, Sha1ToString(II.Sha1)));
|
||||
Unit().swap(II.U);
|
||||
if (FeatureDebug)
|
||||
Printf("EVICTED %zd\n", Idx);
|
||||
}
|
||||
|
||||
bool AddFeature(size_t Idx, uint32_t NewSize, bool Shrink) {
|
||||
assert(NewSize);
|
||||
Idx = Idx % kFeatureSetSize;
|
||||
uint32_t OldSize = GetFeature(Idx);
|
||||
if (OldSize == 0 || (Shrink && OldSize > NewSize)) {
|
||||
if (OldSize > 0) {
|
||||
size_t OldIdx = SmallestElementPerFeature[Idx];
|
||||
InputInfo &II = *Inputs[OldIdx];
|
||||
assert(II.NumFeatures > 0);
|
||||
II.NumFeatures--;
|
||||
if (II.NumFeatures == 0)
|
||||
DeleteInput(OldIdx);
|
||||
}
|
||||
if (FeatureDebug)
|
||||
Printf("ADD FEATURE %zd sz %d\n", Idx, NewSize);
|
||||
SmallestElementPerFeature[Idx] = Inputs.size();
|
||||
InputSizesPerFeature[Idx] = NewSize;
|
||||
CountingFeatures = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t NumFeatures() const {
|
||||
size_t Res = 0;
|
||||
for (size_t i = 0; i < kFeatureSetSize; i++)
|
||||
Res += GetFeature(i) != 0;
|
||||
return Res;
|
||||
}
|
||||
|
||||
void ResetFeatureSet() {
|
||||
assert(Inputs.empty());
|
||||
memset(InputSizesPerFeature, 0, sizeof(InputSizesPerFeature));
|
||||
memset(SmallestElementPerFeature, 0, sizeof(SmallestElementPerFeature));
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
static const bool FeatureDebug = false;
|
||||
|
||||
size_t GetFeature(size_t Idx) const { return InputSizesPerFeature[Idx]; }
|
||||
|
||||
void ValidateFeatureSet() {
|
||||
if (!CountingFeatures) return;
|
||||
if (FeatureDebug)
|
||||
PrintFeatureSet();
|
||||
for (size_t Idx = 0; Idx < kFeatureSetSize; Idx++)
|
||||
if (GetFeature(Idx))
|
||||
Inputs[SmallestElementPerFeature[Idx]]->Tmp++;
|
||||
for (auto II: Inputs) {
|
||||
if (II->Tmp != II->NumFeatures)
|
||||
Printf("ZZZ %zd %zd\n", II->Tmp, II->NumFeatures);
|
||||
assert(II->Tmp == II->NumFeatures);
|
||||
II->Tmp = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Updates the probability distribution for the units in the corpus.
|
||||
// Must be called whenever the corpus or unit weights are changed.
|
||||
void UpdateCorpusDistribution() {
|
||||
size_t N = Inputs.size();
|
||||
Intervals.resize(N + 1);
|
||||
Weights.resize(N);
|
||||
std::iota(Intervals.begin(), Intervals.end(), 0);
|
||||
if (CountingFeatures)
|
||||
for (size_t i = 0; i < N; i++)
|
||||
Weights[i] = Inputs[i]->NumFeatures * (i + 1);
|
||||
else
|
||||
std::iota(Weights.begin(), Weights.end(), 1);
|
||||
CorpusDistribution = std::piecewise_constant_distribution<double>(
|
||||
Intervals.begin(), Intervals.end(), Weights.begin());
|
||||
}
|
||||
std::piecewise_constant_distribution<double> CorpusDistribution;
|
||||
|
||||
std::vector<double> Intervals;
|
||||
std::vector<double> Weights;
|
||||
|
||||
std::unordered_set<std::string> Hashes;
|
||||
std::vector<InputInfo*> Inputs;
|
||||
|
||||
bool CountingFeatures = false;
|
||||
uint32_t InputSizesPerFeature[kFeatureSetSize];
|
||||
uint32_t SmallestElementPerFeature[kFeatureSetSize];
|
||||
|
||||
std::string OutputCorpus;
|
||||
};
|
||||
|
||||
} // namespace fuzzer
|
||||
|
||||
#endif // LLVM_FUZZER_CORPUS
|
||||
@@ -1,52 +0,0 @@
|
||||
//===- FuzzerCrossOver.cpp - Cross over two test inputs -------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Cross over test inputs.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "FuzzerDefs.h"
|
||||
#include "FuzzerMutate.h"
|
||||
#include "FuzzerRandom.h"
|
||||
#include <cstring>
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
// Cross Data1 and Data2, store the result (up to MaxOutSize bytes) in Out.
|
||||
size_t MutationDispatcher::CrossOver(const uint8_t *Data1, size_t Size1,
|
||||
const uint8_t *Data2, size_t Size2,
|
||||
uint8_t *Out, size_t MaxOutSize) {
|
||||
assert(Size1 || Size2);
|
||||
MaxOutSize = Rand(MaxOutSize) + 1;
|
||||
size_t OutPos = 0;
|
||||
size_t Pos1 = 0;
|
||||
size_t Pos2 = 0;
|
||||
size_t *InPos = &Pos1;
|
||||
size_t InSize = Size1;
|
||||
const uint8_t *Data = Data1;
|
||||
bool CurrentlyUsingFirstData = true;
|
||||
while (OutPos < MaxOutSize && (Pos1 < Size1 || Pos2 < Size2)) {
|
||||
// Merge a part of Data into Out.
|
||||
size_t OutSizeLeft = MaxOutSize - OutPos;
|
||||
if (*InPos < InSize) {
|
||||
size_t InSizeLeft = InSize - *InPos;
|
||||
size_t MaxExtraSize = std::min(OutSizeLeft, InSizeLeft);
|
||||
size_t ExtraSize = Rand(MaxExtraSize) + 1;
|
||||
memcpy(Out + OutPos, Data + *InPos, ExtraSize);
|
||||
OutPos += ExtraSize;
|
||||
(*InPos) += ExtraSize;
|
||||
}
|
||||
// Use the other input data on the next iteration.
|
||||
InPos = CurrentlyUsingFirstData ? &Pos2 : &Pos1;
|
||||
InSize = CurrentlyUsingFirstData ? Size2 : Size1;
|
||||
Data = CurrentlyUsingFirstData ? Data2 : Data1;
|
||||
CurrentlyUsingFirstData = !CurrentlyUsingFirstData;
|
||||
}
|
||||
return OutPos;
|
||||
}
|
||||
|
||||
} // namespace fuzzer
|
||||
@@ -1,89 +0,0 @@
|
||||
//===- FuzzerDefs.h - Internal header for the Fuzzer ------------*- C++ -* ===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Basic definitions.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_FUZZER_DEFS_H
|
||||
#define LLVM_FUZZER_DEFS_H
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// Platform detection.
|
||||
#ifdef __linux__
|
||||
#define LIBFUZZER_APPLE 0
|
||||
#define LIBFUZZER_LINUX 1
|
||||
#define LIBFUZZER_WINDOWS 0
|
||||
#elif __APPLE__
|
||||
#define LIBFUZZER_APPLE 1
|
||||
#define LIBFUZZER_LINUX 0
|
||||
#define LIBFUZZER_WINDOWS 0
|
||||
#elif _WIN32
|
||||
#define LIBFUZZER_APPLE 0
|
||||
#define LIBFUZZER_LINUX 0
|
||||
#define LIBFUZZER_WINDOWS 1
|
||||
#else
|
||||
#error "Support for your platform has not been implemented"
|
||||
#endif
|
||||
|
||||
#define LIBFUZZER_POSIX LIBFUZZER_APPLE || LIBFUZZER_LINUX
|
||||
|
||||
#ifdef __x86_64
|
||||
#define ATTRIBUTE_TARGET_POPCNT __attribute__((target("popcnt")))
|
||||
#else
|
||||
#define ATTRIBUTE_TARGET_POPCNT
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __clang__ // avoid gcc warning.
|
||||
# define ATTRIBUTE_NO_SANITIZE_MEMORY __attribute__((no_sanitize("memory")))
|
||||
#else
|
||||
# define ATTRIBUTE_NO_SANITIZE_MEMORY
|
||||
#endif
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
template <class T> T Min(T a, T b) { return a < b ? a : b; }
|
||||
template <class T> T Max(T a, T b) { return a > b ? a : b; }
|
||||
|
||||
class Random;
|
||||
class Dictionary;
|
||||
class DictionaryEntry;
|
||||
class MutationDispatcher;
|
||||
struct FuzzingOptions;
|
||||
class InputCorpus;
|
||||
struct InputInfo;
|
||||
struct ExternalFunctions;
|
||||
|
||||
// Global interface to functions that may or may not be available.
|
||||
extern ExternalFunctions *EF;
|
||||
|
||||
typedef std::vector<uint8_t> Unit;
|
||||
typedef std::vector<Unit> UnitVector;
|
||||
typedef int (*UserCallback)(const uint8_t *Data, size_t Size);
|
||||
|
||||
int FuzzerDriver(int *argc, char ***argv, UserCallback Callback);
|
||||
|
||||
struct ScopedDoingMyOwnMemmem {
|
||||
ScopedDoingMyOwnMemmem();
|
||||
~ScopedDoingMyOwnMemmem();
|
||||
};
|
||||
|
||||
inline uint8_t Bswap(uint8_t x) { return x; }
|
||||
inline uint16_t Bswap(uint16_t x) { return __builtin_bswap16(x); }
|
||||
inline uint32_t Bswap(uint32_t x) { return __builtin_bswap32(x); }
|
||||
inline uint64_t Bswap(uint64_t x) { return __builtin_bswap64(x); }
|
||||
|
||||
} // namespace fuzzer
|
||||
|
||||
#endif // LLVM_FUZZER_DEFS_H
|
||||
@@ -1,124 +0,0 @@
|
||||
//===- FuzzerDictionary.h - Internal header for the Fuzzer ------*- C++ -* ===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// fuzzer::Dictionary
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_FUZZER_DICTIONARY_H
|
||||
#define LLVM_FUZZER_DICTIONARY_H
|
||||
|
||||
#include "FuzzerDefs.h"
|
||||
#include "FuzzerIO.h"
|
||||
#include "FuzzerUtil.h"
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
||||
namespace fuzzer {
|
||||
// A simple POD sized array of bytes.
|
||||
template <size_t kMaxSize> class FixedWord {
|
||||
public:
|
||||
FixedWord() {}
|
||||
FixedWord(const uint8_t *B, uint8_t S) { Set(B, S); }
|
||||
|
||||
void Set(const uint8_t *B, uint8_t S) {
|
||||
assert(S <= kMaxSize);
|
||||
memcpy(Data, B, S);
|
||||
Size = S;
|
||||
}
|
||||
|
||||
bool operator==(const FixedWord<kMaxSize> &w) const {
|
||||
return Size == w.Size && 0 == memcmp(Data, w.Data, Size);
|
||||
}
|
||||
|
||||
bool operator<(const FixedWord<kMaxSize> &w) const {
|
||||
if (Size != w.Size)
|
||||
return Size < w.Size;
|
||||
return memcmp(Data, w.Data, Size) < 0;
|
||||
}
|
||||
|
||||
static size_t GetMaxSize() { return kMaxSize; }
|
||||
const uint8_t *data() const { return Data; }
|
||||
uint8_t size() const { return Size; }
|
||||
|
||||
private:
|
||||
uint8_t Size = 0;
|
||||
uint8_t Data[kMaxSize];
|
||||
};
|
||||
|
||||
typedef FixedWord<27> Word; // 28 bytes.
|
||||
|
||||
class DictionaryEntry {
|
||||
public:
|
||||
DictionaryEntry() {}
|
||||
DictionaryEntry(Word W) : W(W) {}
|
||||
DictionaryEntry(Word W, size_t PositionHint) : W(W), PositionHint(PositionHint) {}
|
||||
const Word &GetW() const { return W; }
|
||||
|
||||
bool HasPositionHint() const { return PositionHint != std::numeric_limits<size_t>::max(); }
|
||||
size_t GetPositionHint() const {
|
||||
assert(HasPositionHint());
|
||||
return PositionHint;
|
||||
}
|
||||
void IncUseCount() { UseCount++; }
|
||||
void IncSuccessCount() { SuccessCount++; }
|
||||
size_t GetUseCount() const { return UseCount; }
|
||||
size_t GetSuccessCount() const {return SuccessCount; }
|
||||
|
||||
void Print(const char *PrintAfter = "\n") {
|
||||
PrintASCII(W.data(), W.size());
|
||||
if (HasPositionHint())
|
||||
Printf("@%zd", GetPositionHint());
|
||||
Printf("%s", PrintAfter);
|
||||
}
|
||||
|
||||
private:
|
||||
Word W;
|
||||
size_t PositionHint = std::numeric_limits<size_t>::max();
|
||||
size_t UseCount = 0;
|
||||
size_t SuccessCount = 0;
|
||||
};
|
||||
|
||||
class Dictionary {
|
||||
public:
|
||||
static const size_t kMaxDictSize = 1 << 14;
|
||||
|
||||
bool ContainsWord(const Word &W) const {
|
||||
return std::any_of(begin(), end(), [&](const DictionaryEntry &DE) {
|
||||
return DE.GetW() == W;
|
||||
});
|
||||
}
|
||||
const DictionaryEntry *begin() const { return &DE[0]; }
|
||||
const DictionaryEntry *end() const { return begin() + Size; }
|
||||
DictionaryEntry & operator[] (size_t Idx) {
|
||||
assert(Idx < Size);
|
||||
return DE[Idx];
|
||||
}
|
||||
void push_back(DictionaryEntry DE) {
|
||||
if (Size < kMaxDictSize)
|
||||
this->DE[Size++] = DE;
|
||||
}
|
||||
void clear() { Size = 0; }
|
||||
bool empty() const { return Size == 0; }
|
||||
size_t size() const { return Size; }
|
||||
|
||||
private:
|
||||
DictionaryEntry DE[kMaxDictSize];
|
||||
size_t Size = 0;
|
||||
};
|
||||
|
||||
// Parses one dictionary entry.
|
||||
// If successfull, write the enty to Unit and returns true,
|
||||
// otherwise returns false.
|
||||
bool ParseOneDictionaryEntry(const std::string &Str, Unit *U);
|
||||
// Parses the dictionary file, fills Units, returns true iff all lines
|
||||
// were parsed succesfully.
|
||||
bool ParseDictionaryFile(const std::string &Text, std::vector<Unit> *Units);
|
||||
|
||||
} // namespace fuzzer
|
||||
|
||||
#endif // LLVM_FUZZER_DICTIONARY_H
|
||||
@@ -1,545 +0,0 @@
|
||||
//===- FuzzerDriver.cpp - FuzzerDriver function and flags -----------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// FuzzerDriver and flag parsing.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "FuzzerCorpus.h"
|
||||
#include "FuzzerInterface.h"
|
||||
#include "FuzzerInternal.h"
|
||||
#include "FuzzerIO.h"
|
||||
#include "FuzzerMutate.h"
|
||||
#include "FuzzerRandom.h"
|
||||
#include "FuzzerTracePC.h"
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <cstring>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
// This function should be present in the libFuzzer so that the client
|
||||
// binary can test for its existence.
|
||||
extern "C" __attribute__((used)) void __libfuzzer_is_present() {}
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
// Program arguments.
|
||||
struct FlagDescription {
|
||||
const char *Name;
|
||||
const char *Description;
|
||||
int Default;
|
||||
int *IntFlag;
|
||||
const char **StrFlag;
|
||||
unsigned int *UIntFlag;
|
||||
};
|
||||
|
||||
struct {
|
||||
#define FUZZER_DEPRECATED_FLAG(Name)
|
||||
#define FUZZER_FLAG_INT(Name, Default, Description) int Name;
|
||||
#define FUZZER_FLAG_UNSIGNED(Name, Default, Description) unsigned int Name;
|
||||
#define FUZZER_FLAG_STRING(Name, Description) const char *Name;
|
||||
#include "FuzzerFlags.def"
|
||||
#undef FUZZER_DEPRECATED_FLAG
|
||||
#undef FUZZER_FLAG_INT
|
||||
#undef FUZZER_FLAG_UNSIGNED
|
||||
#undef FUZZER_FLAG_STRING
|
||||
} Flags;
|
||||
|
||||
static const FlagDescription FlagDescriptions [] {
|
||||
#define FUZZER_DEPRECATED_FLAG(Name) \
|
||||
{#Name, "Deprecated; don't use", 0, nullptr, nullptr, nullptr},
|
||||
#define FUZZER_FLAG_INT(Name, Default, Description) \
|
||||
{#Name, Description, Default, &Flags.Name, nullptr, nullptr},
|
||||
#define FUZZER_FLAG_UNSIGNED(Name, Default, Description) \
|
||||
{#Name, Description, static_cast<int>(Default), \
|
||||
nullptr, nullptr, &Flags.Name},
|
||||
#define FUZZER_FLAG_STRING(Name, Description) \
|
||||
{#Name, Description, 0, nullptr, &Flags.Name, nullptr},
|
||||
#include "FuzzerFlags.def"
|
||||
#undef FUZZER_DEPRECATED_FLAG
|
||||
#undef FUZZER_FLAG_INT
|
||||
#undef FUZZER_FLAG_UNSIGNED
|
||||
#undef FUZZER_FLAG_STRING
|
||||
};
|
||||
|
||||
static const size_t kNumFlags =
|
||||
sizeof(FlagDescriptions) / sizeof(FlagDescriptions[0]);
|
||||
|
||||
static std::vector<std::string> *Inputs;
|
||||
static std::string *ProgName;
|
||||
|
||||
static void PrintHelp() {
|
||||
Printf("Usage:\n");
|
||||
auto Prog = ProgName->c_str();
|
||||
Printf("\nTo run fuzzing pass 0 or more directories.\n");
|
||||
Printf("%s [-flag1=val1 [-flag2=val2 ...] ] [dir1 [dir2 ...] ]\n", Prog);
|
||||
|
||||
Printf("\nTo run individual tests without fuzzing pass 1 or more files:\n");
|
||||
Printf("%s [-flag1=val1 [-flag2=val2 ...] ] file1 [file2 ...]\n", Prog);
|
||||
|
||||
Printf("\nFlags: (strictly in form -flag=value)\n");
|
||||
size_t MaxFlagLen = 0;
|
||||
for (size_t F = 0; F < kNumFlags; F++)
|
||||
MaxFlagLen = std::max(strlen(FlagDescriptions[F].Name), MaxFlagLen);
|
||||
|
||||
for (size_t F = 0; F < kNumFlags; F++) {
|
||||
const auto &D = FlagDescriptions[F];
|
||||
if (strstr(D.Description, "internal flag") == D.Description) continue;
|
||||
Printf(" %s", D.Name);
|
||||
for (size_t i = 0, n = MaxFlagLen - strlen(D.Name); i < n; i++)
|
||||
Printf(" ");
|
||||
Printf("\t");
|
||||
Printf("%d\t%s\n", D.Default, D.Description);
|
||||
}
|
||||
Printf("\nFlags starting with '--' will be ignored and "
|
||||
"will be passed verbatim to subprocesses.\n");
|
||||
}
|
||||
|
||||
static const char *FlagValue(const char *Param, const char *Name) {
|
||||
size_t Len = strlen(Name);
|
||||
if (Param[0] == '-' && strstr(Param + 1, Name) == Param + 1 &&
|
||||
Param[Len + 1] == '=')
|
||||
return &Param[Len + 2];
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Avoid calling stol as it triggers a bug in clang/glibc build.
|
||||
static long MyStol(const char *Str) {
|
||||
long Res = 0;
|
||||
long Sign = 1;
|
||||
if (*Str == '-') {
|
||||
Str++;
|
||||
Sign = -1;
|
||||
}
|
||||
for (size_t i = 0; Str[i]; i++) {
|
||||
char Ch = Str[i];
|
||||
if (Ch < '0' || Ch > '9')
|
||||
return Res;
|
||||
Res = Res * 10 + (Ch - '0');
|
||||
}
|
||||
return Res * Sign;
|
||||
}
|
||||
|
||||
static bool ParseOneFlag(const char *Param) {
|
||||
if (Param[0] != '-') return false;
|
||||
if (Param[1] == '-') {
|
||||
static bool PrintedWarning = false;
|
||||
if (!PrintedWarning) {
|
||||
PrintedWarning = true;
|
||||
Printf("INFO: libFuzzer ignores flags that start with '--'\n");
|
||||
}
|
||||
for (size_t F = 0; F < kNumFlags; F++)
|
||||
if (FlagValue(Param + 1, FlagDescriptions[F].Name))
|
||||
Printf("WARNING: did you mean '%s' (single dash)?\n", Param + 1);
|
||||
return true;
|
||||
}
|
||||
for (size_t F = 0; F < kNumFlags; F++) {
|
||||
const char *Name = FlagDescriptions[F].Name;
|
||||
const char *Str = FlagValue(Param, Name);
|
||||
if (Str) {
|
||||
if (FlagDescriptions[F].IntFlag) {
|
||||
int Val = MyStol(Str);
|
||||
*FlagDescriptions[F].IntFlag = Val;
|
||||
if (Flags.verbosity >= 2)
|
||||
Printf("Flag: %s %d\n", Name, Val);
|
||||
return true;
|
||||
} else if (FlagDescriptions[F].UIntFlag) {
|
||||
unsigned int Val = std::stoul(Str);
|
||||
*FlagDescriptions[F].UIntFlag = Val;
|
||||
if (Flags.verbosity >= 2)
|
||||
Printf("Flag: %s %u\n", Name, Val);
|
||||
return true;
|
||||
} else if (FlagDescriptions[F].StrFlag) {
|
||||
*FlagDescriptions[F].StrFlag = Str;
|
||||
if (Flags.verbosity >= 2)
|
||||
Printf("Flag: %s %s\n", Name, Str);
|
||||
return true;
|
||||
} else { // Deprecated flag.
|
||||
Printf("Flag: %s: deprecated, don't use\n", Name);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
Printf("\n\nWARNING: unrecognized flag '%s'; "
|
||||
"use -help=1 to list all flags\n\n", Param);
|
||||
return true;
|
||||
}
|
||||
|
||||
// We don't use any library to minimize dependencies.
|
||||
static void ParseFlags(const std::vector<std::string> &Args) {
|
||||
for (size_t F = 0; F < kNumFlags; F++) {
|
||||
if (FlagDescriptions[F].IntFlag)
|
||||
*FlagDescriptions[F].IntFlag = FlagDescriptions[F].Default;
|
||||
if (FlagDescriptions[F].UIntFlag)
|
||||
*FlagDescriptions[F].UIntFlag =
|
||||
static_cast<unsigned int>(FlagDescriptions[F].Default);
|
||||
if (FlagDescriptions[F].StrFlag)
|
||||
*FlagDescriptions[F].StrFlag = nullptr;
|
||||
}
|
||||
Inputs = new std::vector<std::string>;
|
||||
for (size_t A = 1; A < Args.size(); A++) {
|
||||
if (ParseOneFlag(Args[A].c_str())) continue;
|
||||
Inputs->push_back(Args[A]);
|
||||
}
|
||||
}
|
||||
|
||||
static std::mutex Mu;
|
||||
|
||||
static void PulseThread() {
|
||||
while (true) {
|
||||
SleepSeconds(600);
|
||||
std::lock_guard<std::mutex> Lock(Mu);
|
||||
Printf("pulse...\n");
|
||||
}
|
||||
}
|
||||
|
||||
static void WorkerThread(const std::string &Cmd, std::atomic<unsigned> *Counter,
|
||||
unsigned NumJobs, std::atomic<bool> *HasErrors) {
|
||||
while (true) {
|
||||
unsigned C = (*Counter)++;
|
||||
if (C >= NumJobs) break;
|
||||
std::string Log = "fuzz-" + std::to_string(C) + ".log";
|
||||
std::string ToRun = Cmd + " > " + Log + " 2>&1\n";
|
||||
if (Flags.verbosity)
|
||||
Printf("%s", ToRun.c_str());
|
||||
int ExitCode = ExecuteCommand(ToRun);
|
||||
if (ExitCode != 0)
|
||||
*HasErrors = true;
|
||||
std::lock_guard<std::mutex> Lock(Mu);
|
||||
Printf("================== Job %u exited with exit code %d ============\n",
|
||||
C, ExitCode);
|
||||
fuzzer::CopyFileToErr(Log);
|
||||
}
|
||||
}
|
||||
|
||||
std::string CloneArgsWithoutX(const std::vector<std::string> &Args,
|
||||
const char *X1, const char *X2) {
|
||||
std::string Cmd;
|
||||
for (auto &S : Args) {
|
||||
if (FlagValue(S.c_str(), X1) || FlagValue(S.c_str(), X2))
|
||||
continue;
|
||||
Cmd += S + " ";
|
||||
}
|
||||
return Cmd;
|
||||
}
|
||||
|
||||
static int RunInMultipleProcesses(const std::vector<std::string> &Args,
|
||||
unsigned NumWorkers, unsigned NumJobs) {
|
||||
std::atomic<unsigned> Counter(0);
|
||||
std::atomic<bool> HasErrors(false);
|
||||
std::string Cmd = CloneArgsWithoutX(Args, "jobs", "workers");
|
||||
std::vector<std::thread> V;
|
||||
std::thread Pulse(PulseThread);
|
||||
Pulse.detach();
|
||||
for (unsigned i = 0; i < NumWorkers; i++)
|
||||
V.push_back(std::thread(WorkerThread, Cmd, &Counter, NumJobs, &HasErrors));
|
||||
for (auto &T : V)
|
||||
T.join();
|
||||
return HasErrors ? 1 : 0;
|
||||
}
|
||||
|
||||
static void RssThread(Fuzzer *F, size_t RssLimitMb) {
|
||||
while (true) {
|
||||
SleepSeconds(1);
|
||||
size_t Peak = GetPeakRSSMb();
|
||||
if (Peak > RssLimitMb)
|
||||
F->RssLimitCallback();
|
||||
}
|
||||
}
|
||||
|
||||
static void StartRssThread(Fuzzer *F, size_t RssLimitMb) {
|
||||
if (!RssLimitMb) return;
|
||||
std::thread T(RssThread, F, RssLimitMb);
|
||||
T.detach();
|
||||
}
|
||||
|
||||
int RunOneTest(Fuzzer *F, const char *InputFilePath, size_t MaxLen) {
|
||||
Unit U = FileToVector(InputFilePath);
|
||||
if (MaxLen && MaxLen < U.size())
|
||||
U.resize(MaxLen);
|
||||
F->RunOne(U.data(), U.size());
|
||||
F->TryDetectingAMemoryLeak(U.data(), U.size(), true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool AllInputsAreFiles() {
|
||||
if (Inputs->empty()) return false;
|
||||
for (auto &Path : *Inputs)
|
||||
if (!IsFile(Path))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
int MinimizeCrashInput(const std::vector<std::string> &Args) {
|
||||
if (Inputs->size() != 1) {
|
||||
Printf("ERROR: -minimize_crash should be given one input file\n");
|
||||
exit(1);
|
||||
}
|
||||
std::string InputFilePath = Inputs->at(0);
|
||||
std::string BaseCmd =
|
||||
CloneArgsWithoutX(Args, "minimize_crash", "exact_artifact_path");
|
||||
auto InputPos = BaseCmd.find(" " + InputFilePath + " ");
|
||||
assert(InputPos != std::string::npos);
|
||||
BaseCmd.erase(InputPos, InputFilePath.size() + 1);
|
||||
if (Flags.runs <= 0 && Flags.max_total_time == 0) {
|
||||
Printf("INFO: you need to specify -runs=N or "
|
||||
"-max_total_time=N with -minimize_crash=1\n"
|
||||
"INFO: defaulting to -max_total_time=600\n");
|
||||
BaseCmd += " -max_total_time=600";
|
||||
}
|
||||
// BaseCmd += " > /dev/null 2>&1 ";
|
||||
|
||||
std::string CurrentFilePath = InputFilePath;
|
||||
while (true) {
|
||||
Unit U = FileToVector(CurrentFilePath);
|
||||
if (U.size() < 2) {
|
||||
Printf("CRASH_MIN: '%s' is small enough\n", CurrentFilePath.c_str());
|
||||
return 0;
|
||||
}
|
||||
Printf("CRASH_MIN: minimizing crash input: '%s' (%zd bytes)\n",
|
||||
CurrentFilePath.c_str(), U.size());
|
||||
|
||||
auto Cmd = BaseCmd + " " + CurrentFilePath;
|
||||
|
||||
Printf("CRASH_MIN: executing: %s\n", Cmd.c_str());
|
||||
int ExitCode = ExecuteCommand(Cmd);
|
||||
if (ExitCode == 0) {
|
||||
Printf("ERROR: the input %s did not crash\n", CurrentFilePath.c_str());
|
||||
exit(1);
|
||||
}
|
||||
Printf("CRASH_MIN: '%s' (%zd bytes) caused a crash. Will try to minimize "
|
||||
"it further\n",
|
||||
CurrentFilePath.c_str(), U.size());
|
||||
|
||||
std::string ArtifactPath = "minimized-from-" + Hash(U);
|
||||
Cmd += " -minimize_crash_internal_step=1 -exact_artifact_path=" +
|
||||
ArtifactPath;
|
||||
Printf("CRASH_MIN: executing: %s\n", Cmd.c_str());
|
||||
ExitCode = ExecuteCommand(Cmd);
|
||||
if (ExitCode == 0) {
|
||||
if (Flags.exact_artifact_path) {
|
||||
CurrentFilePath = Flags.exact_artifact_path;
|
||||
WriteToFile(U, CurrentFilePath);
|
||||
}
|
||||
Printf("CRASH_MIN: failed to minimize beyond %s (%d bytes), exiting\n",
|
||||
CurrentFilePath.c_str(), U.size());
|
||||
return 0;
|
||||
}
|
||||
CurrentFilePath = ArtifactPath;
|
||||
Printf("\n\n\n\n\n\n*********************************\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int MinimizeCrashInputInternalStep(Fuzzer *F, InputCorpus *Corpus) {
|
||||
assert(Inputs->size() == 1);
|
||||
std::string InputFilePath = Inputs->at(0);
|
||||
Unit U = FileToVector(InputFilePath);
|
||||
assert(U.size() > 2);
|
||||
Printf("INFO: Starting MinimizeCrashInputInternalStep: %zd\n", U.size());
|
||||
Corpus->AddToCorpus(U, 0);
|
||||
F->SetMaxInputLen(U.size());
|
||||
F->SetMaxMutationLen(U.size() - 1);
|
||||
F->MinimizeCrashLoop(U);
|
||||
Printf("INFO: Done MinimizeCrashInputInternalStep, no crashes found\n");
|
||||
exit(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int FuzzerDriver(int *argc, char ***argv, UserCallback Callback) {
|
||||
using namespace fuzzer;
|
||||
assert(argc && argv && "Argument pointers cannot be nullptr");
|
||||
EF = new ExternalFunctions();
|
||||
if (EF->LLVMFuzzerInitialize)
|
||||
EF->LLVMFuzzerInitialize(argc, argv);
|
||||
const std::vector<std::string> Args(*argv, *argv + *argc);
|
||||
assert(!Args.empty());
|
||||
ProgName = new std::string(Args[0]);
|
||||
ParseFlags(Args);
|
||||
if (Flags.help) {
|
||||
PrintHelp();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (Flags.minimize_crash)
|
||||
return MinimizeCrashInput(Args);
|
||||
|
||||
if (Flags.close_fd_mask & 2)
|
||||
DupAndCloseStderr();
|
||||
if (Flags.close_fd_mask & 1)
|
||||
CloseStdout();
|
||||
|
||||
if (Flags.jobs > 0 && Flags.workers == 0) {
|
||||
Flags.workers = std::min(NumberOfCpuCores() / 2, Flags.jobs);
|
||||
if (Flags.workers > 1)
|
||||
Printf("Running %u workers\n", Flags.workers);
|
||||
}
|
||||
|
||||
if (Flags.workers > 0 && Flags.jobs > 0)
|
||||
return RunInMultipleProcesses(Args, Flags.workers, Flags.jobs);
|
||||
|
||||
const size_t kMaxSaneLen = 1 << 20;
|
||||
const size_t kMinDefaultLen = 64;
|
||||
FuzzingOptions Options;
|
||||
Options.Verbosity = Flags.verbosity;
|
||||
Options.MaxLen = Flags.max_len;
|
||||
Options.UnitTimeoutSec = Flags.timeout;
|
||||
Options.ErrorExitCode = Flags.error_exitcode;
|
||||
Options.TimeoutExitCode = Flags.timeout_exitcode;
|
||||
Options.MaxTotalTimeSec = Flags.max_total_time;
|
||||
Options.DoCrossOver = Flags.cross_over;
|
||||
Options.MutateDepth = Flags.mutate_depth;
|
||||
Options.UseCounters = Flags.use_counters;
|
||||
Options.UseIndirCalls = Flags.use_indir_calls;
|
||||
Options.UseMemcmp = Flags.use_memcmp;
|
||||
Options.UseMemmem = Flags.use_memmem;
|
||||
Options.UseCmp = Flags.use_cmp;
|
||||
Options.UseValueProfile = Flags.use_value_profile;
|
||||
Options.Shrink = Flags.shrink;
|
||||
Options.ShuffleAtStartUp = Flags.shuffle;
|
||||
Options.PreferSmall = Flags.prefer_small;
|
||||
Options.ReloadIntervalSec = Flags.reload;
|
||||
Options.OnlyASCII = Flags.only_ascii;
|
||||
Options.OutputCSV = Flags.output_csv;
|
||||
Options.DetectLeaks = Flags.detect_leaks;
|
||||
Options.TraceMalloc = Flags.trace_malloc;
|
||||
Options.RssLimitMb = Flags.rss_limit_mb;
|
||||
if (Flags.runs >= 0)
|
||||
Options.MaxNumberOfRuns = Flags.runs;
|
||||
if (!Inputs->empty() && !Flags.minimize_crash_internal_step)
|
||||
Options.OutputCorpus = (*Inputs)[0];
|
||||
Options.ReportSlowUnits = Flags.report_slow_units;
|
||||
if (Flags.artifact_prefix)
|
||||
Options.ArtifactPrefix = Flags.artifact_prefix;
|
||||
if (Flags.exact_artifact_path)
|
||||
Options.ExactArtifactPath = Flags.exact_artifact_path;
|
||||
std::vector<Unit> Dictionary;
|
||||
if (Flags.dict)
|
||||
if (!ParseDictionaryFile(FileToString(Flags.dict), &Dictionary))
|
||||
return 1;
|
||||
if (Flags.verbosity > 0 && !Dictionary.empty())
|
||||
Printf("Dictionary: %zd entries\n", Dictionary.size());
|
||||
bool DoPlainRun = AllInputsAreFiles();
|
||||
Options.SaveArtifacts =
|
||||
!DoPlainRun || Flags.minimize_crash_internal_step;
|
||||
Options.PrintNewCovPcs = Flags.print_pcs;
|
||||
Options.PrintFinalStats = Flags.print_final_stats;
|
||||
Options.PrintCorpusStats = Flags.print_corpus_stats;
|
||||
Options.PrintCoverage = Flags.print_coverage;
|
||||
Options.DumpCoverage = Flags.dump_coverage;
|
||||
if (Flags.exit_on_src_pos)
|
||||
Options.ExitOnSrcPos = Flags.exit_on_src_pos;
|
||||
if (Flags.exit_on_item)
|
||||
Options.ExitOnItem = Flags.exit_on_item;
|
||||
|
||||
unsigned Seed = Flags.seed;
|
||||
// Initialize Seed.
|
||||
if (Seed == 0)
|
||||
Seed = (std::chrono::system_clock::now().time_since_epoch().count() << 10) +
|
||||
GetPid();
|
||||
if (Flags.verbosity)
|
||||
Printf("INFO: Seed: %u\n", Seed);
|
||||
|
||||
Random Rand(Seed);
|
||||
auto *MD = new MutationDispatcher(Rand, Options);
|
||||
auto *Corpus = new InputCorpus(Options.OutputCorpus);
|
||||
auto *F = new Fuzzer(Callback, *Corpus, *MD, Options);
|
||||
|
||||
for (auto &U: Dictionary)
|
||||
if (U.size() <= Word::GetMaxSize())
|
||||
MD->AddWordToManualDictionary(Word(U.data(), U.size()));
|
||||
|
||||
StartRssThread(F, Flags.rss_limit_mb);
|
||||
|
||||
Options.HandleAbrt = Flags.handle_abrt;
|
||||
Options.HandleBus = Flags.handle_bus;
|
||||
Options.HandleFpe = Flags.handle_fpe;
|
||||
Options.HandleIll = Flags.handle_ill;
|
||||
Options.HandleInt = Flags.handle_int;
|
||||
Options.HandleSegv = Flags.handle_segv;
|
||||
Options.HandleTerm = Flags.handle_term;
|
||||
SetSignalHandler(Options);
|
||||
|
||||
if (Flags.minimize_crash_internal_step)
|
||||
return MinimizeCrashInputInternalStep(F, Corpus);
|
||||
|
||||
if (DoPlainRun) {
|
||||
Options.SaveArtifacts = false;
|
||||
int Runs = std::max(1, Flags.runs);
|
||||
Printf("%s: Running %zd inputs %d time(s) each.\n", ProgName->c_str(),
|
||||
Inputs->size(), Runs);
|
||||
for (auto &Path : *Inputs) {
|
||||
auto StartTime = system_clock::now();
|
||||
Printf("Running: %s\n", Path.c_str());
|
||||
for (int Iter = 0; Iter < Runs; Iter++)
|
||||
RunOneTest(F, Path.c_str(), Options.MaxLen);
|
||||
auto StopTime = system_clock::now();
|
||||
auto MS = duration_cast<milliseconds>(StopTime - StartTime).count();
|
||||
Printf("Executed %s in %zd ms\n", Path.c_str(), (long)MS);
|
||||
}
|
||||
Printf("***\n"
|
||||
"*** NOTE: fuzzing was not performed, you have only\n"
|
||||
"*** executed the target code on a fixed set of inputs.\n"
|
||||
"***\n");
|
||||
F->PrintFinalStats();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (Flags.merge) {
|
||||
if (Options.MaxLen == 0)
|
||||
F->SetMaxInputLen(kMaxSaneLen);
|
||||
if (TPC.UsingTracePcGuard()) {
|
||||
if (Flags.merge_control_file)
|
||||
F->CrashResistantMergeInternalStep(Flags.merge_control_file);
|
||||
else
|
||||
F->CrashResistantMerge(Args, *Inputs);
|
||||
} else {
|
||||
F->Merge(*Inputs);
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
size_t TemporaryMaxLen = Options.MaxLen ? Options.MaxLen : kMaxSaneLen;
|
||||
|
||||
UnitVector InitialCorpus;
|
||||
for (auto &Inp : *Inputs) {
|
||||
Printf("Loading corpus dir: %s\n", Inp.c_str());
|
||||
ReadDirToVectorOfUnits(Inp.c_str(), &InitialCorpus, nullptr,
|
||||
TemporaryMaxLen, /*ExitOnError=*/false);
|
||||
}
|
||||
|
||||
if (Options.MaxLen == 0) {
|
||||
size_t MaxLen = 0;
|
||||
for (auto &U : InitialCorpus)
|
||||
MaxLen = std::max(U.size(), MaxLen);
|
||||
F->SetMaxInputLen(std::min(std::max(kMinDefaultLen, MaxLen), kMaxSaneLen));
|
||||
}
|
||||
|
||||
if (InitialCorpus.empty()) {
|
||||
InitialCorpus.push_back(Unit({'\n'})); // Valid ASCII input.
|
||||
if (Options.Verbosity)
|
||||
Printf("INFO: A corpus is not provided, starting from an empty corpus\n");
|
||||
}
|
||||
F->ShuffleAndMinimize(&InitialCorpus);
|
||||
InitialCorpus.clear(); // Don't need this memory any more.
|
||||
F->Loop();
|
||||
|
||||
if (Flags.verbosity)
|
||||
Printf("Done %d runs in %zd second(s)\n", F->getTotalNumberOfRuns(),
|
||||
F->secondsSinceProcessStartUp());
|
||||
F->PrintFinalStats();
|
||||
|
||||
exit(0); // Don't let F destroy itself.
|
||||
}
|
||||
|
||||
// Storage for global ExternalFunctions object.
|
||||
ExternalFunctions *EF = nullptr;
|
||||
|
||||
} // namespace fuzzer
|
||||
@@ -1,50 +0,0 @@
|
||||
//===- FuzzerExtFunctions.def - External functions --------------*- C++ -* ===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// This defines the external function pointers that
|
||||
// ``fuzzer::ExternalFunctions`` should contain and try to initialize. The
|
||||
// EXT_FUNC macro must be defined at the point of inclusion. The signature of
|
||||
// the macro is:
|
||||
//
|
||||
// EXT_FUNC(<name>, <return_type>, <function_signature>, <warn_if_missing>)
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Optional user functions
|
||||
EXT_FUNC(LLVMFuzzerInitialize, int, (int *argc, char ***argv), false);
|
||||
EXT_FUNC(LLVMFuzzerCustomMutator, size_t,
|
||||
(uint8_t * Data, size_t Size, size_t MaxSize, unsigned int Seed),
|
||||
false);
|
||||
EXT_FUNC(LLVMFuzzerCustomCrossOver, size_t,
|
||||
(const uint8_t * Data1, size_t Size1,
|
||||
const uint8_t * Data2, size_t Size2,
|
||||
uint8_t * Out, size_t MaxOutSize, unsigned int Seed),
|
||||
false);
|
||||
|
||||
// Sanitizer functions
|
||||
EXT_FUNC(__lsan_enable, void, (), false);
|
||||
EXT_FUNC(__lsan_disable, void, (), false);
|
||||
EXT_FUNC(__lsan_do_recoverable_leak_check, int, (), false);
|
||||
EXT_FUNC(__sanitizer_get_number_of_counters, size_t, (), false);
|
||||
EXT_FUNC(__sanitizer_install_malloc_and_free_hooks, int,
|
||||
(void (*malloc_hook)(const volatile void *, size_t),
|
||||
void (*free_hook)(const volatile void *)),
|
||||
false);
|
||||
EXT_FUNC(__sanitizer_get_total_unique_caller_callee_pairs, size_t, (), false);
|
||||
EXT_FUNC(__sanitizer_get_total_unique_coverage, size_t, (), true);
|
||||
EXT_FUNC(__sanitizer_print_memory_profile, int, (size_t), false);
|
||||
EXT_FUNC(__sanitizer_print_stack_trace, void, (), true);
|
||||
EXT_FUNC(__sanitizer_symbolize_pc, void,
|
||||
(void *, const char *fmt, char *out_buf, size_t out_buf_size), false);
|
||||
EXT_FUNC(__sanitizer_get_module_and_offset_for_pc, int,
|
||||
(void *pc, char *module_path,
|
||||
size_t module_path_len,void **pc_offset), false);
|
||||
EXT_FUNC(__sanitizer_reset_coverage, void, (), true);
|
||||
EXT_FUNC(__sanitizer_set_death_callback, void, (void (*)(void)), true);
|
||||
EXT_FUNC(__sanitizer_set_report_fd, void, (void*), false);
|
||||
EXT_FUNC(__sanitizer_update_counter_bitset_and_clear_counters, uintptr_t,
|
||||
(uint8_t*), false);
|
||||
@@ -1,35 +0,0 @@
|
||||
//===- FuzzerExtFunctions.h - Interface to external functions ---*- C++ -* ===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Defines an interface to (possibly optional) functions.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_FUZZER_EXT_FUNCTIONS_H
|
||||
#define LLVM_FUZZER_EXT_FUNCTIONS_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
struct ExternalFunctions {
|
||||
// Initialize function pointers. Functions that are not available will be set
|
||||
// to nullptr. Do not call this constructor before ``main()`` has been
|
||||
// entered.
|
||||
ExternalFunctions();
|
||||
|
||||
#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
|
||||
RETURN_TYPE(*NAME) FUNC_SIG = nullptr
|
||||
|
||||
#include "FuzzerExtFunctions.def"
|
||||
|
||||
#undef EXT_FUNC
|
||||
};
|
||||
} // namespace fuzzer
|
||||
|
||||
#endif
|
||||
@@ -1,52 +0,0 @@
|
||||
//===- FuzzerExtFunctionsDlsym.cpp - Interface to external functions ------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Implementation for operating systems that support dlsym(). We only use it on
|
||||
// Apple platforms for now. We don't use this approach on Linux because it
|
||||
// requires that clients of LibFuzzer pass ``--export-dynamic`` to the linker.
|
||||
// That is a complication we don't wish to expose to clients right now.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "FuzzerDefs.h"
|
||||
#if LIBFUZZER_APPLE
|
||||
|
||||
#include "FuzzerExtFunctions.h"
|
||||
#include "FuzzerIO.h"
|
||||
#include <dlfcn.h>
|
||||
|
||||
using namespace fuzzer;
|
||||
|
||||
template <typename T>
|
||||
static T GetFnPtr(const char *FnName, bool WarnIfMissing) {
|
||||
dlerror(); // Clear any previous errors.
|
||||
void *Fn = dlsym(RTLD_DEFAULT, FnName);
|
||||
if (Fn == nullptr) {
|
||||
if (WarnIfMissing) {
|
||||
const char *ErrorMsg = dlerror();
|
||||
Printf("WARNING: Failed to find function \"%s\".", FnName);
|
||||
if (ErrorMsg)
|
||||
Printf(" Reason %s.", ErrorMsg);
|
||||
Printf("\n");
|
||||
}
|
||||
}
|
||||
return reinterpret_cast<T>(Fn);
|
||||
}
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
ExternalFunctions::ExternalFunctions() {
|
||||
#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
|
||||
this->NAME = GetFnPtr<decltype(ExternalFunctions::NAME)>(#NAME, WARN)
|
||||
|
||||
#include "FuzzerExtFunctions.def"
|
||||
|
||||
#undef EXT_FUNC
|
||||
}
|
||||
|
||||
} // namespace fuzzer
|
||||
|
||||
#endif // LIBFUZZER_APPLE
|
||||
@@ -1,53 +0,0 @@
|
||||
//===- FuzzerExtFunctionsWeak.cpp - Interface to external functions -------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Implementation for Linux. This relies on the linker's support for weak
|
||||
// symbols. We don't use this approach on Apple platforms because it requires
|
||||
// clients of LibFuzzer to pass ``-U _<symbol_name>`` to the linker to allow
|
||||
// weak symbols to be undefined. That is a complication we don't want to expose
|
||||
// to clients right now.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "FuzzerDefs.h"
|
||||
#if LIBFUZZER_LINUX
|
||||
|
||||
#include "FuzzerExtFunctions.h"
|
||||
#include "FuzzerIO.h"
|
||||
|
||||
extern "C" {
|
||||
// Declare these symbols as weak to allow them to be optionally defined.
|
||||
#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
|
||||
__attribute__((weak)) RETURN_TYPE NAME FUNC_SIG
|
||||
|
||||
#include "FuzzerExtFunctions.def"
|
||||
|
||||
#undef EXT_FUNC
|
||||
}
|
||||
|
||||
using namespace fuzzer;
|
||||
|
||||
static void CheckFnPtr(void *FnPtr, const char *FnName, bool WarnIfMissing) {
|
||||
if (FnPtr == nullptr && WarnIfMissing) {
|
||||
Printf("WARNING: Failed to find function \"%s\".\n", FnName);
|
||||
}
|
||||
}
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
ExternalFunctions::ExternalFunctions() {
|
||||
#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
|
||||
this->NAME = ::NAME; \
|
||||
CheckFnPtr((void *)::NAME, #NAME, WARN);
|
||||
|
||||
#include "FuzzerExtFunctions.def"
|
||||
|
||||
#undef EXT_FUNC
|
||||
}
|
||||
|
||||
} // namespace fuzzer
|
||||
|
||||
#endif // LIBFUZZER_LINUX
|
||||
@@ -1,56 +0,0 @@
|
||||
//===- FuzzerExtFunctionsWeakAlias.cpp - Interface to external functions --===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Implementation using weak aliases. Works for Windows.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "FuzzerDefs.h"
|
||||
#if LIBFUZZER_WINDOWS
|
||||
|
||||
#include "FuzzerExtFunctions.h"
|
||||
#include "FuzzerIO.h"
|
||||
|
||||
using namespace fuzzer;
|
||||
|
||||
extern "C" {
|
||||
// Declare these symbols as weak to allow them to be optionally defined.
|
||||
#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
|
||||
RETURN_TYPE NAME##Def FUNC_SIG { \
|
||||
Printf("ERROR: Function \"%s\" not defined.\n", #NAME); \
|
||||
exit(1); \
|
||||
} \
|
||||
RETURN_TYPE NAME FUNC_SIG __attribute__((weak, alias(#NAME "Def")));
|
||||
|
||||
#include "FuzzerExtFunctions.def"
|
||||
|
||||
#undef EXT_FUNC
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static T *GetFnPtr(T *Fun, T *FunDef, const char *FnName, bool WarnIfMissing) {
|
||||
if (Fun == FunDef) {
|
||||
if (WarnIfMissing)
|
||||
Printf("WARNING: Failed to find function \"%s\".\n", FnName);
|
||||
return nullptr;
|
||||
}
|
||||
return Fun;
|
||||
}
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
ExternalFunctions::ExternalFunctions() {
|
||||
#define EXT_FUNC(NAME, RETURN_TYPE, FUNC_SIG, WARN) \
|
||||
this->NAME = GetFnPtr<decltype(::NAME)>(::NAME, ::NAME##Def, #NAME, WARN);
|
||||
|
||||
#include "FuzzerExtFunctions.def"
|
||||
|
||||
#undef EXT_FUNC
|
||||
}
|
||||
|
||||
} // namespace fuzzer
|
||||
|
||||
#endif // LIBFUZZER_WINDOWS
|
||||
@@ -1,115 +0,0 @@
|
||||
//===- FuzzerFlags.def - Run-time flags -------------------------*- C++ -* ===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Flags. FUZZER_FLAG_INT/FUZZER_FLAG_STRING macros should be defined at the
|
||||
// point of inclusion. We are not using any flag parsing library for better
|
||||
// portability and independence.
|
||||
//===----------------------------------------------------------------------===//
|
||||
FUZZER_FLAG_INT(verbosity, 1, "Verbosity level.")
|
||||
FUZZER_FLAG_UNSIGNED(seed, 0, "Random seed. If 0, seed is generated.")
|
||||
FUZZER_FLAG_INT(runs, -1,
|
||||
"Number of individual test runs (-1 for infinite runs).")
|
||||
FUZZER_FLAG_INT(max_len, 0, "Maximum length of the test input. "
|
||||
"If 0, libFuzzer tries to guess a good value based on the corpus "
|
||||
"and reports it. ")
|
||||
FUZZER_FLAG_INT(cross_over, 1, "If 1, cross over inputs.")
|
||||
FUZZER_FLAG_INT(mutate_depth, 5,
|
||||
"Apply this number of consecutive mutations to each input.")
|
||||
FUZZER_FLAG_INT(shuffle, 1, "Shuffle inputs at startup")
|
||||
FUZZER_FLAG_INT(prefer_small, 1,
|
||||
"If 1, always prefer smaller inputs during the corpus shuffle.")
|
||||
FUZZER_FLAG_INT(
|
||||
timeout, 1200,
|
||||
"Timeout in seconds (if positive). "
|
||||
"If one unit runs more than this number of seconds the process will abort.")
|
||||
FUZZER_FLAG_INT(error_exitcode, 77, "When libFuzzer itself reports a bug "
|
||||
"this exit code will be used.")
|
||||
FUZZER_FLAG_INT(timeout_exitcode, 77, "When libFuzzer reports a timeout "
|
||||
"this exit code will be used.")
|
||||
FUZZER_FLAG_INT(max_total_time, 0, "If positive, indicates the maximal total "
|
||||
"time in seconds to run the fuzzer.")
|
||||
FUZZER_FLAG_INT(help, 0, "Print help.")
|
||||
FUZZER_FLAG_INT(merge, 0, "If 1, the 2-nd, 3-rd, etc corpora will be "
|
||||
"merged into the 1-st corpus. Only interesting units will be taken. "
|
||||
"This flag can be used to minimize a corpus.")
|
||||
FUZZER_FLAG_STRING(merge_control_file, "internal flag")
|
||||
FUZZER_FLAG_INT(minimize_crash, 0, "If 1, minimizes the provided"
|
||||
" crash input. Use with -runs=N or -max_total_time=N to limit "
|
||||
"the number attempts")
|
||||
FUZZER_FLAG_INT(minimize_crash_internal_step, 0, "internal flag")
|
||||
FUZZER_FLAG_INT(use_counters, 1, "Use coverage counters")
|
||||
FUZZER_FLAG_INT(use_indir_calls, 1, "Use indirect caller-callee counters")
|
||||
FUZZER_FLAG_INT(use_memcmp, 1,
|
||||
"Use hints from intercepting memcmp, strcmp, etc")
|
||||
FUZZER_FLAG_INT(use_memmem, 1,
|
||||
"Use hints from intercepting memmem, strstr, etc")
|
||||
FUZZER_FLAG_INT(use_value_profile, 0,
|
||||
"Experimental. Use value profile to guide fuzzing.")
|
||||
FUZZER_FLAG_INT(use_cmp, 1, "Use CMP traces to guide mutations")
|
||||
FUZZER_FLAG_INT(shrink, 0, "Experimental. Try to shrink corpus elements.")
|
||||
FUZZER_FLAG_UNSIGNED(jobs, 0, "Number of jobs to run. If jobs >= 1 we spawn"
|
||||
" this number of jobs in separate worker processes"
|
||||
" with stdout/stderr redirected to fuzz-JOB.log.")
|
||||
FUZZER_FLAG_UNSIGNED(workers, 0,
|
||||
"Number of simultaneous worker processes to run the jobs."
|
||||
" If zero, \"min(jobs,NumberOfCpuCores()/2)\" is used.")
|
||||
FUZZER_FLAG_INT(reload, 1,
|
||||
"Reload the main corpus every <N> seconds to get new units"
|
||||
" discovered by other processes. If 0, disabled")
|
||||
FUZZER_FLAG_INT(report_slow_units, 10,
|
||||
"Report slowest units if they run for more than this number of seconds.")
|
||||
FUZZER_FLAG_INT(only_ascii, 0,
|
||||
"If 1, generate only ASCII (isprint+isspace) inputs.")
|
||||
FUZZER_FLAG_STRING(dict, "Experimental. Use the dictionary file.")
|
||||
FUZZER_FLAG_STRING(artifact_prefix, "Write fuzzing artifacts (crash, "
|
||||
"timeout, or slow inputs) as "
|
||||
"$(artifact_prefix)file")
|
||||
FUZZER_FLAG_STRING(exact_artifact_path,
|
||||
"Write the single artifact on failure (crash, timeout) "
|
||||
"as $(exact_artifact_path). This overrides -artifact_prefix "
|
||||
"and will not use checksum in the file name. Do not "
|
||||
"use the same path for several parallel processes.")
|
||||
FUZZER_FLAG_INT(output_csv, 0, "Enable pulse output in CSV format.")
|
||||
FUZZER_FLAG_INT(print_pcs, 0, "If 1, print out newly covered PCs.")
|
||||
FUZZER_FLAG_INT(print_final_stats, 0, "If 1, print statistics at exit.")
|
||||
FUZZER_FLAG_INT(print_corpus_stats, 0,
|
||||
"If 1, print statistics on corpus elements at exit.")
|
||||
FUZZER_FLAG_INT(print_coverage, 0, "If 1, print coverage information at exit."
|
||||
" Experimental, only with trace-pc-guard")
|
||||
FUZZER_FLAG_INT(dump_coverage, 0, "If 1, dump coverage information at exit."
|
||||
" Experimental, only with trace-pc-guard")
|
||||
FUZZER_FLAG_INT(handle_segv, 1, "If 1, try to intercept SIGSEGV.")
|
||||
FUZZER_FLAG_INT(handle_bus, 1, "If 1, try to intercept SIGSEGV.")
|
||||
FUZZER_FLAG_INT(handle_abrt, 1, "If 1, try to intercept SIGABRT.")
|
||||
FUZZER_FLAG_INT(handle_ill, 1, "If 1, try to intercept SIGILL.")
|
||||
FUZZER_FLAG_INT(handle_fpe, 1, "If 1, try to intercept SIGFPE.")
|
||||
FUZZER_FLAG_INT(handle_int, 1, "If 1, try to intercept SIGINT.")
|
||||
FUZZER_FLAG_INT(handle_term, 1, "If 1, try to intercept SIGTERM.")
|
||||
FUZZER_FLAG_INT(close_fd_mask, 0, "If 1, close stdout at startup; "
|
||||
"if 2, close stderr; if 3, close both. "
|
||||
"Be careful, this will also close e.g. asan's stderr/stdout.")
|
||||
FUZZER_FLAG_INT(detect_leaks, 1, "If 1, and if LeakSanitizer is enabled "
|
||||
"try to detect memory leaks during fuzzing (i.e. not only at shut down).")
|
||||
FUZZER_FLAG_INT(trace_malloc, 0, "If >= 1 will print all mallocs/frees. "
|
||||
"If >= 2 will also print stack traces.")
|
||||
FUZZER_FLAG_INT(rss_limit_mb, 2048, "If non-zero, the fuzzer will exit upon"
|
||||
"reaching this limit of RSS memory usage.")
|
||||
FUZZER_FLAG_STRING(exit_on_src_pos, "Exit if a newly found PC originates"
|
||||
" from the given source location. Example: -exit_on_src_pos=foo.cc:123. "
|
||||
"Used primarily for testing libFuzzer itself.")
|
||||
FUZZER_FLAG_STRING(exit_on_item, "Exit if an item with a given sha1 sum"
|
||||
" was added to the corpus. "
|
||||
"Used primarily for testing libFuzzer itself.")
|
||||
|
||||
FUZZER_DEPRECATED_FLAG(exit_on_first)
|
||||
FUZZER_DEPRECATED_FLAG(save_minimized_corpus)
|
||||
FUZZER_DEPRECATED_FLAG(sync_command)
|
||||
FUZZER_DEPRECATED_FLAG(sync_timeout)
|
||||
FUZZER_DEPRECATED_FLAG(test_single_input)
|
||||
FUZZER_DEPRECATED_FLAG(drill)
|
||||
FUZZER_DEPRECATED_FLAG(truncate_units)
|
||||
@@ -1,117 +0,0 @@
|
||||
//===- FuzzerIO.cpp - IO utils. -------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// IO functions.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "FuzzerIO.h"
|
||||
#include "FuzzerDefs.h"
|
||||
#include "FuzzerExtFunctions.h"
|
||||
#include <algorithm>
|
||||
#include <cstdarg>
|
||||
#include <fstream>
|
||||
#include <iterator>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
static FILE *OutputFile = stderr;
|
||||
|
||||
long GetEpoch(const std::string &Path) {
|
||||
struct stat St;
|
||||
if (stat(Path.c_str(), &St))
|
||||
return 0; // Can't stat, be conservative.
|
||||
return St.st_mtime;
|
||||
}
|
||||
|
||||
Unit FileToVector(const std::string &Path, size_t MaxSize, bool ExitOnError) {
|
||||
std::ifstream T(Path);
|
||||
if (ExitOnError && !T) {
|
||||
Printf("No such directory: %s; exiting\n", Path.c_str());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
T.seekg(0, T.end);
|
||||
size_t FileLen = T.tellg();
|
||||
if (MaxSize)
|
||||
FileLen = std::min(FileLen, MaxSize);
|
||||
|
||||
T.seekg(0, T.beg);
|
||||
Unit Res(FileLen);
|
||||
T.read(reinterpret_cast<char *>(Res.data()), FileLen);
|
||||
return Res;
|
||||
}
|
||||
|
||||
std::string FileToString(const std::string &Path) {
|
||||
std::ifstream T(Path);
|
||||
return std::string((std::istreambuf_iterator<char>(T)),
|
||||
std::istreambuf_iterator<char>());
|
||||
}
|
||||
|
||||
void CopyFileToErr(const std::string &Path) {
|
||||
Printf("%s", FileToString(Path).c_str());
|
||||
}
|
||||
|
||||
void WriteToFile(const Unit &U, const std::string &Path) {
|
||||
// Use raw C interface because this function may be called from a sig handler.
|
||||
FILE *Out = fopen(Path.c_str(), "w");
|
||||
if (!Out) return;
|
||||
fwrite(U.data(), sizeof(U[0]), U.size(), Out);
|
||||
fclose(Out);
|
||||
}
|
||||
|
||||
void ReadDirToVectorOfUnits(const char *Path, std::vector<Unit> *V,
|
||||
long *Epoch, size_t MaxSize, bool ExitOnError) {
|
||||
long E = Epoch ? *Epoch : 0;
|
||||
std::vector<std::string> Files;
|
||||
ListFilesInDirRecursive(Path, Epoch, &Files, /*TopDir*/true);
|
||||
size_t NumLoaded = 0;
|
||||
for (size_t i = 0; i < Files.size(); i++) {
|
||||
auto &X = Files[i];
|
||||
if (Epoch && GetEpoch(X) < E) continue;
|
||||
NumLoaded++;
|
||||
if ((NumLoaded & (NumLoaded - 1)) == 0 && NumLoaded >= 1024)
|
||||
Printf("Loaded %zd/%zd files from %s\n", NumLoaded, Files.size(), Path);
|
||||
auto S = FileToVector(X, MaxSize, ExitOnError);
|
||||
if (!S.empty())
|
||||
V->push_back(S);
|
||||
}
|
||||
}
|
||||
|
||||
std::string DirPlusFile(const std::string &DirPath,
|
||||
const std::string &FileName) {
|
||||
return DirPath + GetSeparator() + FileName;
|
||||
}
|
||||
|
||||
void DupAndCloseStderr() {
|
||||
int OutputFd = DuplicateFile(2);
|
||||
if (OutputFd > 0) {
|
||||
FILE *NewOutputFile = OpenFile(OutputFd, "w");
|
||||
if (NewOutputFile) {
|
||||
OutputFile = NewOutputFile;
|
||||
if (EF->__sanitizer_set_report_fd)
|
||||
EF->__sanitizer_set_report_fd(reinterpret_cast<void *>(OutputFd));
|
||||
CloseFile(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CloseStdout() {
|
||||
CloseFile(1);
|
||||
}
|
||||
|
||||
void Printf(const char *Fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, Fmt);
|
||||
vfprintf(OutputFile, Fmt, ap);
|
||||
va_end(ap);
|
||||
fflush(OutputFile);
|
||||
}
|
||||
|
||||
} // namespace fuzzer
|
||||
@@ -1,64 +0,0 @@
|
||||
//===- FuzzerIO.h - Internal header for IO utils ----------------*- C++ -* ===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// IO interface.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_FUZZER_IO_H
|
||||
#define LLVM_FUZZER_IO_H
|
||||
|
||||
#include "FuzzerDefs.h"
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
long GetEpoch(const std::string &Path);
|
||||
|
||||
Unit FileToVector(const std::string &Path, size_t MaxSize = 0,
|
||||
bool ExitOnError = true);
|
||||
|
||||
std::string FileToString(const std::string &Path);
|
||||
|
||||
void CopyFileToErr(const std::string &Path);
|
||||
|
||||
void WriteToFile(const Unit &U, const std::string &Path);
|
||||
|
||||
void ReadDirToVectorOfUnits(const char *Path, std::vector<Unit> *V,
|
||||
long *Epoch, size_t MaxSize, bool ExitOnError);
|
||||
|
||||
// Returns "Dir/FileName" or equivalent for the current OS.
|
||||
std::string DirPlusFile(const std::string &DirPath,
|
||||
const std::string &FileName);
|
||||
|
||||
// Returns the name of the dir, similar to the 'dirname' utility.
|
||||
std::string DirName(const std::string &FileName);
|
||||
|
||||
void DupAndCloseStderr();
|
||||
|
||||
void CloseStdout();
|
||||
|
||||
void Printf(const char *Fmt, ...);
|
||||
|
||||
// Platform specific functions:
|
||||
bool IsFile(const std::string &Path);
|
||||
|
||||
void ListFilesInDirRecursive(const std::string &Dir, long *Epoch,
|
||||
std::vector<std::string> *V, bool TopDir);
|
||||
|
||||
char GetSeparator();
|
||||
|
||||
FILE* OpenFile(int Fd, const char *Mode);
|
||||
|
||||
int CloseFile(int Fd);
|
||||
|
||||
int DuplicateFile(int Fd);
|
||||
|
||||
void RemoveFile(const std::string &Path);
|
||||
|
||||
} // namespace fuzzer
|
||||
|
||||
#endif // LLVM_FUZZER_IO_H
|
||||
@@ -1,88 +0,0 @@
|
||||
//===- FuzzerIOPosix.cpp - IO utils for Posix. ----------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// IO functions implementation using Posix API.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "FuzzerDefs.h"
|
||||
#if LIBFUZZER_POSIX
|
||||
|
||||
#include "FuzzerExtFunctions.h"
|
||||
#include "FuzzerIO.h"
|
||||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
#include <dirent.h>
|
||||
#include <fstream>
|
||||
#include <iterator>
|
||||
#include <libgen.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
bool IsFile(const std::string &Path) {
|
||||
struct stat St;
|
||||
if (stat(Path.c_str(), &St))
|
||||
return false;
|
||||
return S_ISREG(St.st_mode);
|
||||
}
|
||||
|
||||
void ListFilesInDirRecursive(const std::string &Dir, long *Epoch,
|
||||
std::vector<std::string> *V, bool TopDir) {
|
||||
auto E = GetEpoch(Dir);
|
||||
if (Epoch)
|
||||
if (E && *Epoch >= E) return;
|
||||
|
||||
DIR *D = opendir(Dir.c_str());
|
||||
if (!D) {
|
||||
Printf("No such directory: %s; exiting\n", Dir.c_str());
|
||||
exit(1);
|
||||
}
|
||||
while (auto E = readdir(D)) {
|
||||
std::string Path = DirPlusFile(Dir, E->d_name);
|
||||
if (E->d_type == DT_REG || E->d_type == DT_LNK)
|
||||
V->push_back(Path);
|
||||
else if (E->d_type == DT_DIR && *E->d_name != '.')
|
||||
ListFilesInDirRecursive(Path, Epoch, V, false);
|
||||
}
|
||||
closedir(D);
|
||||
if (Epoch && TopDir)
|
||||
*Epoch = E;
|
||||
}
|
||||
|
||||
char GetSeparator() {
|
||||
return '/';
|
||||
}
|
||||
|
||||
FILE* OpenFile(int Fd, const char* Mode) {
|
||||
return fdopen(Fd, Mode);
|
||||
}
|
||||
|
||||
int CloseFile(int fd) {
|
||||
return close(fd);
|
||||
}
|
||||
|
||||
int DuplicateFile(int Fd) {
|
||||
return dup(Fd);
|
||||
}
|
||||
|
||||
void RemoveFile(const std::string &Path) {
|
||||
unlink(Path.c_str());
|
||||
}
|
||||
|
||||
std::string DirName(const std::string &FileName) {
|
||||
char *Tmp = new char[FileName.size() + 1];
|
||||
memcpy(Tmp, FileName.c_str(), FileName.size() + 1);
|
||||
std::string Res = dirname(Tmp);
|
||||
delete [] Tmp;
|
||||
return Res;
|
||||
}
|
||||
|
||||
} // namespace fuzzer
|
||||
|
||||
#endif // LIBFUZZER_POSIX
|
||||
@@ -1,282 +0,0 @@
|
||||
//===- FuzzerIOWindows.cpp - IO utils for Windows. ------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// IO functions implementation for Windows.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "FuzzerDefs.h"
|
||||
#if LIBFUZZER_WINDOWS
|
||||
|
||||
#include "FuzzerExtFunctions.h"
|
||||
#include "FuzzerIO.h"
|
||||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
#include <fstream>
|
||||
#include <io.h>
|
||||
#include <iterator>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <windows.h>
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
static bool IsFile(const std::string &Path, const DWORD &FileAttributes) {
|
||||
|
||||
if (FileAttributes & FILE_ATTRIBUTE_NORMAL)
|
||||
return true;
|
||||
|
||||
if (FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
return false;
|
||||
|
||||
HANDLE FileHandle(
|
||||
CreateFileA(Path.c_str(), 0, FILE_SHARE_READ, NULL, OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS, 0));
|
||||
|
||||
if (FileHandle == INVALID_HANDLE_VALUE) {
|
||||
Printf("CreateFileA() failed for \"%s\" (Error code: %lu).\n", Path.c_str(),
|
||||
GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD FileType = GetFileType(FileHandle);
|
||||
|
||||
if (FileType == FILE_TYPE_UNKNOWN) {
|
||||
Printf("GetFileType() failed for \"%s\" (Error code: %lu).\n", Path.c_str(),
|
||||
GetLastError());
|
||||
CloseHandle(FileHandle);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (FileType != FILE_TYPE_DISK) {
|
||||
CloseHandle(FileHandle);
|
||||
return false;
|
||||
}
|
||||
|
||||
CloseHandle(FileHandle);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IsFile(const std::string &Path) {
|
||||
DWORD Att = GetFileAttributesA(Path.c_str());
|
||||
|
||||
if (Att == INVALID_FILE_ATTRIBUTES) {
|
||||
Printf("GetFileAttributesA() failed for \"%s\" (Error code: %lu).\n",
|
||||
Path.c_str(), GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
return IsFile(Path, Att);
|
||||
}
|
||||
|
||||
void ListFilesInDirRecursive(const std::string &Dir, long *Epoch,
|
||||
std::vector<std::string> *V, bool TopDir) {
|
||||
auto E = GetEpoch(Dir);
|
||||
if (Epoch)
|
||||
if (E && *Epoch >= E) return;
|
||||
|
||||
std::string Path(Dir);
|
||||
assert(!Path.empty());
|
||||
if (Path.back() != '\\')
|
||||
Path.push_back('\\');
|
||||
Path.push_back('*');
|
||||
|
||||
// Get the first directory entry.
|
||||
WIN32_FIND_DATAA FindInfo;
|
||||
HANDLE FindHandle(FindFirstFileA(Path.c_str(), &FindInfo));
|
||||
if (FindHandle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
Printf("No file found in: %s.\n", Dir.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
std::string FileName = DirPlusFile(Dir, FindInfo.cFileName);
|
||||
|
||||
if (FindInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
size_t FilenameLen = strlen(FindInfo.cFileName);
|
||||
if ((FilenameLen == 1 && FindInfo.cFileName[0] == '.') ||
|
||||
(FilenameLen == 2 && FindInfo.cFileName[0] == '.' &&
|
||||
FindInfo.cFileName[1] == '.'))
|
||||
continue;
|
||||
|
||||
ListFilesInDirRecursive(FileName, Epoch, V, false);
|
||||
}
|
||||
else if (IsFile(FileName, FindInfo.dwFileAttributes))
|
||||
V->push_back(FileName);
|
||||
} while (FindNextFileA(FindHandle, &FindInfo));
|
||||
|
||||
DWORD LastError = GetLastError();
|
||||
if (LastError != ERROR_NO_MORE_FILES)
|
||||
Printf("FindNextFileA failed (Error code: %lu).\n", LastError);
|
||||
|
||||
FindClose(FindHandle);
|
||||
|
||||
if (Epoch && TopDir)
|
||||
*Epoch = E;
|
||||
}
|
||||
|
||||
char GetSeparator() {
|
||||
return '\\';
|
||||
}
|
||||
|
||||
FILE* OpenFile(int Fd, const char* Mode) {
|
||||
return _fdopen(Fd, Mode);
|
||||
}
|
||||
|
||||
int CloseFile(int Fd) {
|
||||
return _close(Fd);
|
||||
}
|
||||
|
||||
int DuplicateFile(int Fd) {
|
||||
return _dup(Fd);
|
||||
}
|
||||
|
||||
void RemoveFile(const std::string &Path) {
|
||||
_unlink(Path.c_str());
|
||||
}
|
||||
|
||||
static bool IsSeparator(char C) {
|
||||
return C == '\\' || C == '/';
|
||||
}
|
||||
|
||||
// Parse disk designators, like "C:\". If Relative == true, also accepts: "C:".
|
||||
// Returns number of characters considered if successful.
|
||||
static size_t ParseDrive(const std::string &FileName, const size_t Offset,
|
||||
bool Relative = true) {
|
||||
if (Offset + 1 >= FileName.size() || FileName[Offset + 1] != ':')
|
||||
return 0;
|
||||
if (Offset + 2 >= FileName.size() || !IsSeparator(FileName[Offset + 2])) {
|
||||
if (!Relative) // Accept relative path?
|
||||
return 0;
|
||||
else
|
||||
return 2;
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
|
||||
// Parse a file name, like: SomeFile.txt
|
||||
// Returns number of characters considered if successful.
|
||||
static size_t ParseFileName(const std::string &FileName, const size_t Offset) {
|
||||
size_t Pos = Offset;
|
||||
const size_t End = FileName.size();
|
||||
for(; Pos < End && !IsSeparator(FileName[Pos]); ++Pos)
|
||||
;
|
||||
return Pos - Offset;
|
||||
}
|
||||
|
||||
// Parse a directory ending in separator, like: SomeDir\
|
||||
// Returns number of characters considered if successful.
|
||||
static size_t ParseDir(const std::string &FileName, const size_t Offset) {
|
||||
size_t Pos = Offset;
|
||||
const size_t End = FileName.size();
|
||||
if (Pos >= End || IsSeparator(FileName[Pos]))
|
||||
return 0;
|
||||
for(; Pos < End && !IsSeparator(FileName[Pos]); ++Pos)
|
||||
;
|
||||
if (Pos >= End)
|
||||
return 0;
|
||||
++Pos; // Include separator.
|
||||
return Pos - Offset;
|
||||
}
|
||||
|
||||
// Parse a servername and share, like: SomeServer\SomeShare\
|
||||
// Returns number of characters considered if successful.
|
||||
static size_t ParseServerAndShare(const std::string &FileName,
|
||||
const size_t Offset) {
|
||||
size_t Pos = Offset, Res;
|
||||
if (!(Res = ParseDir(FileName, Pos)))
|
||||
return 0;
|
||||
Pos += Res;
|
||||
if (!(Res = ParseDir(FileName, Pos)))
|
||||
return 0;
|
||||
Pos += Res;
|
||||
return Pos - Offset;
|
||||
}
|
||||
|
||||
// Parse the given Ref string from the position Offset, to exactly match the given
|
||||
// string Patt.
|
||||
// Returns number of characters considered if successful.
|
||||
static size_t ParseCustomString(const std::string &Ref, size_t Offset,
|
||||
const char *Patt) {
|
||||
size_t Len = strlen(Patt);
|
||||
if (Offset + Len > Ref.size())
|
||||
return 0;
|
||||
return Ref.compare(Offset, Len, Patt) == 0 ? Len : 0;
|
||||
}
|
||||
|
||||
// Parse a location, like:
|
||||
// \\?\UNC\Server\Share\ \\?\C:\ \\Server\Share\ \ C:\ C:
|
||||
// Returns number of characters considered if successful.
|
||||
static size_t ParseLocation(const std::string &FileName) {
|
||||
size_t Pos = 0, Res;
|
||||
|
||||
if ((Res = ParseCustomString(FileName, Pos, R"(\\?\)"))) {
|
||||
Pos += Res;
|
||||
if ((Res = ParseCustomString(FileName, Pos, R"(UNC\)"))) {
|
||||
Pos += Res;
|
||||
if ((Res = ParseServerAndShare(FileName, Pos)))
|
||||
return Pos + Res;
|
||||
return 0;
|
||||
}
|
||||
if ((Res = ParseDrive(FileName, Pos, false)))
|
||||
return Pos + Res;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (Pos < FileName.size() && IsSeparator(FileName[Pos])) {
|
||||
++Pos;
|
||||
if (Pos < FileName.size() && IsSeparator(FileName[Pos])) {
|
||||
++Pos;
|
||||
if ((Res = ParseServerAndShare(FileName, Pos)))
|
||||
return Pos + Res;
|
||||
return 0;
|
||||
}
|
||||
return Pos;
|
||||
}
|
||||
|
||||
if ((Res = ParseDrive(FileName, Pos)))
|
||||
return Pos + Res;
|
||||
|
||||
return Pos;
|
||||
}
|
||||
|
||||
std::string DirName(const std::string &FileName) {
|
||||
size_t LocationLen = ParseLocation(FileName);
|
||||
size_t DirLen = 0, Res;
|
||||
while ((Res = ParseDir(FileName, LocationLen + DirLen)))
|
||||
DirLen += Res;
|
||||
size_t FileLen = ParseFileName(FileName, LocationLen + DirLen);
|
||||
|
||||
if (LocationLen + DirLen + FileLen != FileName.size()) {
|
||||
Printf("DirName() failed for \"%s\", invalid path.\n", FileName.c_str());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (DirLen) {
|
||||
--DirLen; // Remove trailing separator.
|
||||
if (!FileLen) { // Path ended in separator.
|
||||
assert(DirLen);
|
||||
// Remove file name from Dir.
|
||||
while (DirLen && !IsSeparator(FileName[LocationLen + DirLen - 1]))
|
||||
--DirLen;
|
||||
if (DirLen) // Remove trailing separator.
|
||||
--DirLen;
|
||||
}
|
||||
}
|
||||
|
||||
if (!LocationLen) { // Relative path.
|
||||
if (!DirLen)
|
||||
return ".";
|
||||
return std::string(".\\").append(FileName, 0, DirLen);
|
||||
}
|
||||
|
||||
return FileName.substr(0, LocationLen + DirLen);
|
||||
}
|
||||
|
||||
} // namespace fuzzer
|
||||
|
||||
#endif // LIBFUZZER_WINDOWS
|
||||
@@ -1,67 +0,0 @@
|
||||
//===- FuzzerInterface.h - Interface header for the Fuzzer ------*- C++ -* ===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Define the interface between libFuzzer and the library being tested.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// NOTE: the libFuzzer interface is thin and in the majority of cases
|
||||
// you should not include this file into your target. In 95% of cases
|
||||
// all you need is to define the following function in your file:
|
||||
// extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
|
||||
|
||||
// WARNING: keep the interface in C.
|
||||
|
||||
#ifndef LLVM_FUZZER_INTERFACE_H
|
||||
#define LLVM_FUZZER_INTERFACE_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
// Mandatory user-provided target function.
|
||||
// Executes the code under test with [Data, Data+Size) as the input.
|
||||
// libFuzzer will invoke this function *many* times with different inputs.
|
||||
// Must return 0.
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
|
||||
|
||||
// Optional user-provided initialization function.
|
||||
// If provided, this function will be called by libFuzzer once at startup.
|
||||
// It may read and modify argc/argv.
|
||||
// Must return 0.
|
||||
int LLVMFuzzerInitialize(int *argc, char ***argv);
|
||||
|
||||
// Optional user-provided custom mutator.
|
||||
// Mutates raw data in [Data, Data+Size) inplace.
|
||||
// Returns the new size, which is not greater than MaxSize.
|
||||
// Given the same Seed produces the same mutation.
|
||||
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize,
|
||||
unsigned int Seed);
|
||||
|
||||
// Optional user-provided custom cross-over function.
|
||||
// Combines pieces of Data1 & Data2 together into Out.
|
||||
// Returns the new size, which is not greater than MaxOutSize.
|
||||
// Should produce the same mutation given the same Seed.
|
||||
size_t LLVMFuzzerCustomCrossOver(const uint8_t *Data1, size_t Size1,
|
||||
const uint8_t *Data2, size_t Size2,
|
||||
uint8_t *Out, size_t MaxOutSize,
|
||||
unsigned int Seed);
|
||||
|
||||
// Experimental, may go away in future.
|
||||
// libFuzzer-provided function to be used inside LLVMFuzzerTestOneInput.
|
||||
// Mutates raw data in [Data, Data+Size) inplace.
|
||||
// Returns the new size, which is not greater than MaxSize.
|
||||
size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif // LLVM_FUZZER_INTERFACE_H
|
||||
@@ -1,182 +0,0 @@
|
||||
//===- FuzzerInternal.h - Internal header for the Fuzzer --------*- C++ -* ===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Define the main class fuzzer::Fuzzer and most functions.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_FUZZER_INTERNAL_H
|
||||
#define LLVM_FUZZER_INTERNAL_H
|
||||
|
||||
#include "FuzzerDefs.h"
|
||||
#include "FuzzerExtFunctions.h"
|
||||
#include "FuzzerInterface.h"
|
||||
#include "FuzzerOptions.h"
|
||||
#include "FuzzerSHA1.h"
|
||||
#include "FuzzerValueBitMap.h"
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <climits>
|
||||
#include <cstdlib>
|
||||
#include <string.h>
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
using namespace std::chrono;
|
||||
|
||||
class Fuzzer {
|
||||
public:
|
||||
|
||||
// Aggregates all available coverage measurements.
|
||||
struct Coverage {
|
||||
Coverage() { Reset(); }
|
||||
|
||||
void Reset() {
|
||||
BlockCoverage = 0;
|
||||
CallerCalleeCoverage = 0;
|
||||
CounterBitmapBits = 0;
|
||||
CounterBitmap.clear();
|
||||
VPMap.Reset();
|
||||
}
|
||||
|
||||
size_t BlockCoverage;
|
||||
size_t CallerCalleeCoverage;
|
||||
// Precalculated number of bits in CounterBitmap.
|
||||
size_t CounterBitmapBits;
|
||||
std::vector<uint8_t> CounterBitmap;
|
||||
ValueBitMap VPMap;
|
||||
};
|
||||
|
||||
Fuzzer(UserCallback CB, InputCorpus &Corpus, MutationDispatcher &MD,
|
||||
FuzzingOptions Options);
|
||||
~Fuzzer();
|
||||
void Loop();
|
||||
void MinimizeCrashLoop(const Unit &U);
|
||||
void ShuffleAndMinimize(UnitVector *V);
|
||||
void InitializeTraceState();
|
||||
void RereadOutputCorpus(size_t MaxSize);
|
||||
|
||||
size_t secondsSinceProcessStartUp() {
|
||||
return duration_cast<seconds>(system_clock::now() - ProcessStartTime)
|
||||
.count();
|
||||
}
|
||||
|
||||
bool TimedOut() {
|
||||
return Options.MaxTotalTimeSec > 0 &&
|
||||
secondsSinceProcessStartUp() >
|
||||
static_cast<size_t>(Options.MaxTotalTimeSec);
|
||||
}
|
||||
|
||||
size_t execPerSec() {
|
||||
size_t Seconds = secondsSinceProcessStartUp();
|
||||
return Seconds ? TotalNumberOfRuns / Seconds : 0;
|
||||
}
|
||||
|
||||
size_t getTotalNumberOfRuns() { return TotalNumberOfRuns; }
|
||||
|
||||
static void StaticAlarmCallback();
|
||||
static void StaticCrashSignalCallback();
|
||||
static void StaticInterruptCallback();
|
||||
|
||||
void ExecuteCallback(const uint8_t *Data, size_t Size);
|
||||
size_t RunOne(const uint8_t *Data, size_t Size);
|
||||
|
||||
// Merge Corpora[1:] into Corpora[0].
|
||||
void Merge(const std::vector<std::string> &Corpora);
|
||||
void CrashResistantMerge(const std::vector<std::string> &Args,
|
||||
const std::vector<std::string> &Corpora);
|
||||
void CrashResistantMergeInternalStep(const std::string &ControlFilePath);
|
||||
// Returns a subset of 'Extra' that adds coverage to 'Initial'.
|
||||
UnitVector FindExtraUnits(const UnitVector &Initial, const UnitVector &Extra);
|
||||
MutationDispatcher &GetMD() { return MD; }
|
||||
void PrintFinalStats();
|
||||
void SetMaxInputLen(size_t MaxInputLen);
|
||||
void SetMaxMutationLen(size_t MaxMutationLen);
|
||||
void RssLimitCallback();
|
||||
|
||||
// Public for tests.
|
||||
void ResetCoverage();
|
||||
|
||||
bool InFuzzingThread() const { return IsMyThread; }
|
||||
size_t GetCurrentUnitInFuzzingThead(const uint8_t **Data) const;
|
||||
void TryDetectingAMemoryLeak(const uint8_t *Data, size_t Size,
|
||||
bool DuringInitialCorpusExecution);
|
||||
|
||||
void HandleMalloc(size_t Size);
|
||||
|
||||
private:
|
||||
void AlarmCallback();
|
||||
void CrashCallback();
|
||||
void InterruptCallback();
|
||||
void MutateAndTestOne();
|
||||
void ReportNewCoverage(InputInfo *II, const Unit &U);
|
||||
size_t RunOne(const Unit &U) { return RunOne(U.data(), U.size()); }
|
||||
void WriteToOutputCorpus(const Unit &U);
|
||||
void WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix);
|
||||
void PrintStats(const char *Where, const char *End = "\n", size_t Units = 0);
|
||||
void PrintStatusForNewUnit(const Unit &U);
|
||||
void ShuffleCorpus(UnitVector *V);
|
||||
void AddToCorpus(const Unit &U);
|
||||
void CheckExitOnSrcPosOrItem();
|
||||
|
||||
// Trace-based fuzzing: we run a unit with some kind of tracing
|
||||
// enabled and record potentially useful mutations. Then
|
||||
// We apply these mutations one by one to the unit and run it again.
|
||||
|
||||
// Start tracing; forget all previously proposed mutations.
|
||||
void StartTraceRecording();
|
||||
// Stop tracing.
|
||||
void StopTraceRecording();
|
||||
|
||||
void SetDeathCallback();
|
||||
static void StaticDeathCallback();
|
||||
void DumpCurrentUnit(const char *Prefix);
|
||||
void DeathCallback();
|
||||
|
||||
void ResetEdgeCoverage();
|
||||
void ResetCounters();
|
||||
void PrepareCounters(Fuzzer::Coverage *C);
|
||||
bool RecordMaxCoverage(Fuzzer::Coverage *C);
|
||||
|
||||
void AllocateCurrentUnitData();
|
||||
uint8_t *CurrentUnitData = nullptr;
|
||||
std::atomic<size_t> CurrentUnitSize;
|
||||
uint8_t BaseSha1[kSHA1NumBytes]; // Checksum of the base unit.
|
||||
bool RunningCB = false;
|
||||
|
||||
size_t TotalNumberOfRuns = 0;
|
||||
size_t NumberOfNewUnitsAdded = 0;
|
||||
|
||||
bool HasMoreMallocsThanFrees = false;
|
||||
size_t NumberOfLeakDetectionAttempts = 0;
|
||||
|
||||
UserCallback CB;
|
||||
InputCorpus &Corpus;
|
||||
MutationDispatcher &MD;
|
||||
FuzzingOptions Options;
|
||||
|
||||
system_clock::time_point ProcessStartTime = system_clock::now();
|
||||
system_clock::time_point UnitStartTime, UnitStopTime;
|
||||
long TimeOfLongestUnitInSeconds = 0;
|
||||
long EpochOfLastReadOfOutputCorpus = 0;
|
||||
|
||||
// Maximum recorded coverage.
|
||||
Coverage MaxCoverage;
|
||||
|
||||
size_t MaxInputLen = 0;
|
||||
size_t MaxMutationLen = 0;
|
||||
|
||||
// Need to know our own thread.
|
||||
static thread_local bool IsMyThread;
|
||||
|
||||
bool InMergeMode = false;
|
||||
};
|
||||
|
||||
}; // namespace fuzzer
|
||||
|
||||
#endif // LLVM_FUZZER_INTERNAL_H
|
||||
@@ -1,792 +0,0 @@
|
||||
//===- FuzzerLoop.cpp - Fuzzer's main loop --------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Fuzzer's main loop.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "FuzzerCorpus.h"
|
||||
#include "FuzzerInternal.h"
|
||||
#include "FuzzerIO.h"
|
||||
#include "FuzzerMutate.h"
|
||||
#include "FuzzerRandom.h"
|
||||
#include "FuzzerTracePC.h"
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
|
||||
#if defined(__has_include)
|
||||
#if __has_include(<sanitizer / coverage_interface.h>)
|
||||
#include <sanitizer/coverage_interface.h>
|
||||
#endif
|
||||
#if __has_include(<sanitizer / lsan_interface.h>)
|
||||
#include <sanitizer/lsan_interface.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define NO_SANITIZE_MEMORY
|
||||
#if defined(__has_feature)
|
||||
#if __has_feature(memory_sanitizer)
|
||||
#undef NO_SANITIZE_MEMORY
|
||||
#define NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace fuzzer {
|
||||
static const size_t kMaxUnitSizeToPrint = 256;
|
||||
|
||||
thread_local bool Fuzzer::IsMyThread;
|
||||
|
||||
static void MissingExternalApiFunction(const char *FnName) {
|
||||
Printf("ERROR: %s is not defined. Exiting.\n"
|
||||
"Did you use -fsanitize-coverage=... to build your code?\n",
|
||||
FnName);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#define CHECK_EXTERNAL_FUNCTION(fn) \
|
||||
do { \
|
||||
if (!(EF->fn)) \
|
||||
MissingExternalApiFunction(#fn); \
|
||||
} while (false)
|
||||
|
||||
// Only one Fuzzer per process.
|
||||
static Fuzzer *F;
|
||||
|
||||
void Fuzzer::ResetEdgeCoverage() {
|
||||
CHECK_EXTERNAL_FUNCTION(__sanitizer_reset_coverage);
|
||||
EF->__sanitizer_reset_coverage();
|
||||
}
|
||||
|
||||
void Fuzzer::ResetCounters() {
|
||||
if (Options.UseCounters)
|
||||
EF->__sanitizer_update_counter_bitset_and_clear_counters(0);
|
||||
}
|
||||
|
||||
void Fuzzer::PrepareCounters(Fuzzer::Coverage *C) {
|
||||
if (Options.UseCounters) {
|
||||
size_t NumCounters = EF->__sanitizer_get_number_of_counters();
|
||||
C->CounterBitmap.resize(NumCounters);
|
||||
}
|
||||
}
|
||||
|
||||
// Records data to a maximum coverage tracker. Returns true if additional
|
||||
// coverage was discovered.
|
||||
bool Fuzzer::RecordMaxCoverage(Fuzzer::Coverage *C) {
|
||||
bool Res = false;
|
||||
|
||||
uint64_t NewBlockCoverage = EF->__sanitizer_get_total_unique_coverage();
|
||||
if (NewBlockCoverage > C->BlockCoverage) {
|
||||
Res = true;
|
||||
C->BlockCoverage = NewBlockCoverage;
|
||||
}
|
||||
|
||||
if (Options.UseIndirCalls &&
|
||||
EF->__sanitizer_get_total_unique_caller_callee_pairs) {
|
||||
uint64_t NewCallerCalleeCoverage =
|
||||
EF->__sanitizer_get_total_unique_caller_callee_pairs();
|
||||
if (NewCallerCalleeCoverage > C->CallerCalleeCoverage) {
|
||||
Res = true;
|
||||
C->CallerCalleeCoverage = NewCallerCalleeCoverage;
|
||||
}
|
||||
}
|
||||
|
||||
if (Options.UseCounters) {
|
||||
uint64_t CounterDelta =
|
||||
EF->__sanitizer_update_counter_bitset_and_clear_counters(
|
||||
C->CounterBitmap.data());
|
||||
if (CounterDelta > 0) {
|
||||
Res = true;
|
||||
C->CounterBitmapBits += CounterDelta;
|
||||
}
|
||||
}
|
||||
|
||||
return Res;
|
||||
}
|
||||
|
||||
// Leak detection is expensive, so we first check if there were more mallocs
|
||||
// than frees (using the sanitizer malloc hooks) and only then try to call lsan.
|
||||
struct MallocFreeTracer {
|
||||
void Start(int TraceLevel) {
|
||||
this->TraceLevel = TraceLevel;
|
||||
if (TraceLevel)
|
||||
Printf("MallocFreeTracer: START\n");
|
||||
Mallocs = 0;
|
||||
Frees = 0;
|
||||
}
|
||||
// Returns true if there were more mallocs than frees.
|
||||
bool Stop() {
|
||||
if (TraceLevel)
|
||||
Printf("MallocFreeTracer: STOP %zd %zd (%s)\n", Mallocs.load(),
|
||||
Frees.load(), Mallocs == Frees ? "same" : "DIFFERENT");
|
||||
bool Result = Mallocs > Frees;
|
||||
Mallocs = 0;
|
||||
Frees = 0;
|
||||
TraceLevel = 0;
|
||||
return Result;
|
||||
}
|
||||
std::atomic<size_t> Mallocs;
|
||||
std::atomic<size_t> Frees;
|
||||
int TraceLevel = 0;
|
||||
};
|
||||
|
||||
static MallocFreeTracer AllocTracer;
|
||||
|
||||
ATTRIBUTE_NO_SANITIZE_MEMORY
|
||||
void MallocHook(const volatile void *ptr, size_t size) {
|
||||
size_t N = AllocTracer.Mallocs++;
|
||||
F->HandleMalloc(size);
|
||||
if (int TraceLevel = AllocTracer.TraceLevel) {
|
||||
Printf("MALLOC[%zd] %p %zd\n", N, ptr, size);
|
||||
if (TraceLevel >= 2 && EF)
|
||||
EF->__sanitizer_print_stack_trace();
|
||||
}
|
||||
}
|
||||
|
||||
ATTRIBUTE_NO_SANITIZE_MEMORY
|
||||
void FreeHook(const volatile void *ptr) {
|
||||
size_t N = AllocTracer.Frees++;
|
||||
if (int TraceLevel = AllocTracer.TraceLevel) {
|
||||
Printf("FREE[%zd] %p\n", N, ptr);
|
||||
if (TraceLevel >= 2 && EF)
|
||||
EF->__sanitizer_print_stack_trace();
|
||||
}
|
||||
}
|
||||
|
||||
// Crash on a single malloc that exceeds the rss limit.
|
||||
void Fuzzer::HandleMalloc(size_t Size) {
|
||||
if (!Options.RssLimitMb || (Size >> 20) < (size_t)Options.RssLimitMb)
|
||||
return;
|
||||
Printf("==%d== ERROR: libFuzzer: out-of-memory (malloc(%zd))\n", GetPid(),
|
||||
Size);
|
||||
Printf(" To change the out-of-memory limit use -rss_limit_mb=<N>\n\n");
|
||||
if (EF->__sanitizer_print_stack_trace)
|
||||
EF->__sanitizer_print_stack_trace();
|
||||
DumpCurrentUnit("oom-");
|
||||
Printf("SUMMARY: libFuzzer: out-of-memory\n");
|
||||
PrintFinalStats();
|
||||
_Exit(Options.ErrorExitCode); // Stop right now.
|
||||
}
|
||||
|
||||
Fuzzer::Fuzzer(UserCallback CB, InputCorpus &Corpus, MutationDispatcher &MD,
|
||||
FuzzingOptions Options)
|
||||
: CB(CB), Corpus(Corpus), MD(MD), Options(Options) {
|
||||
SetDeathCallback();
|
||||
InitializeTraceState();
|
||||
assert(!F);
|
||||
F = this;
|
||||
TPC.ResetMaps();
|
||||
ResetCoverage();
|
||||
IsMyThread = true;
|
||||
if (Options.DetectLeaks && EF->__sanitizer_install_malloc_and_free_hooks)
|
||||
EF->__sanitizer_install_malloc_and_free_hooks(MallocHook, FreeHook);
|
||||
TPC.SetUseCounters(Options.UseCounters);
|
||||
TPC.SetUseValueProfile(Options.UseValueProfile);
|
||||
TPC.SetPrintNewPCs(Options.PrintNewCovPcs);
|
||||
|
||||
if (Options.Verbosity)
|
||||
TPC.PrintModuleInfo();
|
||||
if (!Options.OutputCorpus.empty() && Options.ReloadIntervalSec)
|
||||
EpochOfLastReadOfOutputCorpus = GetEpoch(Options.OutputCorpus);
|
||||
MaxInputLen = MaxMutationLen = Options.MaxLen;
|
||||
AllocateCurrentUnitData();
|
||||
CurrentUnitSize = 0;
|
||||
memset(BaseSha1, 0, sizeof(BaseSha1));
|
||||
}
|
||||
|
||||
Fuzzer::~Fuzzer() { }
|
||||
|
||||
void Fuzzer::AllocateCurrentUnitData() {
|
||||
if (CurrentUnitData || MaxInputLen == 0) return;
|
||||
CurrentUnitData = new uint8_t[MaxInputLen];
|
||||
}
|
||||
|
||||
void Fuzzer::SetDeathCallback() {
|
||||
CHECK_EXTERNAL_FUNCTION(__sanitizer_set_death_callback);
|
||||
EF->__sanitizer_set_death_callback(StaticDeathCallback);
|
||||
}
|
||||
|
||||
void Fuzzer::StaticDeathCallback() {
|
||||
assert(F);
|
||||
F->DeathCallback();
|
||||
}
|
||||
|
||||
static void WarnOnUnsuccessfullMerge(bool DoWarn) {
|
||||
if (!DoWarn) return;
|
||||
Printf(
|
||||
"***\n"
|
||||
"***\n"
|
||||
"***\n"
|
||||
"*** NOTE: merge did not succeed due to a failure on one of the inputs.\n"
|
||||
"*** You will need to filter out crashes from the corpus, e.g. like this:\n"
|
||||
"*** for f in WITH_CRASHES/*; do ./fuzzer $f && cp $f NO_CRASHES; done\n"
|
||||
"*** Future versions may have crash-resistant merge, stay tuned.\n"
|
||||
"***\n"
|
||||
"***\n"
|
||||
"***\n");
|
||||
}
|
||||
|
||||
void Fuzzer::DumpCurrentUnit(const char *Prefix) {
|
||||
WarnOnUnsuccessfullMerge(InMergeMode);
|
||||
if (!CurrentUnitData) return; // Happens when running individual inputs.
|
||||
MD.PrintMutationSequence();
|
||||
Printf("; base unit: %s\n", Sha1ToString(BaseSha1).c_str());
|
||||
size_t UnitSize = CurrentUnitSize;
|
||||
if (UnitSize <= kMaxUnitSizeToPrint) {
|
||||
PrintHexArray(CurrentUnitData, UnitSize, "\n");
|
||||
PrintASCII(CurrentUnitData, UnitSize, "\n");
|
||||
}
|
||||
WriteUnitToFileWithPrefix({CurrentUnitData, CurrentUnitData + UnitSize},
|
||||
Prefix);
|
||||
}
|
||||
|
||||
NO_SANITIZE_MEMORY
|
||||
void Fuzzer::DeathCallback() {
|
||||
DumpCurrentUnit("crash-");
|
||||
PrintFinalStats();
|
||||
}
|
||||
|
||||
void Fuzzer::StaticAlarmCallback() {
|
||||
assert(F);
|
||||
F->AlarmCallback();
|
||||
}
|
||||
|
||||
void Fuzzer::StaticCrashSignalCallback() {
|
||||
assert(F);
|
||||
F->CrashCallback();
|
||||
}
|
||||
|
||||
void Fuzzer::StaticInterruptCallback() {
|
||||
assert(F);
|
||||
F->InterruptCallback();
|
||||
}
|
||||
|
||||
void Fuzzer::CrashCallback() {
|
||||
Printf("==%lu== ERROR: libFuzzer: deadly signal\n", GetPid());
|
||||
if (EF->__sanitizer_print_stack_trace)
|
||||
EF->__sanitizer_print_stack_trace();
|
||||
Printf("NOTE: libFuzzer has rudimentary signal handlers.\n"
|
||||
" Combine libFuzzer with AddressSanitizer or similar for better "
|
||||
"crash reports.\n");
|
||||
Printf("SUMMARY: libFuzzer: deadly signal\n");
|
||||
DumpCurrentUnit("crash-");
|
||||
PrintFinalStats();
|
||||
exit(Options.ErrorExitCode);
|
||||
}
|
||||
|
||||
void Fuzzer::InterruptCallback() {
|
||||
Printf("==%lu== libFuzzer: run interrupted; exiting\n", GetPid());
|
||||
PrintFinalStats();
|
||||
_Exit(0); // Stop right now, don't perform any at-exit actions.
|
||||
}
|
||||
|
||||
NO_SANITIZE_MEMORY
|
||||
void Fuzzer::AlarmCallback() {
|
||||
assert(Options.UnitTimeoutSec > 0);
|
||||
if (!InFuzzingThread()) return;
|
||||
if (!RunningCB)
|
||||
return; // We have not started running units yet.
|
||||
size_t Seconds =
|
||||
duration_cast<seconds>(system_clock::now() - UnitStartTime).count();
|
||||
if (Seconds == 0)
|
||||
return;
|
||||
if (Options.Verbosity >= 2)
|
||||
Printf("AlarmCallback %zd\n", Seconds);
|
||||
if (Seconds >= (size_t)Options.UnitTimeoutSec) {
|
||||
Printf("ALARM: working on the last Unit for %zd seconds\n", Seconds);
|
||||
Printf(" and the timeout value is %d (use -timeout=N to change)\n",
|
||||
Options.UnitTimeoutSec);
|
||||
DumpCurrentUnit("timeout-");
|
||||
Printf("==%lu== ERROR: libFuzzer: timeout after %d seconds\n", GetPid(),
|
||||
Seconds);
|
||||
if (EF->__sanitizer_print_stack_trace)
|
||||
EF->__sanitizer_print_stack_trace();
|
||||
Printf("SUMMARY: libFuzzer: timeout\n");
|
||||
PrintFinalStats();
|
||||
_Exit(Options.TimeoutExitCode); // Stop right now.
|
||||
}
|
||||
}
|
||||
|
||||
void Fuzzer::RssLimitCallback() {
|
||||
Printf(
|
||||
"==%lu== ERROR: libFuzzer: out-of-memory (used: %zdMb; limit: %zdMb)\n",
|
||||
GetPid(), GetPeakRSSMb(), Options.RssLimitMb);
|
||||
Printf(" To change the out-of-memory limit use -rss_limit_mb=<N>\n\n");
|
||||
if (EF->__sanitizer_print_memory_profile)
|
||||
EF->__sanitizer_print_memory_profile(95);
|
||||
DumpCurrentUnit("oom-");
|
||||
Printf("SUMMARY: libFuzzer: out-of-memory\n");
|
||||
PrintFinalStats();
|
||||
_Exit(Options.ErrorExitCode); // Stop right now.
|
||||
}
|
||||
|
||||
void Fuzzer::PrintStats(const char *Where, const char *End, size_t Units) {
|
||||
size_t ExecPerSec = execPerSec();
|
||||
if (Options.OutputCSV) {
|
||||
static bool csvHeaderPrinted = false;
|
||||
if (!csvHeaderPrinted) {
|
||||
csvHeaderPrinted = true;
|
||||
Printf("runs,block_cov,bits,cc_cov,corpus,execs_per_sec,tbms,reason\n");
|
||||
}
|
||||
Printf("%zd,%zd,%zd,%zd,%zd,%zd,%s\n", TotalNumberOfRuns,
|
||||
MaxCoverage.BlockCoverage, MaxCoverage.CounterBitmapBits,
|
||||
MaxCoverage.CallerCalleeCoverage, Corpus.size(), ExecPerSec, Where);
|
||||
}
|
||||
|
||||
if (!Options.Verbosity)
|
||||
return;
|
||||
Printf("#%zd\t%s", TotalNumberOfRuns, Where);
|
||||
if (MaxCoverage.BlockCoverage)
|
||||
Printf(" cov: %zd", MaxCoverage.BlockCoverage);
|
||||
if (size_t N = MaxCoverage.VPMap.GetNumBitsSinceLastMerge())
|
||||
Printf(" vp: %zd", N);
|
||||
if (size_t N = TPC.GetTotalPCCoverage())
|
||||
Printf(" cov: %zd", N);
|
||||
if (auto TB = MaxCoverage.CounterBitmapBits)
|
||||
Printf(" bits: %zd", TB);
|
||||
if (size_t N = Corpus.NumFeatures())
|
||||
Printf( " ft: %zd", N);
|
||||
if (MaxCoverage.CallerCalleeCoverage)
|
||||
Printf(" indir: %zd", MaxCoverage.CallerCalleeCoverage);
|
||||
if (!Corpus.empty()) {
|
||||
Printf(" corp: %zd", Corpus.NumActiveUnits());
|
||||
if (size_t N = Corpus.SizeInBytes()) {
|
||||
if (N < (1<<14))
|
||||
Printf("/%zdb", N);
|
||||
else if (N < (1 << 24))
|
||||
Printf("/%zdKb", N >> 10);
|
||||
else
|
||||
Printf("/%zdMb", N >> 20);
|
||||
}
|
||||
}
|
||||
if (Units)
|
||||
Printf(" units: %zd", Units);
|
||||
|
||||
Printf(" exec/s: %zd", ExecPerSec);
|
||||
Printf(" rss: %zdMb", GetPeakRSSMb());
|
||||
Printf("%s", End);
|
||||
}
|
||||
|
||||
void Fuzzer::PrintFinalStats() {
|
||||
if (Options.PrintCoverage)
|
||||
TPC.PrintCoverage();
|
||||
if (Options.DumpCoverage)
|
||||
TPC.DumpCoverage();
|
||||
if (Options.PrintCorpusStats)
|
||||
Corpus.PrintStats();
|
||||
if (!Options.PrintFinalStats) return;
|
||||
size_t ExecPerSec = execPerSec();
|
||||
Printf("stat::number_of_executed_units: %zd\n", TotalNumberOfRuns);
|
||||
Printf("stat::average_exec_per_sec: %zd\n", ExecPerSec);
|
||||
Printf("stat::new_units_added: %zd\n", NumberOfNewUnitsAdded);
|
||||
Printf("stat::slowest_unit_time_sec: %zd\n", TimeOfLongestUnitInSeconds);
|
||||
Printf("stat::peak_rss_mb: %zd\n", GetPeakRSSMb());
|
||||
}
|
||||
|
||||
void Fuzzer::SetMaxInputLen(size_t MaxInputLen) {
|
||||
assert(this->MaxInputLen == 0); // Can only reset MaxInputLen from 0 to non-0.
|
||||
assert(MaxInputLen);
|
||||
this->MaxInputLen = MaxInputLen;
|
||||
this->MaxMutationLen = MaxInputLen;
|
||||
AllocateCurrentUnitData();
|
||||
Printf("INFO: -max_len is not provided, using %zd\n", MaxInputLen);
|
||||
}
|
||||
|
||||
void Fuzzer::SetMaxMutationLen(size_t MaxMutationLen) {
|
||||
assert(MaxMutationLen && MaxMutationLen <= MaxInputLen);
|
||||
this->MaxMutationLen = MaxMutationLen;
|
||||
}
|
||||
|
||||
void Fuzzer::CheckExitOnSrcPosOrItem() {
|
||||
if (!Options.ExitOnSrcPos.empty()) {
|
||||
static auto *PCsSet = new std::set<uintptr_t>;
|
||||
for (size_t i = 1, N = TPC.GetNumPCs(); i < N; i++) {
|
||||
uintptr_t PC = TPC.GetPC(i);
|
||||
if (!PC) continue;
|
||||
if (!PCsSet->insert(PC).second) continue;
|
||||
std::string Descr = DescribePC("%L", PC);
|
||||
if (Descr.find(Options.ExitOnSrcPos) != std::string::npos) {
|
||||
Printf("INFO: found line matching '%s', exiting.\n",
|
||||
Options.ExitOnSrcPos.c_str());
|
||||
_Exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!Options.ExitOnItem.empty()) {
|
||||
if (Corpus.HasUnit(Options.ExitOnItem)) {
|
||||
Printf("INFO: found item with checksum '%s', exiting.\n",
|
||||
Options.ExitOnItem.c_str());
|
||||
_Exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Fuzzer::RereadOutputCorpus(size_t MaxSize) {
|
||||
if (Options.OutputCorpus.empty() || !Options.ReloadIntervalSec) return;
|
||||
std::vector<Unit> AdditionalCorpus;
|
||||
ReadDirToVectorOfUnits(Options.OutputCorpus.c_str(), &AdditionalCorpus,
|
||||
&EpochOfLastReadOfOutputCorpus, MaxSize,
|
||||
/*ExitOnError*/ false);
|
||||
if (Options.Verbosity >= 2)
|
||||
Printf("Reload: read %zd new units.\n", AdditionalCorpus.size());
|
||||
bool Reloaded = false;
|
||||
for (auto &U : AdditionalCorpus) {
|
||||
if (U.size() > MaxSize)
|
||||
U.resize(MaxSize);
|
||||
if (!Corpus.HasUnit(U)) {
|
||||
if (size_t NumFeatures = RunOne(U)) {
|
||||
CheckExitOnSrcPosOrItem();
|
||||
Corpus.AddToCorpus(U, NumFeatures);
|
||||
Reloaded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Reloaded)
|
||||
PrintStats("RELOAD");
|
||||
}
|
||||
|
||||
void Fuzzer::ShuffleCorpus(UnitVector *V) {
|
||||
std::random_shuffle(V->begin(), V->end(), MD.GetRand());
|
||||
if (Options.PreferSmall)
|
||||
std::stable_sort(V->begin(), V->end(), [](const Unit &A, const Unit &B) {
|
||||
return A.size() < B.size();
|
||||
});
|
||||
}
|
||||
|
||||
void Fuzzer::ShuffleAndMinimize(UnitVector *InitialCorpus) {
|
||||
Printf("#0\tREAD units: %zd\n", InitialCorpus->size());
|
||||
if (Options.ShuffleAtStartUp)
|
||||
ShuffleCorpus(InitialCorpus);
|
||||
|
||||
// Test the callback with empty input and never try it again.
|
||||
uint8_t dummy;
|
||||
ExecuteCallback(&dummy, 0);
|
||||
|
||||
for (const auto &U : *InitialCorpus) {
|
||||
if (size_t NumFeatures = RunOne(U)) {
|
||||
CheckExitOnSrcPosOrItem();
|
||||
Corpus.AddToCorpus(U, NumFeatures);
|
||||
if (Options.Verbosity >= 2)
|
||||
Printf("NEW0: %zd L %zd\n", MaxCoverage.BlockCoverage, U.size());
|
||||
}
|
||||
TryDetectingAMemoryLeak(U.data(), U.size(),
|
||||
/*DuringInitialCorpusExecution*/ true);
|
||||
}
|
||||
PrintStats("INITED");
|
||||
if (Corpus.empty()) {
|
||||
Printf("ERROR: no interesting inputs were found. "
|
||||
"Is the code instrumented for coverage? Exiting.\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
size_t Fuzzer::RunOne(const uint8_t *Data, size_t Size) {
|
||||
if (!Size) return 0;
|
||||
TotalNumberOfRuns++;
|
||||
|
||||
ExecuteCallback(Data, Size);
|
||||
|
||||
size_t Res = 0;
|
||||
if (size_t NumFeatures = TPC.CollectFeatures([&](size_t Feature) -> bool {
|
||||
return Corpus.AddFeature(Feature, Size, Options.Shrink);
|
||||
}))
|
||||
Res = NumFeatures;
|
||||
|
||||
if (!TPC.UsingTracePcGuard()) {
|
||||
if (TPC.UpdateValueProfileMap(&MaxCoverage.VPMap))
|
||||
Res = 1;
|
||||
if (!Res && RecordMaxCoverage(&MaxCoverage))
|
||||
Res = 1;
|
||||
}
|
||||
|
||||
auto TimeOfUnit =
|
||||
duration_cast<seconds>(UnitStopTime - UnitStartTime).count();
|
||||
if (!(TotalNumberOfRuns & (TotalNumberOfRuns - 1)) &&
|
||||
secondsSinceProcessStartUp() >= 2)
|
||||
PrintStats("pulse ");
|
||||
if (TimeOfUnit > TimeOfLongestUnitInSeconds * 1.1 &&
|
||||
TimeOfUnit >= Options.ReportSlowUnits) {
|
||||
TimeOfLongestUnitInSeconds = TimeOfUnit;
|
||||
Printf("Slowest unit: %zd s:\n", TimeOfLongestUnitInSeconds);
|
||||
WriteUnitToFileWithPrefix({Data, Data + Size}, "slow-unit-");
|
||||
}
|
||||
return Res;
|
||||
}
|
||||
|
||||
size_t Fuzzer::GetCurrentUnitInFuzzingThead(const uint8_t **Data) const {
|
||||
assert(InFuzzingThread());
|
||||
*Data = CurrentUnitData;
|
||||
return CurrentUnitSize;
|
||||
}
|
||||
|
||||
void Fuzzer::ExecuteCallback(const uint8_t *Data, size_t Size) {
|
||||
assert(InFuzzingThread());
|
||||
// We copy the contents of Unit into a separate heap buffer
|
||||
// so that we reliably find buffer overflows in it.
|
||||
uint8_t *DataCopy = new uint8_t[Size];
|
||||
memcpy(DataCopy, Data, Size);
|
||||
if (CurrentUnitData && CurrentUnitData != Data)
|
||||
memcpy(CurrentUnitData, Data, Size);
|
||||
CurrentUnitSize = Size;
|
||||
AllocTracer.Start(Options.TraceMalloc);
|
||||
UnitStartTime = system_clock::now();
|
||||
ResetCounters(); // Reset coverage right before the callback.
|
||||
TPC.ResetMaps();
|
||||
RunningCB = true;
|
||||
int Res = CB(DataCopy, Size);
|
||||
RunningCB = false;
|
||||
UnitStopTime = system_clock::now();
|
||||
(void)Res;
|
||||
assert(Res == 0);
|
||||
HasMoreMallocsThanFrees = AllocTracer.Stop();
|
||||
CurrentUnitSize = 0;
|
||||
delete[] DataCopy;
|
||||
}
|
||||
|
||||
void Fuzzer::WriteToOutputCorpus(const Unit &U) {
|
||||
if (Options.OnlyASCII)
|
||||
assert(IsASCII(U));
|
||||
if (Options.OutputCorpus.empty())
|
||||
return;
|
||||
std::string Path = DirPlusFile(Options.OutputCorpus, Hash(U));
|
||||
WriteToFile(U, Path);
|
||||
if (Options.Verbosity >= 2)
|
||||
Printf("Written to %s\n", Path.c_str());
|
||||
}
|
||||
|
||||
void Fuzzer::WriteUnitToFileWithPrefix(const Unit &U, const char *Prefix) {
|
||||
if (!Options.SaveArtifacts)
|
||||
return;
|
||||
std::string Path = Options.ArtifactPrefix + Prefix + Hash(U);
|
||||
if (!Options.ExactArtifactPath.empty())
|
||||
Path = Options.ExactArtifactPath; // Overrides ArtifactPrefix.
|
||||
WriteToFile(U, Path);
|
||||
Printf("artifact_prefix='%s'; Test unit written to %s\n",
|
||||
Options.ArtifactPrefix.c_str(), Path.c_str());
|
||||
if (U.size() <= kMaxUnitSizeToPrint)
|
||||
Printf("Base64: %s\n", Base64(U).c_str());
|
||||
}
|
||||
|
||||
void Fuzzer::PrintStatusForNewUnit(const Unit &U) {
|
||||
if (!Options.PrintNEW)
|
||||
return;
|
||||
PrintStats("NEW ", "");
|
||||
if (Options.Verbosity) {
|
||||
Printf(" L: %zd ", U.size());
|
||||
MD.PrintMutationSequence();
|
||||
Printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
void Fuzzer::ReportNewCoverage(InputInfo *II, const Unit &U) {
|
||||
II->NumSuccessfullMutations++;
|
||||
MD.RecordSuccessfulMutationSequence();
|
||||
PrintStatusForNewUnit(U);
|
||||
WriteToOutputCorpus(U);
|
||||
NumberOfNewUnitsAdded++;
|
||||
TPC.PrintNewPCs();
|
||||
}
|
||||
|
||||
// Finds minimal number of units in 'Extra' that add coverage to 'Initial'.
|
||||
// We do it by actually executing the units, sometimes more than once,
|
||||
// because we may be using different coverage-like signals and the only
|
||||
// common thing between them is that we can say "this unit found new stuff".
|
||||
UnitVector Fuzzer::FindExtraUnits(const UnitVector &Initial,
|
||||
const UnitVector &Extra) {
|
||||
UnitVector Res = Extra;
|
||||
UnitVector Tmp;
|
||||
size_t OldSize = Res.size();
|
||||
for (int Iter = 0; Iter < 10; Iter++) {
|
||||
ShuffleCorpus(&Res);
|
||||
TPC.ResetMaps();
|
||||
Corpus.ResetFeatureSet();
|
||||
ResetCoverage();
|
||||
|
||||
for (auto &U : Initial) {
|
||||
TPC.ResetMaps();
|
||||
RunOne(U);
|
||||
}
|
||||
|
||||
Tmp.clear();
|
||||
for (auto &U : Res) {
|
||||
TPC.ResetMaps();
|
||||
if (RunOne(U))
|
||||
Tmp.push_back(U);
|
||||
}
|
||||
|
||||
char Stat[7] = "MIN ";
|
||||
Stat[3] = '0' + Iter;
|
||||
PrintStats(Stat, "\n", Tmp.size());
|
||||
|
||||
size_t NewSize = Tmp.size();
|
||||
assert(NewSize <= OldSize);
|
||||
Res.swap(Tmp);
|
||||
|
||||
if (NewSize + 5 >= OldSize)
|
||||
break;
|
||||
OldSize = NewSize;
|
||||
}
|
||||
return Res;
|
||||
}
|
||||
|
||||
void Fuzzer::Merge(const std::vector<std::string> &Corpora) {
|
||||
if (Corpora.size() <= 1) {
|
||||
Printf("Merge requires two or more corpus dirs\n");
|
||||
return;
|
||||
}
|
||||
InMergeMode = true;
|
||||
std::vector<std::string> ExtraCorpora(Corpora.begin() + 1, Corpora.end());
|
||||
|
||||
assert(MaxInputLen > 0);
|
||||
UnitVector Initial, Extra;
|
||||
ReadDirToVectorOfUnits(Corpora[0].c_str(), &Initial, nullptr, MaxInputLen,
|
||||
true);
|
||||
for (auto &C : ExtraCorpora)
|
||||
ReadDirToVectorOfUnits(C.c_str(), &Extra, nullptr, MaxInputLen, true);
|
||||
|
||||
if (!Initial.empty()) {
|
||||
Printf("=== Minimizing the initial corpus of %zd units\n", Initial.size());
|
||||
Initial = FindExtraUnits({}, Initial);
|
||||
}
|
||||
|
||||
Printf("=== Merging extra %zd units\n", Extra.size());
|
||||
auto Res = FindExtraUnits(Initial, Extra);
|
||||
|
||||
for (auto &U: Res)
|
||||
WriteToOutputCorpus(U);
|
||||
|
||||
Printf("=== Merge: written %zd units\n", Res.size());
|
||||
}
|
||||
|
||||
// Tries detecting a memory leak on the particular input that we have just
|
||||
// executed before calling this function.
|
||||
void Fuzzer::TryDetectingAMemoryLeak(const uint8_t *Data, size_t Size,
|
||||
bool DuringInitialCorpusExecution) {
|
||||
if (!HasMoreMallocsThanFrees) return; // mallocs==frees, a leak is unlikely.
|
||||
if (!Options.DetectLeaks) return;
|
||||
if (!&(EF->__lsan_enable) || !&(EF->__lsan_disable) ||
|
||||
!(EF->__lsan_do_recoverable_leak_check))
|
||||
return; // No lsan.
|
||||
// Run the target once again, but with lsan disabled so that if there is
|
||||
// a real leak we do not report it twice.
|
||||
EF->__lsan_disable();
|
||||
ExecuteCallback(Data, Size);
|
||||
EF->__lsan_enable();
|
||||
if (!HasMoreMallocsThanFrees) return; // a leak is unlikely.
|
||||
if (NumberOfLeakDetectionAttempts++ > 1000) {
|
||||
Options.DetectLeaks = false;
|
||||
Printf("INFO: libFuzzer disabled leak detection after every mutation.\n"
|
||||
" Most likely the target function accumulates allocated\n"
|
||||
" memory in a global state w/o actually leaking it.\n"
|
||||
" You may try running this binary with -trace_malloc=[12]"
|
||||
" to get a trace of mallocs and frees.\n"
|
||||
" If LeakSanitizer is enabled in this process it will still\n"
|
||||
" run on the process shutdown.\n");
|
||||
return;
|
||||
}
|
||||
// Now perform the actual lsan pass. This is expensive and we must ensure
|
||||
// we don't call it too often.
|
||||
if (EF->__lsan_do_recoverable_leak_check()) { // Leak is found, report it.
|
||||
if (DuringInitialCorpusExecution)
|
||||
Printf("\nINFO: a leak has been found in the initial corpus.\n\n");
|
||||
Printf("INFO: to ignore leaks on libFuzzer side use -detect_leaks=0.\n\n");
|
||||
CurrentUnitSize = Size;
|
||||
DumpCurrentUnit("leak-");
|
||||
PrintFinalStats();
|
||||
_Exit(Options.ErrorExitCode); // not exit() to disable lsan further on.
|
||||
}
|
||||
}
|
||||
|
||||
void Fuzzer::MutateAndTestOne() {
|
||||
MD.StartMutationSequence();
|
||||
|
||||
auto &II = Corpus.ChooseUnitToMutate(MD.GetRand());
|
||||
const auto &U = II.U;
|
||||
memcpy(BaseSha1, II.Sha1, sizeof(BaseSha1));
|
||||
assert(CurrentUnitData);
|
||||
size_t Size = U.size();
|
||||
assert(Size <= MaxInputLen && "Oversized Unit");
|
||||
memcpy(CurrentUnitData, U.data(), Size);
|
||||
|
||||
assert(MaxMutationLen > 0);
|
||||
|
||||
for (int i = 0; i < Options.MutateDepth; i++) {
|
||||
if (TotalNumberOfRuns >= Options.MaxNumberOfRuns)
|
||||
break;
|
||||
size_t NewSize = 0;
|
||||
NewSize = MD.Mutate(CurrentUnitData, Size, MaxMutationLen);
|
||||
assert(NewSize > 0 && "Mutator returned empty unit");
|
||||
assert(NewSize <= MaxMutationLen && "Mutator return overisized unit");
|
||||
Size = NewSize;
|
||||
if (i == 0)
|
||||
StartTraceRecording();
|
||||
II.NumExecutedMutations++;
|
||||
if (size_t NumFeatures = RunOne(CurrentUnitData, Size)) {
|
||||
Corpus.AddToCorpus({CurrentUnitData, CurrentUnitData + Size}, NumFeatures,
|
||||
/*MayDeleteFile=*/true);
|
||||
ReportNewCoverage(&II, {CurrentUnitData, CurrentUnitData + Size});
|
||||
CheckExitOnSrcPosOrItem();
|
||||
}
|
||||
StopTraceRecording();
|
||||
TryDetectingAMemoryLeak(CurrentUnitData, Size,
|
||||
/*DuringInitialCorpusExecution*/ false);
|
||||
}
|
||||
}
|
||||
|
||||
void Fuzzer::ResetCoverage() {
|
||||
ResetEdgeCoverage();
|
||||
MaxCoverage.Reset();
|
||||
PrepareCounters(&MaxCoverage);
|
||||
}
|
||||
|
||||
void Fuzzer::Loop() {
|
||||
system_clock::time_point LastCorpusReload = system_clock::now();
|
||||
if (Options.DoCrossOver)
|
||||
MD.SetCorpus(&Corpus);
|
||||
while (true) {
|
||||
auto Now = system_clock::now();
|
||||
if (duration_cast<seconds>(Now - LastCorpusReload).count() >=
|
||||
Options.ReloadIntervalSec) {
|
||||
RereadOutputCorpus(MaxInputLen);
|
||||
LastCorpusReload = system_clock::now();
|
||||
}
|
||||
if (TotalNumberOfRuns >= Options.MaxNumberOfRuns)
|
||||
break;
|
||||
if (TimedOut()) break;
|
||||
// Perform several mutations and runs.
|
||||
MutateAndTestOne();
|
||||
}
|
||||
|
||||
PrintStats("DONE ", "\n");
|
||||
MD.PrintRecommendedDictionary();
|
||||
}
|
||||
|
||||
void Fuzzer::MinimizeCrashLoop(const Unit &U) {
|
||||
if (U.size() <= 2) return;
|
||||
while (!TimedOut() && TotalNumberOfRuns < Options.MaxNumberOfRuns) {
|
||||
MD.StartMutationSequence();
|
||||
memcpy(CurrentUnitData, U.data(), U.size());
|
||||
for (int i = 0; i < Options.MutateDepth; i++) {
|
||||
size_t NewSize = MD.Mutate(CurrentUnitData, U.size(), MaxMutationLen);
|
||||
assert(NewSize > 0 && NewSize <= MaxMutationLen);
|
||||
RunOne(CurrentUnitData, NewSize);
|
||||
TryDetectingAMemoryLeak(CurrentUnitData, NewSize,
|
||||
/*DuringInitialCorpusExecution*/ false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fuzzer
|
||||
|
||||
extern "C" {
|
||||
|
||||
size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) {
|
||||
assert(fuzzer::F);
|
||||
return fuzzer::F->GetMD().DefaultMutate(Data, Size, MaxSize);
|
||||
}
|
||||
} // extern "C"
|
||||
@@ -1,21 +0,0 @@
|
||||
//===- FuzzerMain.cpp - main() function and flags -------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// main() and flags.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "FuzzerDefs.h"
|
||||
|
||||
extern "C" {
|
||||
// This function should be defined by the user.
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
|
||||
} // extern "C"
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
return fuzzer::FuzzerDriver(&argc, &argv, LLVMFuzzerTestOneInput);
|
||||
}
|
||||
@@ -1,261 +0,0 @@
|
||||
//===- FuzzerMerge.cpp - merging corpora ----------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Merging corpora.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "FuzzerInternal.h"
|
||||
#include "FuzzerIO.h"
|
||||
#include "FuzzerMerge.h"
|
||||
#include "FuzzerTracePC.h"
|
||||
#include "FuzzerUtil.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <iterator>
|
||||
#include <sstream>
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
bool Merger::Parse(const std::string &Str, bool ParseCoverage) {
|
||||
std::istringstream SS(Str);
|
||||
return Parse(SS, ParseCoverage);
|
||||
}
|
||||
|
||||
void Merger::ParseOrExit(std::istream &IS, bool ParseCoverage) {
|
||||
if (!Parse(IS, ParseCoverage)) {
|
||||
Printf("MERGE: failed to parse the control file (unexpected error)\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// The control file example:
|
||||
//
|
||||
// 3 # The number of inputs
|
||||
// 1 # The number of inputs in the first corpus, <= the previous number
|
||||
// file0
|
||||
// file1
|
||||
// file2 # One file name per line.
|
||||
// STARTED 0 123 # FileID, file size
|
||||
// DONE 0 1 4 6 8 # FileID COV1 COV2 ...
|
||||
// STARTED 1 456 # If DONE is missing, the input crashed while processing.
|
||||
// STARTED 2 567
|
||||
// DONE 2 8 9
|
||||
bool Merger::Parse(std::istream &IS, bool ParseCoverage) {
|
||||
LastFailure.clear();
|
||||
std::string Line;
|
||||
|
||||
// Parse NumFiles.
|
||||
if (!std::getline(IS, Line, '\n')) return false;
|
||||
std::istringstream L1(Line);
|
||||
size_t NumFiles = 0;
|
||||
L1 >> NumFiles;
|
||||
if (NumFiles == 0 || NumFiles > 10000000) return false;
|
||||
|
||||
// Parse NumFilesInFirstCorpus.
|
||||
if (!std::getline(IS, Line, '\n')) return false;
|
||||
std::istringstream L2(Line);
|
||||
NumFilesInFirstCorpus = NumFiles + 1;
|
||||
L2 >> NumFilesInFirstCorpus;
|
||||
if (NumFilesInFirstCorpus > NumFiles) return false;
|
||||
|
||||
// Parse file names.
|
||||
Files.resize(NumFiles);
|
||||
for (size_t i = 0; i < NumFiles; i++)
|
||||
if (!std::getline(IS, Files[i].Name, '\n'))
|
||||
return false;
|
||||
|
||||
// Parse STARTED and DONE lines.
|
||||
size_t ExpectedStartMarker = 0;
|
||||
const size_t kInvalidStartMarker = -1;
|
||||
size_t LastSeenStartMarker = kInvalidStartMarker;
|
||||
while (std::getline(IS, Line, '\n')) {
|
||||
std::istringstream ISS1(Line);
|
||||
std::string Marker;
|
||||
size_t N;
|
||||
ISS1 >> Marker;
|
||||
ISS1 >> N;
|
||||
if (Marker == "STARTED") {
|
||||
// STARTED FILE_ID FILE_SIZE
|
||||
if (ExpectedStartMarker != N)
|
||||
return false;
|
||||
ISS1 >> Files[ExpectedStartMarker].Size;
|
||||
LastSeenStartMarker = ExpectedStartMarker;
|
||||
assert(ExpectedStartMarker < Files.size());
|
||||
ExpectedStartMarker++;
|
||||
} else if (Marker == "DONE") {
|
||||
// DONE FILE_SIZE COV1 COV2 COV3 ...
|
||||
size_t CurrentFileIdx = N;
|
||||
if (CurrentFileIdx != LastSeenStartMarker)
|
||||
return false;
|
||||
LastSeenStartMarker = kInvalidStartMarker;
|
||||
if (ParseCoverage) {
|
||||
auto &V = Files[CurrentFileIdx].Features;
|
||||
V.clear();
|
||||
while (ISS1 >> std::hex >> N)
|
||||
V.push_back(N);
|
||||
std::sort(V.begin(), V.end());
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (LastSeenStartMarker != kInvalidStartMarker)
|
||||
LastFailure = Files[LastSeenStartMarker].Name;
|
||||
|
||||
FirstNotProcessedFile = ExpectedStartMarker;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Decides which files need to be merged (add thost to NewFiles).
|
||||
// Returns the number of new features added.
|
||||
size_t Merger::Merge(std::vector<std::string> *NewFiles) {
|
||||
NewFiles->clear();
|
||||
assert(NumFilesInFirstCorpus <= Files.size());
|
||||
std::set<uint32_t> AllFeatures;
|
||||
|
||||
// What features are in the initial corpus?
|
||||
for (size_t i = 0; i < NumFilesInFirstCorpus; i++) {
|
||||
auto &Cur = Files[i].Features;
|
||||
AllFeatures.insert(Cur.begin(), Cur.end());
|
||||
}
|
||||
size_t InitialNumFeatures = AllFeatures.size();
|
||||
|
||||
// Remove all features that we already know from all other inputs.
|
||||
for (size_t i = NumFilesInFirstCorpus; i < Files.size(); i++) {
|
||||
auto &Cur = Files[i].Features;
|
||||
std::vector<uint32_t> Tmp;
|
||||
std::set_difference(Cur.begin(), Cur.end(), AllFeatures.begin(),
|
||||
AllFeatures.end(), std::inserter(Tmp, Tmp.begin()));
|
||||
Cur.swap(Tmp);
|
||||
}
|
||||
|
||||
// Sort. Give preference to
|
||||
// * smaller files
|
||||
// * files with more features.
|
||||
std::sort(Files.begin() + NumFilesInFirstCorpus, Files.end(),
|
||||
[&](const MergeFileInfo &a, const MergeFileInfo &b) -> bool {
|
||||
if (a.Size != b.Size)
|
||||
return a.Size < b.Size;
|
||||
return a.Features.size() > b.Features.size();
|
||||
});
|
||||
|
||||
// One greedy pass: add the file's features to AllFeatures.
|
||||
// If new features were added, add this file to NewFiles.
|
||||
for (size_t i = NumFilesInFirstCorpus; i < Files.size(); i++) {
|
||||
auto &Cur = Files[i].Features;
|
||||
// Printf("%s -> sz %zd ft %zd\n", Files[i].Name.c_str(),
|
||||
// Files[i].Size, Cur.size());
|
||||
size_t OldSize = AllFeatures.size();
|
||||
AllFeatures.insert(Cur.begin(), Cur.end());
|
||||
if (AllFeatures.size() > OldSize)
|
||||
NewFiles->push_back(Files[i].Name);
|
||||
}
|
||||
return AllFeatures.size() - InitialNumFeatures;
|
||||
}
|
||||
|
||||
// Inner process. May crash if the target crashes.
|
||||
void Fuzzer::CrashResistantMergeInternalStep(const std::string &CFPath) {
|
||||
Printf("MERGE-INNER: using the control file '%s'\n", CFPath.c_str());
|
||||
Merger M;
|
||||
std::ifstream IF(CFPath);
|
||||
M.ParseOrExit(IF, false);
|
||||
IF.close();
|
||||
if (!M.LastFailure.empty())
|
||||
Printf("MERGE-INNER: '%s' caused a failure at the previous merge step\n",
|
||||
M.LastFailure.c_str());
|
||||
|
||||
Printf("MERGE-INNER: %zd total files;"
|
||||
" %zd processed earlier; will process %zd files now\n",
|
||||
M.Files.size(), M.FirstNotProcessedFile,
|
||||
M.Files.size() - M.FirstNotProcessedFile);
|
||||
|
||||
std::ofstream OF(CFPath, std::ofstream::out | std::ofstream::app);
|
||||
for (size_t i = M.FirstNotProcessedFile; i < M.Files.size(); i++) {
|
||||
auto U = FileToVector(M.Files[i].Name);
|
||||
if (U.size() > MaxInputLen) {
|
||||
U.resize(MaxInputLen);
|
||||
U.shrink_to_fit();
|
||||
}
|
||||
std::ostringstream StartedLine;
|
||||
// Write the pre-run marker.
|
||||
OF << "STARTED " << std::dec << i << " " << U.size() << "\n";
|
||||
OF.flush(); // Flush is important since ExecuteCommand may crash.
|
||||
// Run.
|
||||
TPC.ResetMaps();
|
||||
ExecuteCallback(U.data(), U.size());
|
||||
// Collect coverage.
|
||||
std::set<size_t> Features;
|
||||
TPC.CollectFeatures([&](size_t Feature) -> bool {
|
||||
Features.insert(Feature);
|
||||
return true;
|
||||
});
|
||||
// Show stats.
|
||||
TotalNumberOfRuns++;
|
||||
if (!(TotalNumberOfRuns & (TotalNumberOfRuns - 1)))
|
||||
PrintStats("pulse ");
|
||||
// Write the post-run marker and the coverage.
|
||||
OF << "DONE " << i;
|
||||
for (size_t F : Features)
|
||||
OF << " " << std::hex << F;
|
||||
OF << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Outer process. Does not call the target code and thus sohuld not fail.
|
||||
void Fuzzer::CrashResistantMerge(const std::vector<std::string> &Args,
|
||||
const std::vector<std::string> &Corpora) {
|
||||
if (Corpora.size() <= 1) {
|
||||
Printf("Merge requires two or more corpus dirs\n");
|
||||
return;
|
||||
}
|
||||
std::vector<std::string> AllFiles;
|
||||
ListFilesInDirRecursive(Corpora[0], nullptr, &AllFiles, /*TopDir*/true);
|
||||
size_t NumFilesInFirstCorpus = AllFiles.size();
|
||||
for (size_t i = 1; i < Corpora.size(); i++)
|
||||
ListFilesInDirRecursive(Corpora[i], nullptr, &AllFiles, /*TopDir*/true);
|
||||
Printf("MERGE-OUTER: %zd files, %zd in the initial corpus\n",
|
||||
AllFiles.size(), NumFilesInFirstCorpus);
|
||||
std::string CFPath =
|
||||
"libFuzzerTemp." + std::to_string(GetPid()) + ".txt";
|
||||
// Write the control file.
|
||||
RemoveFile(CFPath);
|
||||
std::ofstream ControlFile(CFPath);
|
||||
ControlFile << AllFiles.size() << "\n";
|
||||
ControlFile << NumFilesInFirstCorpus << "\n";
|
||||
for (auto &Path: AllFiles)
|
||||
ControlFile << Path << "\n";
|
||||
ControlFile.close();
|
||||
|
||||
// Execute the inner process untill it passes.
|
||||
// Every inner process should execute at least one input.
|
||||
std::string BaseCmd = CloneArgsWithoutX(Args, "keep-all-flags");
|
||||
for (size_t i = 1; i <= AllFiles.size(); i++) {
|
||||
Printf("MERGE-OUTER: attempt %zd\n", i);
|
||||
auto ExitCode =
|
||||
ExecuteCommand(BaseCmd + " -merge_control_file=" + CFPath);
|
||||
if (!ExitCode) {
|
||||
Printf("MERGE-OUTER: succesfull in %zd attempt(s)\n", i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Read the control file and do the merge.
|
||||
Merger M;
|
||||
std::ifstream IF(CFPath);
|
||||
M.ParseOrExit(IF, true);
|
||||
IF.close();
|
||||
std::vector<std::string> NewFiles;
|
||||
size_t NumNewFeatures = M.Merge(&NewFiles);
|
||||
Printf("MERGE-OUTER: %zd new files with %zd new features added\n",
|
||||
NewFiles.size(), NumNewFeatures);
|
||||
for (auto &F: NewFiles)
|
||||
WriteToOutputCorpus(FileToVector(F));
|
||||
// We are done, delete the control file.
|
||||
RemoveFile(CFPath);
|
||||
}
|
||||
|
||||
} // namespace fuzzer
|
||||
@@ -1,70 +0,0 @@
|
||||
//===- FuzzerMerge.h - merging corpa ----------------------------*- C++ -* ===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Merging Corpora.
|
||||
//
|
||||
// The task:
|
||||
// Take the existing corpus (possibly empty) and merge new inputs into
|
||||
// it so that only inputs with new coverage ('features') are added.
|
||||
// The process should tolerate the crashes, OOMs, leaks, etc.
|
||||
//
|
||||
// Algorithm:
|
||||
// The outter process collects the set of files and writes their names
|
||||
// into a temporary "control" file, then repeatedly launches the inner
|
||||
// process until all inputs are processed.
|
||||
// The outer process does not actually execute the target code.
|
||||
//
|
||||
// The inner process reads the control file and sees a) list of all the inputs
|
||||
// and b) the last processed input. Then it starts processing the inputs one
|
||||
// by one. Before processing every input it writes one line to control file:
|
||||
// STARTED INPUT_ID INPUT_SIZE
|
||||
// After processing an input it write another line:
|
||||
// DONE INPUT_ID Feature1 Feature2 Feature3 ...
|
||||
// If a crash happens while processing an input the last line in the control
|
||||
// file will be "STARTED INPUT_ID" and so the next process will know
|
||||
// where to resume.
|
||||
//
|
||||
// Once all inputs are processed by the innner process(es) the outer process
|
||||
// reads the control files and does the merge based entirely on the contents
|
||||
// of control file.
|
||||
// It uses a single pass greedy algorithm choosing first the smallest inputs
|
||||
// within the same size the inputs that have more new features.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_FUZZER_MERGE_H
|
||||
#define LLVM_FUZZER_MERGE_H
|
||||
|
||||
#include "FuzzerDefs.h"
|
||||
|
||||
#include <istream>
|
||||
#include <set>
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
struct MergeFileInfo {
|
||||
std::string Name;
|
||||
size_t Size = 0;
|
||||
std::vector<uint32_t> Features;
|
||||
};
|
||||
|
||||
struct Merger {
|
||||
std::vector<MergeFileInfo> Files;
|
||||
size_t NumFilesInFirstCorpus = 0;
|
||||
size_t FirstNotProcessedFile = 0;
|
||||
std::string LastFailure;
|
||||
|
||||
bool Parse(std::istream &IS, bool ParseCoverage);
|
||||
bool Parse(const std::string &Str, bool ParseCoverage);
|
||||
void ParseOrExit(std::istream &IS, bool ParseCoverage);
|
||||
size_t Merge(std::vector<std::string> *NewFiles);
|
||||
};
|
||||
|
||||
} // namespace fuzzer
|
||||
|
||||
#endif // LLVM_FUZZER_MERGE_H
|
||||
@@ -1,527 +0,0 @@
|
||||
//===- FuzzerMutate.cpp - Mutate a test input -----------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Mutate a test input.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "FuzzerCorpus.h"
|
||||
#include "FuzzerDefs.h"
|
||||
#include "FuzzerExtFunctions.h"
|
||||
#include "FuzzerIO.h"
|
||||
#include "FuzzerMutate.h"
|
||||
#include "FuzzerOptions.h"
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
const size_t Dictionary::kMaxDictSize;
|
||||
|
||||
static void PrintASCII(const Word &W, const char *PrintAfter) {
|
||||
PrintASCII(W.data(), W.size(), PrintAfter);
|
||||
}
|
||||
|
||||
MutationDispatcher::MutationDispatcher(Random &Rand,
|
||||
const FuzzingOptions &Options)
|
||||
: Rand(Rand), Options(Options) {
|
||||
DefaultMutators.insert(
|
||||
DefaultMutators.begin(),
|
||||
{
|
||||
{&MutationDispatcher::Mutate_EraseBytes, "EraseBytes"},
|
||||
{&MutationDispatcher::Mutate_InsertByte, "InsertByte"},
|
||||
{&MutationDispatcher::Mutate_InsertRepeatedBytes,
|
||||
"InsertRepeatedBytes"},
|
||||
{&MutationDispatcher::Mutate_ChangeByte, "ChangeByte"},
|
||||
{&MutationDispatcher::Mutate_ChangeBit, "ChangeBit"},
|
||||
{&MutationDispatcher::Mutate_ShuffleBytes, "ShuffleBytes"},
|
||||
{&MutationDispatcher::Mutate_ChangeASCIIInteger, "ChangeASCIIInt"},
|
||||
{&MutationDispatcher::Mutate_ChangeBinaryInteger, "ChangeBinInt"},
|
||||
{&MutationDispatcher::Mutate_CopyPart, "CopyPart"},
|
||||
{&MutationDispatcher::Mutate_CrossOver, "CrossOver"},
|
||||
{&MutationDispatcher::Mutate_AddWordFromManualDictionary,
|
||||
"ManualDict"},
|
||||
{&MutationDispatcher::Mutate_AddWordFromTemporaryAutoDictionary,
|
||||
"TempAutoDict"},
|
||||
{&MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary,
|
||||
"PersAutoDict"},
|
||||
});
|
||||
if(Options.UseCmp)
|
||||
DefaultMutators.push_back(
|
||||
{&MutationDispatcher::Mutate_AddWordFromTORC, "CMP"});
|
||||
|
||||
if (EF->LLVMFuzzerCustomMutator)
|
||||
Mutators.push_back({&MutationDispatcher::Mutate_Custom, "Custom"});
|
||||
else
|
||||
Mutators = DefaultMutators;
|
||||
|
||||
if (EF->LLVMFuzzerCustomCrossOver)
|
||||
Mutators.push_back(
|
||||
{&MutationDispatcher::Mutate_CustomCrossOver, "CustomCrossOver"});
|
||||
}
|
||||
|
||||
static char RandCh(Random &Rand) {
|
||||
if (Rand.RandBool()) return Rand(256);
|
||||
const char *Special = "!*'();:@&=+$,/?%#[]012Az-`~.\xff\x00";
|
||||
return Special[Rand(sizeof(Special) - 1)];
|
||||
}
|
||||
|
||||
size_t MutationDispatcher::Mutate_Custom(uint8_t *Data, size_t Size,
|
||||
size_t MaxSize) {
|
||||
return EF->LLVMFuzzerCustomMutator(Data, Size, MaxSize, Rand.Rand());
|
||||
}
|
||||
|
||||
size_t MutationDispatcher::Mutate_CustomCrossOver(uint8_t *Data, size_t Size,
|
||||
size_t MaxSize) {
|
||||
if (!Corpus || Corpus->size() < 2 || Size == 0)
|
||||
return 0;
|
||||
size_t Idx = Rand(Corpus->size());
|
||||
const Unit &Other = (*Corpus)[Idx];
|
||||
if (Other.empty())
|
||||
return 0;
|
||||
MutateInPlaceHere.resize(MaxSize);
|
||||
auto &U = MutateInPlaceHere;
|
||||
size_t NewSize = EF->LLVMFuzzerCustomCrossOver(
|
||||
Data, Size, Other.data(), Other.size(), U.data(), U.size(), Rand.Rand());
|
||||
if (!NewSize)
|
||||
return 0;
|
||||
assert(NewSize <= MaxSize && "CustomCrossOver returned overisized unit");
|
||||
memcpy(Data, U.data(), NewSize);
|
||||
return NewSize;
|
||||
}
|
||||
|
||||
size_t MutationDispatcher::Mutate_ShuffleBytes(uint8_t *Data, size_t Size,
|
||||
size_t MaxSize) {
|
||||
if (Size > MaxSize) return 0;
|
||||
assert(Size);
|
||||
size_t ShuffleAmount =
|
||||
Rand(std::min(Size, (size_t)8)) + 1; // [1,8] and <= Size.
|
||||
size_t ShuffleStart = Rand(Size - ShuffleAmount);
|
||||
assert(ShuffleStart + ShuffleAmount <= Size);
|
||||
std::random_shuffle(Data + ShuffleStart, Data + ShuffleStart + ShuffleAmount,
|
||||
Rand);
|
||||
return Size;
|
||||
}
|
||||
|
||||
size_t MutationDispatcher::Mutate_EraseBytes(uint8_t *Data, size_t Size,
|
||||
size_t MaxSize) {
|
||||
assert(Size);
|
||||
if (Size == 1) return 0;
|
||||
size_t N = Rand(Size / 2) + 1;
|
||||
assert(N < Size);
|
||||
size_t Idx = Rand(Size - N + 1);
|
||||
// Erase Data[Idx:Idx+N].
|
||||
memmove(Data + Idx, Data + Idx + N, Size - Idx - N);
|
||||
// Printf("Erase: %zd %zd => %zd; Idx %zd\n", N, Size, Size - N, Idx);
|
||||
return Size - N;
|
||||
}
|
||||
|
||||
size_t MutationDispatcher::Mutate_InsertByte(uint8_t *Data, size_t Size,
|
||||
size_t MaxSize) {
|
||||
if (Size >= MaxSize) return 0;
|
||||
size_t Idx = Rand(Size + 1);
|
||||
// Insert new value at Data[Idx].
|
||||
memmove(Data + Idx + 1, Data + Idx, Size - Idx);
|
||||
Data[Idx] = RandCh(Rand);
|
||||
return Size + 1;
|
||||
}
|
||||
|
||||
size_t MutationDispatcher::Mutate_InsertRepeatedBytes(uint8_t *Data,
|
||||
size_t Size,
|
||||
size_t MaxSize) {
|
||||
const size_t kMinBytesToInsert = 3;
|
||||
if (Size + kMinBytesToInsert >= MaxSize) return 0;
|
||||
size_t MaxBytesToInsert = std::min(MaxSize - Size, (size_t)128);
|
||||
size_t N = Rand(MaxBytesToInsert - kMinBytesToInsert + 1) + kMinBytesToInsert;
|
||||
assert(Size + N <= MaxSize && N);
|
||||
size_t Idx = Rand(Size + 1);
|
||||
// Insert new values at Data[Idx].
|
||||
memmove(Data + Idx + N, Data + Idx, Size - Idx);
|
||||
// Give preference to 0x00 and 0xff.
|
||||
uint8_t Byte = Rand.RandBool() ? Rand(256) : (Rand.RandBool() ? 0 : 255);
|
||||
for (size_t i = 0; i < N; i++)
|
||||
Data[Idx + i] = Byte;
|
||||
return Size + N;
|
||||
}
|
||||
|
||||
size_t MutationDispatcher::Mutate_ChangeByte(uint8_t *Data, size_t Size,
|
||||
size_t MaxSize) {
|
||||
if (Size > MaxSize) return 0;
|
||||
size_t Idx = Rand(Size);
|
||||
Data[Idx] = RandCh(Rand);
|
||||
return Size;
|
||||
}
|
||||
|
||||
size_t MutationDispatcher::Mutate_ChangeBit(uint8_t *Data, size_t Size,
|
||||
size_t MaxSize) {
|
||||
if (Size > MaxSize) return 0;
|
||||
size_t Idx = Rand(Size);
|
||||
Data[Idx] ^= 1 << Rand(8);
|
||||
return Size;
|
||||
}
|
||||
|
||||
size_t MutationDispatcher::Mutate_AddWordFromManualDictionary(uint8_t *Data,
|
||||
size_t Size,
|
||||
size_t MaxSize) {
|
||||
return AddWordFromDictionary(ManualDictionary, Data, Size, MaxSize);
|
||||
}
|
||||
|
||||
size_t MutationDispatcher::Mutate_AddWordFromTemporaryAutoDictionary(
|
||||
uint8_t *Data, size_t Size, size_t MaxSize) {
|
||||
return AddWordFromDictionary(TempAutoDictionary, Data, Size, MaxSize);
|
||||
}
|
||||
|
||||
size_t MutationDispatcher::ApplyDictionaryEntry(uint8_t *Data, size_t Size,
|
||||
size_t MaxSize,
|
||||
DictionaryEntry &DE) {
|
||||
const Word &W = DE.GetW();
|
||||
bool UsePositionHint = DE.HasPositionHint() &&
|
||||
DE.GetPositionHint() + W.size() < Size &&
|
||||
Rand.RandBool();
|
||||
if (Rand.RandBool()) { // Insert W.
|
||||
if (Size + W.size() > MaxSize) return 0;
|
||||
size_t Idx = UsePositionHint ? DE.GetPositionHint() : Rand(Size + 1);
|
||||
memmove(Data + Idx + W.size(), Data + Idx, Size - Idx);
|
||||
memcpy(Data + Idx, W.data(), W.size());
|
||||
Size += W.size();
|
||||
} else { // Overwrite some bytes with W.
|
||||
if (W.size() > Size) return 0;
|
||||
size_t Idx = UsePositionHint ? DE.GetPositionHint() : Rand(Size - W.size());
|
||||
memcpy(Data + Idx, W.data(), W.size());
|
||||
}
|
||||
return Size;
|
||||
}
|
||||
|
||||
// Somewhere in the past we have observed a comparison instructions
|
||||
// with arguments Arg1 Arg2. This function tries to guess a dictionary
|
||||
// entry that will satisfy that comparison.
|
||||
// It first tries to find one of the arguments (possibly swapped) in the
|
||||
// input and if it succeeds it creates a DE with a position hint.
|
||||
// Otherwise it creates a DE with one of the arguments w/o a position hint.
|
||||
template <class T>
|
||||
DictionaryEntry MutationDispatcher::MakeDictionaryEntryFromCMP(
|
||||
T Arg1, T Arg2, const uint8_t *Data, size_t Size) {
|
||||
ScopedDoingMyOwnMemmem scoped_doing_my_own_memmem;
|
||||
bool HandleFirst = Rand.RandBool();
|
||||
T ExistingBytes, DesiredBytes;
|
||||
Word W;
|
||||
const uint8_t *End = Data + Size;
|
||||
for (int Arg = 0; Arg < 2; Arg++) {
|
||||
ExistingBytes = HandleFirst ? Arg1 : Arg2;
|
||||
DesiredBytes = HandleFirst ? Arg2 : Arg1;
|
||||
DesiredBytes += Rand(-1, 1);
|
||||
if (Rand.RandBool()) ExistingBytes = Bswap(ExistingBytes);
|
||||
if (Rand.RandBool()) DesiredBytes = Bswap(DesiredBytes);
|
||||
HandleFirst = !HandleFirst;
|
||||
W.Set(reinterpret_cast<uint8_t*>(&DesiredBytes), sizeof(T));
|
||||
const size_t kMaxNumPositions = 8;
|
||||
size_t Positions[kMaxNumPositions];
|
||||
size_t NumPositions = 0;
|
||||
for (const uint8_t *Cur = Data;
|
||||
Cur < End && NumPositions < kMaxNumPositions; Cur++) {
|
||||
Cur = (uint8_t *)SearchMemory(Cur, End - Cur, &ExistingBytes, sizeof(T));
|
||||
if (!Cur) break;
|
||||
Positions[NumPositions++] = Cur - Data;
|
||||
}
|
||||
if (!NumPositions) break;
|
||||
return DictionaryEntry(W, Positions[Rand(NumPositions)]);
|
||||
}
|
||||
DictionaryEntry DE(W);
|
||||
return DE;
|
||||
}
|
||||
|
||||
size_t MutationDispatcher::Mutate_AddWordFromTORC(
|
||||
uint8_t *Data, size_t Size, size_t MaxSize) {
|
||||
Word W;
|
||||
DictionaryEntry DE;
|
||||
if (Rand.RandBool()) {
|
||||
auto X = TPC.TORC8.Get(Rand.Rand());
|
||||
DE = MakeDictionaryEntryFromCMP(X.A, X.B, Data, Size);
|
||||
} else {
|
||||
auto X = TPC.TORC4.Get(Rand.Rand());
|
||||
if ((X.A >> 16) == 0 && (X.B >> 16) == 0 && Rand.RandBool())
|
||||
DE = MakeDictionaryEntryFromCMP((uint16_t)X.A, (uint16_t)X.B, Data,
|
||||
Size);
|
||||
else
|
||||
DE = MakeDictionaryEntryFromCMP(X.A, X.B, Data, Size);
|
||||
}
|
||||
Size = ApplyDictionaryEntry(Data, Size, MaxSize, DE);
|
||||
if (!Size) return 0;
|
||||
DictionaryEntry &DERef =
|
||||
CmpDictionaryEntriesDeque[CmpDictionaryEntriesDequeIdx++ %
|
||||
kCmpDictionaryEntriesDequeSize];
|
||||
DERef = DE;
|
||||
CurrentDictionaryEntrySequence.push_back(&DERef);
|
||||
return Size;
|
||||
}
|
||||
|
||||
size_t MutationDispatcher::Mutate_AddWordFromPersistentAutoDictionary(
|
||||
uint8_t *Data, size_t Size, size_t MaxSize) {
|
||||
return AddWordFromDictionary(PersistentAutoDictionary, Data, Size, MaxSize);
|
||||
}
|
||||
|
||||
size_t MutationDispatcher::AddWordFromDictionary(Dictionary &D, uint8_t *Data,
|
||||
size_t Size, size_t MaxSize) {
|
||||
if (Size > MaxSize) return 0;
|
||||
if (D.empty()) return 0;
|
||||
DictionaryEntry &DE = D[Rand(D.size())];
|
||||
Size = ApplyDictionaryEntry(Data, Size, MaxSize, DE);
|
||||
if (!Size) return 0;
|
||||
DE.IncUseCount();
|
||||
CurrentDictionaryEntrySequence.push_back(&DE);
|
||||
return Size;
|
||||
}
|
||||
|
||||
// Overwrites part of To[0,ToSize) with a part of From[0,FromSize).
|
||||
// Returns ToSize.
|
||||
size_t MutationDispatcher::CopyPartOf(const uint8_t *From, size_t FromSize,
|
||||
uint8_t *To, size_t ToSize) {
|
||||
// Copy From[FromBeg, FromBeg + CopySize) into To[ToBeg, ToBeg + CopySize).
|
||||
size_t ToBeg = Rand(ToSize);
|
||||
size_t CopySize = Rand(ToSize - ToBeg) + 1;
|
||||
assert(ToBeg + CopySize <= ToSize);
|
||||
CopySize = std::min(CopySize, FromSize);
|
||||
size_t FromBeg = Rand(FromSize - CopySize + 1);
|
||||
assert(FromBeg + CopySize <= FromSize);
|
||||
memmove(To + ToBeg, From + FromBeg, CopySize);
|
||||
return ToSize;
|
||||
}
|
||||
|
||||
// Inserts part of From[0,ToSize) into To.
|
||||
// Returns new size of To on success or 0 on failure.
|
||||
size_t MutationDispatcher::InsertPartOf(const uint8_t *From, size_t FromSize,
|
||||
uint8_t *To, size_t ToSize,
|
||||
size_t MaxToSize) {
|
||||
if (ToSize >= MaxToSize) return 0;
|
||||
size_t AvailableSpace = MaxToSize - ToSize;
|
||||
size_t MaxCopySize = std::min(AvailableSpace, FromSize);
|
||||
size_t CopySize = Rand(MaxCopySize) + 1;
|
||||
size_t FromBeg = Rand(FromSize - CopySize + 1);
|
||||
assert(FromBeg + CopySize <= FromSize);
|
||||
size_t ToInsertPos = Rand(ToSize + 1);
|
||||
assert(ToInsertPos + CopySize <= MaxToSize);
|
||||
size_t TailSize = ToSize - ToInsertPos;
|
||||
if (To == From) {
|
||||
MutateInPlaceHere.resize(MaxToSize);
|
||||
memcpy(MutateInPlaceHere.data(), From + FromBeg, CopySize);
|
||||
memmove(To + ToInsertPos + CopySize, To + ToInsertPos, TailSize);
|
||||
memmove(To + ToInsertPos, MutateInPlaceHere.data(), CopySize);
|
||||
} else {
|
||||
memmove(To + ToInsertPos + CopySize, To + ToInsertPos, TailSize);
|
||||
memmove(To + ToInsertPos, From + FromBeg, CopySize);
|
||||
}
|
||||
return ToSize + CopySize;
|
||||
}
|
||||
|
||||
size_t MutationDispatcher::Mutate_CopyPart(uint8_t *Data, size_t Size,
|
||||
size_t MaxSize) {
|
||||
if (Size > MaxSize) return 0;
|
||||
if (Rand.RandBool())
|
||||
return CopyPartOf(Data, Size, Data, Size);
|
||||
else
|
||||
return InsertPartOf(Data, Size, Data, Size, MaxSize);
|
||||
}
|
||||
|
||||
size_t MutationDispatcher::Mutate_ChangeASCIIInteger(uint8_t *Data, size_t Size,
|
||||
size_t MaxSize) {
|
||||
if (Size > MaxSize) return 0;
|
||||
size_t B = Rand(Size);
|
||||
while (B < Size && !isdigit(Data[B])) B++;
|
||||
if (B == Size) return 0;
|
||||
size_t E = B;
|
||||
while (E < Size && isdigit(Data[E])) E++;
|
||||
assert(B < E);
|
||||
// now we have digits in [B, E).
|
||||
// strtol and friends don't accept non-zero-teminated data, parse it manually.
|
||||
uint64_t Val = Data[B] - '0';
|
||||
for (size_t i = B + 1; i < E; i++)
|
||||
Val = Val * 10 + Data[i] - '0';
|
||||
|
||||
// Mutate the integer value.
|
||||
switch(Rand(5)) {
|
||||
case 0: Val++; break;
|
||||
case 1: Val--; break;
|
||||
case 2: Val /= 2; break;
|
||||
case 3: Val *= 2; break;
|
||||
case 4: Val = Rand(Val * Val); break;
|
||||
default: assert(0);
|
||||
}
|
||||
// Just replace the bytes with the new ones, don't bother moving bytes.
|
||||
for (size_t i = B; i < E; i++) {
|
||||
size_t Idx = E + B - i - 1;
|
||||
assert(Idx >= B && Idx < E);
|
||||
Data[Idx] = (Val % 10) + '0';
|
||||
Val /= 10;
|
||||
}
|
||||
return Size;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
size_t ChangeBinaryInteger(uint8_t *Data, size_t Size, Random &Rand) {
|
||||
if (Size < sizeof(T)) return 0;
|
||||
size_t Off = Rand(Size - sizeof(T) + 1);
|
||||
assert(Off + sizeof(T) <= Size);
|
||||
T Val;
|
||||
if (Off < 64 && !Rand(4)) {
|
||||
Val = Size;
|
||||
if (Rand.RandBool())
|
||||
Val = Bswap(Val);
|
||||
} else {
|
||||
memcpy(&Val, Data + Off, sizeof(Val));
|
||||
T Add = Rand(21);
|
||||
Add -= 10;
|
||||
if (Rand.RandBool())
|
||||
Val = Bswap(T(Bswap(Val) + Add)); // Add assuming different endiannes.
|
||||
else
|
||||
Val = Val + Add; // Add assuming current endiannes.
|
||||
if (Add == 0 || Rand.RandBool()) // Maybe negate.
|
||||
Val = -Val;
|
||||
}
|
||||
memcpy(Data + Off, &Val, sizeof(Val));
|
||||
return Size;
|
||||
}
|
||||
|
||||
size_t MutationDispatcher::Mutate_ChangeBinaryInteger(uint8_t *Data,
|
||||
size_t Size,
|
||||
size_t MaxSize) {
|
||||
if (Size > MaxSize) return 0;
|
||||
switch (Rand(4)) {
|
||||
case 3: return ChangeBinaryInteger<uint64_t>(Data, Size, Rand);
|
||||
case 2: return ChangeBinaryInteger<uint32_t>(Data, Size, Rand);
|
||||
case 1: return ChangeBinaryInteger<uint16_t>(Data, Size, Rand);
|
||||
case 0: return ChangeBinaryInteger<uint8_t>(Data, Size, Rand);
|
||||
default: assert(0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t MutationDispatcher::Mutate_CrossOver(uint8_t *Data, size_t Size,
|
||||
size_t MaxSize) {
|
||||
if (Size > MaxSize) return 0;
|
||||
if (!Corpus || Corpus->size() < 2 || Size == 0) return 0;
|
||||
size_t Idx = Rand(Corpus->size());
|
||||
const Unit &O = (*Corpus)[Idx];
|
||||
if (O.empty()) return 0;
|
||||
MutateInPlaceHere.resize(MaxSize);
|
||||
auto &U = MutateInPlaceHere;
|
||||
size_t NewSize = 0;
|
||||
switch(Rand(3)) {
|
||||
case 0:
|
||||
NewSize = CrossOver(Data, Size, O.data(), O.size(), U.data(), U.size());
|
||||
break;
|
||||
case 1:
|
||||
NewSize = InsertPartOf(O.data(), O.size(), U.data(), U.size(), MaxSize);
|
||||
if (NewSize)
|
||||
break;
|
||||
// LLVM_FALLTHROUGH;
|
||||
case 2:
|
||||
NewSize = CopyPartOf(O.data(), O.size(), U.data(), U.size());
|
||||
break;
|
||||
default: assert(0);
|
||||
}
|
||||
assert(NewSize > 0 && "CrossOver returned empty unit");
|
||||
assert(NewSize <= MaxSize && "CrossOver returned overisized unit");
|
||||
memcpy(Data, U.data(), NewSize);
|
||||
return NewSize;
|
||||
}
|
||||
|
||||
void MutationDispatcher::StartMutationSequence() {
|
||||
CurrentMutatorSequence.clear();
|
||||
CurrentDictionaryEntrySequence.clear();
|
||||
}
|
||||
|
||||
// Copy successful dictionary entries to PersistentAutoDictionary.
|
||||
void MutationDispatcher::RecordSuccessfulMutationSequence() {
|
||||
for (auto DE : CurrentDictionaryEntrySequence) {
|
||||
// PersistentAutoDictionary.AddWithSuccessCountOne(DE);
|
||||
DE->IncSuccessCount();
|
||||
// Linear search is fine here as this happens seldom.
|
||||
if (!PersistentAutoDictionary.ContainsWord(DE->GetW()))
|
||||
PersistentAutoDictionary.push_back({DE->GetW(), 1});
|
||||
}
|
||||
}
|
||||
|
||||
void MutationDispatcher::PrintRecommendedDictionary() {
|
||||
std::vector<DictionaryEntry> V;
|
||||
for (auto &DE : PersistentAutoDictionary)
|
||||
if (!ManualDictionary.ContainsWord(DE.GetW()))
|
||||
V.push_back(DE);
|
||||
if (V.empty()) return;
|
||||
Printf("###### Recommended dictionary. ######\n");
|
||||
for (auto &DE: V) {
|
||||
Printf("\"");
|
||||
PrintASCII(DE.GetW(), "\"");
|
||||
Printf(" # Uses: %zd\n", DE.GetUseCount());
|
||||
}
|
||||
Printf("###### End of recommended dictionary. ######\n");
|
||||
}
|
||||
|
||||
void MutationDispatcher::PrintMutationSequence() {
|
||||
Printf("MS: %zd ", CurrentMutatorSequence.size());
|
||||
for (auto M : CurrentMutatorSequence)
|
||||
Printf("%s-", M.Name);
|
||||
if (!CurrentDictionaryEntrySequence.empty()) {
|
||||
Printf(" DE: ");
|
||||
for (auto DE : CurrentDictionaryEntrySequence) {
|
||||
Printf("\"");
|
||||
PrintASCII(DE->GetW(), "\"-");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t MutationDispatcher::Mutate(uint8_t *Data, size_t Size, size_t MaxSize) {
|
||||
return MutateImpl(Data, Size, MaxSize, Mutators);
|
||||
}
|
||||
|
||||
size_t MutationDispatcher::DefaultMutate(uint8_t *Data, size_t Size,
|
||||
size_t MaxSize) {
|
||||
return MutateImpl(Data, Size, MaxSize, DefaultMutators);
|
||||
}
|
||||
|
||||
// Mutates Data in place, returns new size.
|
||||
size_t MutationDispatcher::MutateImpl(uint8_t *Data, size_t Size,
|
||||
size_t MaxSize,
|
||||
const std::vector<Mutator> &Mutators) {
|
||||
assert(MaxSize > 0);
|
||||
if (Size == 0) {
|
||||
for (size_t i = 0; i < MaxSize; i++)
|
||||
Data[i] = RandCh(Rand);
|
||||
if (Options.OnlyASCII)
|
||||
ToASCII(Data, MaxSize);
|
||||
return MaxSize;
|
||||
}
|
||||
assert(Size > 0);
|
||||
// Some mutations may fail (e.g. can't insert more bytes if Size == MaxSize),
|
||||
// in which case they will return 0.
|
||||
// Try several times before returning un-mutated data.
|
||||
for (int Iter = 0; Iter < 100; Iter++) {
|
||||
auto M = Mutators[Rand(Mutators.size())];
|
||||
size_t NewSize = (this->*(M.Fn))(Data, Size, MaxSize);
|
||||
if (NewSize && NewSize <= MaxSize) {
|
||||
if (Options.OnlyASCII)
|
||||
ToASCII(Data, NewSize);
|
||||
CurrentMutatorSequence.push_back(M);
|
||||
return NewSize;
|
||||
}
|
||||
}
|
||||
return std::min(Size, MaxSize);
|
||||
}
|
||||
|
||||
void MutationDispatcher::AddWordToManualDictionary(const Word &W) {
|
||||
ManualDictionary.push_back(
|
||||
{W, std::numeric_limits<size_t>::max()});
|
||||
}
|
||||
|
||||
void MutationDispatcher::AddWordToAutoDictionary(DictionaryEntry DE) {
|
||||
static const size_t kMaxAutoDictSize = 1 << 14;
|
||||
if (TempAutoDictionary.size() >= kMaxAutoDictSize) return;
|
||||
TempAutoDictionary.push_back(DE);
|
||||
}
|
||||
|
||||
void MutationDispatcher::ClearAutoDictionary() {
|
||||
TempAutoDictionary.clear();
|
||||
}
|
||||
|
||||
} // namespace fuzzer
|
||||
@@ -1,145 +0,0 @@
|
||||
//===- FuzzerMutate.h - Internal header for the Fuzzer ----------*- C++ -* ===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// fuzzer::MutationDispatcher
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_FUZZER_MUTATE_H
|
||||
#define LLVM_FUZZER_MUTATE_H
|
||||
|
||||
#include "FuzzerDefs.h"
|
||||
#include "FuzzerDictionary.h"
|
||||
#include "FuzzerRandom.h"
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
class MutationDispatcher {
|
||||
public:
|
||||
MutationDispatcher(Random &Rand, const FuzzingOptions &Options);
|
||||
~MutationDispatcher() {}
|
||||
/// Indicate that we are about to start a new sequence of mutations.
|
||||
void StartMutationSequence();
|
||||
/// Print the current sequence of mutations.
|
||||
void PrintMutationSequence();
|
||||
/// Indicate that the current sequence of mutations was successfull.
|
||||
void RecordSuccessfulMutationSequence();
|
||||
/// Mutates data by invoking user-provided mutator.
|
||||
size_t Mutate_Custom(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||
/// Mutates data by invoking user-provided crossover.
|
||||
size_t Mutate_CustomCrossOver(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||
/// Mutates data by shuffling bytes.
|
||||
size_t Mutate_ShuffleBytes(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||
/// Mutates data by erasing bytes.
|
||||
size_t Mutate_EraseBytes(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||
/// Mutates data by inserting a byte.
|
||||
size_t Mutate_InsertByte(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||
/// Mutates data by inserting several repeated bytes.
|
||||
size_t Mutate_InsertRepeatedBytes(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||
/// Mutates data by chanding one byte.
|
||||
size_t Mutate_ChangeByte(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||
/// Mutates data by chanding one bit.
|
||||
size_t Mutate_ChangeBit(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||
/// Mutates data by copying/inserting a part of data into a different place.
|
||||
size_t Mutate_CopyPart(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||
|
||||
/// Mutates data by adding a word from the manual dictionary.
|
||||
size_t Mutate_AddWordFromManualDictionary(uint8_t *Data, size_t Size,
|
||||
size_t MaxSize);
|
||||
|
||||
/// Mutates data by adding a word from the temporary automatic dictionary.
|
||||
size_t Mutate_AddWordFromTemporaryAutoDictionary(uint8_t *Data, size_t Size,
|
||||
size_t MaxSize);
|
||||
|
||||
/// Mutates data by adding a word from the TORC.
|
||||
size_t Mutate_AddWordFromTORC(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||
|
||||
/// Mutates data by adding a word from the persistent automatic dictionary.
|
||||
size_t Mutate_AddWordFromPersistentAutoDictionary(uint8_t *Data, size_t Size,
|
||||
size_t MaxSize);
|
||||
|
||||
/// Tries to find an ASCII integer in Data, changes it to another ASCII int.
|
||||
size_t Mutate_ChangeASCIIInteger(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||
/// Change a 1-, 2-, 4-, or 8-byte integer in interesting ways.
|
||||
size_t Mutate_ChangeBinaryInteger(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||
|
||||
/// CrossOver Data with some other element of the corpus.
|
||||
size_t Mutate_CrossOver(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||
|
||||
/// Applies one of the configured mutations.
|
||||
/// Returns the new size of data which could be up to MaxSize.
|
||||
size_t Mutate(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||
/// Applies one of the default mutations. Provided as a service
|
||||
/// to mutation authors.
|
||||
size_t DefaultMutate(uint8_t *Data, size_t Size, size_t MaxSize);
|
||||
|
||||
/// Creates a cross-over of two pieces of Data, returns its size.
|
||||
size_t CrossOver(const uint8_t *Data1, size_t Size1, const uint8_t *Data2,
|
||||
size_t Size2, uint8_t *Out, size_t MaxOutSize);
|
||||
|
||||
void AddWordToManualDictionary(const Word &W);
|
||||
|
||||
void AddWordToAutoDictionary(DictionaryEntry DE);
|
||||
void ClearAutoDictionary();
|
||||
void PrintRecommendedDictionary();
|
||||
|
||||
void SetCorpus(const InputCorpus *Corpus) { this->Corpus = Corpus; }
|
||||
|
||||
Random &GetRand() { return Rand; }
|
||||
|
||||
private:
|
||||
|
||||
struct Mutator {
|
||||
size_t (MutationDispatcher::*Fn)(uint8_t *Data, size_t Size, size_t Max);
|
||||
const char *Name;
|
||||
};
|
||||
|
||||
size_t AddWordFromDictionary(Dictionary &D, uint8_t *Data, size_t Size,
|
||||
size_t MaxSize);
|
||||
size_t MutateImpl(uint8_t *Data, size_t Size, size_t MaxSize,
|
||||
const std::vector<Mutator> &Mutators);
|
||||
|
||||
size_t InsertPartOf(const uint8_t *From, size_t FromSize, uint8_t *To,
|
||||
size_t ToSize, size_t MaxToSize);
|
||||
size_t CopyPartOf(const uint8_t *From, size_t FromSize, uint8_t *To,
|
||||
size_t ToSize);
|
||||
size_t ApplyDictionaryEntry(uint8_t *Data, size_t Size, size_t MaxSize,
|
||||
DictionaryEntry &DE);
|
||||
|
||||
template <class T>
|
||||
DictionaryEntry MakeDictionaryEntryFromCMP(T Arg1, T Arg2,
|
||||
const uint8_t *Data, size_t Size);
|
||||
|
||||
Random &Rand;
|
||||
const FuzzingOptions &Options;
|
||||
|
||||
// Dictionary provided by the user via -dict=DICT_FILE.
|
||||
Dictionary ManualDictionary;
|
||||
// Temporary dictionary modified by the fuzzer itself,
|
||||
// recreated periodically.
|
||||
Dictionary TempAutoDictionary;
|
||||
// Persistent dictionary modified by the fuzzer, consists of
|
||||
// entries that led to successfull discoveries in the past mutations.
|
||||
Dictionary PersistentAutoDictionary;
|
||||
|
||||
std::vector<Mutator> CurrentMutatorSequence;
|
||||
std::vector<DictionaryEntry *> CurrentDictionaryEntrySequence;
|
||||
|
||||
static const size_t kCmpDictionaryEntriesDequeSize = 16;
|
||||
DictionaryEntry CmpDictionaryEntriesDeque[kCmpDictionaryEntriesDequeSize];
|
||||
size_t CmpDictionaryEntriesDequeIdx = 0;
|
||||
|
||||
const InputCorpus *Corpus = nullptr;
|
||||
std::vector<uint8_t> MutateInPlaceHere;
|
||||
|
||||
std::vector<Mutator> Mutators;
|
||||
std::vector<Mutator> DefaultMutators;
|
||||
};
|
||||
|
||||
} // namespace fuzzer
|
||||
|
||||
#endif // LLVM_FUZZER_MUTATE_H
|
||||
@@ -1,68 +0,0 @@
|
||||
//===- FuzzerOptions.h - Internal header for the Fuzzer ---------*- C++ -* ===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// fuzzer::FuzzingOptions
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_FUZZER_OPTIONS_H
|
||||
#define LLVM_FUZZER_OPTIONS_H
|
||||
|
||||
#include "FuzzerDefs.h"
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
struct FuzzingOptions {
|
||||
int Verbosity = 1;
|
||||
size_t MaxLen = 0;
|
||||
int UnitTimeoutSec = 300;
|
||||
int TimeoutExitCode = 77;
|
||||
int ErrorExitCode = 77;
|
||||
int MaxTotalTimeSec = 0;
|
||||
int RssLimitMb = 0;
|
||||
bool DoCrossOver = true;
|
||||
int MutateDepth = 5;
|
||||
bool UseCounters = false;
|
||||
bool UseIndirCalls = true;
|
||||
bool UseMemcmp = true;
|
||||
bool UseMemmem = true;
|
||||
bool UseCmp = false;
|
||||
bool UseValueProfile = false;
|
||||
bool Shrink = false;
|
||||
int ReloadIntervalSec = 1;
|
||||
bool ShuffleAtStartUp = true;
|
||||
bool PreferSmall = true;
|
||||
size_t MaxNumberOfRuns = -1L;
|
||||
int ReportSlowUnits = 10;
|
||||
bool OnlyASCII = false;
|
||||
std::string OutputCorpus;
|
||||
std::string ArtifactPrefix = "./";
|
||||
std::string ExactArtifactPath;
|
||||
std::string ExitOnSrcPos;
|
||||
std::string ExitOnItem;
|
||||
bool SaveArtifacts = true;
|
||||
bool PrintNEW = true; // Print a status line when new units are found;
|
||||
bool OutputCSV = false;
|
||||
bool PrintNewCovPcs = false;
|
||||
bool PrintFinalStats = false;
|
||||
bool PrintCorpusStats = false;
|
||||
bool PrintCoverage = false;
|
||||
bool DumpCoverage = false;
|
||||
bool DetectLeaks = true;
|
||||
int TraceMalloc = 0;
|
||||
bool HandleAbrt = false;
|
||||
bool HandleBus = false;
|
||||
bool HandleFpe = false;
|
||||
bool HandleIll = false;
|
||||
bool HandleInt = false;
|
||||
bool HandleSegv = false;
|
||||
bool HandleTerm = false;
|
||||
};
|
||||
|
||||
} // namespace fuzzer
|
||||
|
||||
#endif // LLVM_FUZZER_OPTIONS_H
|
||||
@@ -1,36 +0,0 @@
|
||||
//===- FuzzerRandom.h - Internal header for the Fuzzer ----------*- C++ -* ===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// fuzzer::Random
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_FUZZER_RANDOM_H
|
||||
#define LLVM_FUZZER_RANDOM_H
|
||||
|
||||
#include <random>
|
||||
|
||||
namespace fuzzer {
|
||||
class Random {
|
||||
public:
|
||||
Random(unsigned int seed) : R(seed) {}
|
||||
size_t Rand() { return R(); }
|
||||
size_t RandBool() { return Rand() % 2; }
|
||||
size_t operator()(size_t n) { return n ? Rand() % n : 0; }
|
||||
intptr_t operator()(intptr_t From, intptr_t To) {
|
||||
assert(From < To);
|
||||
intptr_t RangeSize = To - From + 1;
|
||||
return operator()(RangeSize) + From;
|
||||
}
|
||||
std::mt19937 &Get_mt19937() { return R; }
|
||||
private:
|
||||
std::mt19937 R;
|
||||
};
|
||||
|
||||
} // namespace fuzzer
|
||||
|
||||
#endif // LLVM_FUZZER_RANDOM_H
|
||||
@@ -1,222 +0,0 @@
|
||||
//===- FuzzerSHA1.h - Private copy of the SHA1 implementation ---*- C++ -* ===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// This code is taken from public domain
|
||||
// (http://oauth.googlecode.com/svn/code/c/liboauth/src/sha1.c)
|
||||
// and modified by adding anonymous namespace, adding an interface
|
||||
// function fuzzer::ComputeSHA1() and removing unnecessary code.
|
||||
//
|
||||
// lib/Fuzzer can not use SHA1 implementation from openssl because
|
||||
// openssl may not be available and because we may be fuzzing openssl itself.
|
||||
// For the same reason we do not want to depend on SHA1 from LLVM tree.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "FuzzerSHA1.h"
|
||||
#include "FuzzerDefs.h"
|
||||
|
||||
/* This code is public-domain - it is based on libcrypt
|
||||
* placed in the public domain by Wei Dai and other contributors.
|
||||
*/
|
||||
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace { // Added for LibFuzzer
|
||||
|
||||
#ifdef __BIG_ENDIAN__
|
||||
# define SHA_BIG_ENDIAN
|
||||
#elif defined __LITTLE_ENDIAN__
|
||||
/* override */
|
||||
#elif defined __BYTE_ORDER
|
||||
# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
# define SHA_BIG_ENDIAN
|
||||
# endif
|
||||
#else // ! defined __LITTLE_ENDIAN__
|
||||
# include <endian.h> // machine/endian.h
|
||||
# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||
# define SHA_BIG_ENDIAN
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
/* header */
|
||||
|
||||
#define HASH_LENGTH 20
|
||||
#define BLOCK_LENGTH 64
|
||||
|
||||
typedef struct sha1nfo {
|
||||
uint32_t buffer[BLOCK_LENGTH/4];
|
||||
uint32_t state[HASH_LENGTH/4];
|
||||
uint32_t byteCount;
|
||||
uint8_t bufferOffset;
|
||||
uint8_t keyBuffer[BLOCK_LENGTH];
|
||||
uint8_t innerHash[HASH_LENGTH];
|
||||
} sha1nfo;
|
||||
|
||||
/* public API - prototypes - TODO: doxygen*/
|
||||
|
||||
/**
|
||||
*/
|
||||
void sha1_init(sha1nfo *s);
|
||||
/**
|
||||
*/
|
||||
void sha1_writebyte(sha1nfo *s, uint8_t data);
|
||||
/**
|
||||
*/
|
||||
void sha1_write(sha1nfo *s, const char *data, size_t len);
|
||||
/**
|
||||
*/
|
||||
uint8_t* sha1_result(sha1nfo *s);
|
||||
|
||||
|
||||
/* code */
|
||||
#define SHA1_K0 0x5a827999
|
||||
#define SHA1_K20 0x6ed9eba1
|
||||
#define SHA1_K40 0x8f1bbcdc
|
||||
#define SHA1_K60 0xca62c1d6
|
||||
|
||||
void sha1_init(sha1nfo *s) {
|
||||
s->state[0] = 0x67452301;
|
||||
s->state[1] = 0xefcdab89;
|
||||
s->state[2] = 0x98badcfe;
|
||||
s->state[3] = 0x10325476;
|
||||
s->state[4] = 0xc3d2e1f0;
|
||||
s->byteCount = 0;
|
||||
s->bufferOffset = 0;
|
||||
}
|
||||
|
||||
uint32_t sha1_rol32(uint32_t number, uint8_t bits) {
|
||||
return ((number << bits) | (number >> (32-bits)));
|
||||
}
|
||||
|
||||
void sha1_hashBlock(sha1nfo *s) {
|
||||
uint8_t i;
|
||||
uint32_t a,b,c,d,e,t;
|
||||
|
||||
a=s->state[0];
|
||||
b=s->state[1];
|
||||
c=s->state[2];
|
||||
d=s->state[3];
|
||||
e=s->state[4];
|
||||
for (i=0; i<80; i++) {
|
||||
if (i>=16) {
|
||||
t = s->buffer[(i+13)&15] ^ s->buffer[(i+8)&15] ^ s->buffer[(i+2)&15] ^ s->buffer[i&15];
|
||||
s->buffer[i&15] = sha1_rol32(t,1);
|
||||
}
|
||||
if (i<20) {
|
||||
t = (d ^ (b & (c ^ d))) + SHA1_K0;
|
||||
} else if (i<40) {
|
||||
t = (b ^ c ^ d) + SHA1_K20;
|
||||
} else if (i<60) {
|
||||
t = ((b & c) | (d & (b | c))) + SHA1_K40;
|
||||
} else {
|
||||
t = (b ^ c ^ d) + SHA1_K60;
|
||||
}
|
||||
t+=sha1_rol32(a,5) + e + s->buffer[i&15];
|
||||
e=d;
|
||||
d=c;
|
||||
c=sha1_rol32(b,30);
|
||||
b=a;
|
||||
a=t;
|
||||
}
|
||||
s->state[0] += a;
|
||||
s->state[1] += b;
|
||||
s->state[2] += c;
|
||||
s->state[3] += d;
|
||||
s->state[4] += e;
|
||||
}
|
||||
|
||||
void sha1_addUncounted(sha1nfo *s, uint8_t data) {
|
||||
uint8_t * const b = (uint8_t*) s->buffer;
|
||||
#ifdef SHA_BIG_ENDIAN
|
||||
b[s->bufferOffset] = data;
|
||||
#else
|
||||
b[s->bufferOffset ^ 3] = data;
|
||||
#endif
|
||||
s->bufferOffset++;
|
||||
if (s->bufferOffset == BLOCK_LENGTH) {
|
||||
sha1_hashBlock(s);
|
||||
s->bufferOffset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void sha1_writebyte(sha1nfo *s, uint8_t data) {
|
||||
++s->byteCount;
|
||||
sha1_addUncounted(s, data);
|
||||
}
|
||||
|
||||
void sha1_write(sha1nfo *s, const char *data, size_t len) {
|
||||
for (;len--;) sha1_writebyte(s, (uint8_t) *data++);
|
||||
}
|
||||
|
||||
void sha1_pad(sha1nfo *s) {
|
||||
// Implement SHA-1 padding (fips180-2 §5.1.1)
|
||||
|
||||
// Pad with 0x80 followed by 0x00 until the end of the block
|
||||
sha1_addUncounted(s, 0x80);
|
||||
while (s->bufferOffset != 56) sha1_addUncounted(s, 0x00);
|
||||
|
||||
// Append length in the last 8 bytes
|
||||
sha1_addUncounted(s, 0); // We're only using 32 bit lengths
|
||||
sha1_addUncounted(s, 0); // But SHA-1 supports 64 bit lengths
|
||||
sha1_addUncounted(s, 0); // So zero pad the top bits
|
||||
sha1_addUncounted(s, s->byteCount >> 29); // Shifting to multiply by 8
|
||||
sha1_addUncounted(s, s->byteCount >> 21); // as SHA-1 supports bitstreams as well as
|
||||
sha1_addUncounted(s, s->byteCount >> 13); // byte.
|
||||
sha1_addUncounted(s, s->byteCount >> 5);
|
||||
sha1_addUncounted(s, s->byteCount << 3);
|
||||
}
|
||||
|
||||
uint8_t* sha1_result(sha1nfo *s) {
|
||||
// Pad to complete the last block
|
||||
sha1_pad(s);
|
||||
|
||||
#ifndef SHA_BIG_ENDIAN
|
||||
// Swap byte order back
|
||||
int i;
|
||||
for (i=0; i<5; i++) {
|
||||
s->state[i]=
|
||||
(((s->state[i])<<24)& 0xff000000)
|
||||
| (((s->state[i])<<8) & 0x00ff0000)
|
||||
| (((s->state[i])>>8) & 0x0000ff00)
|
||||
| (((s->state[i])>>24)& 0x000000ff);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Return pointer to hash (20 characters)
|
||||
return (uint8_t*) s->state;
|
||||
}
|
||||
|
||||
} // namespace; Added for LibFuzzer
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
// The rest is added for LibFuzzer
|
||||
void ComputeSHA1(const uint8_t *Data, size_t Len, uint8_t *Out) {
|
||||
sha1nfo s;
|
||||
sha1_init(&s);
|
||||
sha1_write(&s, (const char*)Data, Len);
|
||||
memcpy(Out, sha1_result(&s), HASH_LENGTH);
|
||||
}
|
||||
|
||||
std::string Sha1ToString(const uint8_t Sha1[kSHA1NumBytes]) {
|
||||
std::stringstream SS;
|
||||
for (int i = 0; i < kSHA1NumBytes; i++)
|
||||
SS << std::hex << std::setfill('0') << std::setw(2) << (unsigned)Sha1[i];
|
||||
return SS.str();
|
||||
}
|
||||
|
||||
std::string Hash(const Unit &U) {
|
||||
uint8_t Hash[kSHA1NumBytes];
|
||||
ComputeSHA1(U.data(), U.size(), Hash);
|
||||
return Sha1ToString(Hash);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
//===- FuzzerSHA1.h - Internal header for the SHA1 utils --------*- C++ -* ===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// SHA1 utils.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_FUZZER_SHA1_H
|
||||
#define LLVM_FUZZER_SHA1_H
|
||||
|
||||
#include "FuzzerDefs.h"
|
||||
#include <cstddef>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
// Private copy of SHA1 implementation.
|
||||
static const int kSHA1NumBytes = 20;
|
||||
|
||||
// Computes SHA1 hash of 'Len' bytes in 'Data', writes kSHA1NumBytes to 'Out'.
|
||||
void ComputeSHA1(const uint8_t *Data, size_t Len, uint8_t *Out);
|
||||
|
||||
std::string Sha1ToString(const uint8_t Sha1[kSHA1NumBytes]);
|
||||
|
||||
std::string Hash(const Unit &U);
|
||||
|
||||
} // namespace fuzzer
|
||||
|
||||
#endif // LLVM_FUZZER_SHA1_H
|
||||
@@ -1,339 +0,0 @@
|
||||
//===- FuzzerTracePC.cpp - PC tracing--------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Trace PCs.
|
||||
// This module implements __sanitizer_cov_trace_pc_guard[_init],
|
||||
// the callback required for -fsanitize-coverage=trace-pc-guard instrumentation.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "FuzzerCorpus.h"
|
||||
#include "FuzzerDefs.h"
|
||||
#include "FuzzerDictionary.h"
|
||||
#include "FuzzerExtFunctions.h"
|
||||
#include "FuzzerIO.h"
|
||||
#include "FuzzerTracePC.h"
|
||||
#include "FuzzerValueBitMap.h"
|
||||
#include <map>
|
||||
#include <sanitizer/coverage_interface.h>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
TracePC TPC;
|
||||
|
||||
void TracePC::HandleTrace(uint32_t *Guard, uintptr_t PC) {
|
||||
uint32_t Idx = *Guard;
|
||||
if (!Idx) return;
|
||||
PCs[Idx % kNumPCs] = PC;
|
||||
Counters[Idx % kNumCounters]++;
|
||||
}
|
||||
|
||||
size_t TracePC::GetTotalPCCoverage() {
|
||||
size_t Res = 0;
|
||||
for (size_t i = 1; i < GetNumPCs(); i++)
|
||||
if (PCs[i])
|
||||
Res++;
|
||||
return Res;
|
||||
}
|
||||
|
||||
void TracePC::HandleInit(uint32_t *Start, uint32_t *Stop) {
|
||||
if (Start == Stop || *Start) return;
|
||||
assert(NumModules < sizeof(Modules) / sizeof(Modules[0]));
|
||||
for (uint32_t *P = Start; P < Stop; P++)
|
||||
*P = ++NumGuards;
|
||||
Modules[NumModules].Start = Start;
|
||||
Modules[NumModules].Stop = Stop;
|
||||
NumModules++;
|
||||
}
|
||||
|
||||
void TracePC::PrintModuleInfo() {
|
||||
Printf("INFO: Loaded %zd modules (%zd guards): ", NumModules, NumGuards);
|
||||
for (size_t i = 0; i < NumModules; i++)
|
||||
Printf("[%p, %p), ", Modules[i].Start, Modules[i].Stop);
|
||||
Printf("\n");
|
||||
}
|
||||
|
||||
void TracePC::HandleCallerCallee(uintptr_t Caller, uintptr_t Callee) {
|
||||
const uintptr_t kBits = 12;
|
||||
const uintptr_t kMask = (1 << kBits) - 1;
|
||||
uintptr_t Idx = (Caller & kMask) | ((Callee & kMask) << kBits);
|
||||
HandleValueProfile(Idx);
|
||||
}
|
||||
|
||||
static bool IsInterestingCoverageFile(std::string &File) {
|
||||
if (File.find("compiler-rt/lib/") != std::string::npos)
|
||||
return false; // sanitizer internal.
|
||||
if (File.find("/usr/lib/") != std::string::npos)
|
||||
return false;
|
||||
if (File.find("/usr/include/") != std::string::npos)
|
||||
return false;
|
||||
if (File == "<null>")
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void TracePC::PrintNewPCs() {
|
||||
if (DoPrintNewPCs) {
|
||||
if (!PrintedPCs)
|
||||
PrintedPCs = new std::set<uintptr_t>;
|
||||
for (size_t i = 1; i < GetNumPCs(); i++)
|
||||
if (PCs[i] && PrintedPCs->insert(PCs[i]).second)
|
||||
PrintPC("\tNEW_PC: %p %F %L\n", "\tNEW_PC: %p\n", PCs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void TracePC::PrintCoverage() {
|
||||
if (!EF->__sanitizer_symbolize_pc ||
|
||||
!EF->__sanitizer_get_module_and_offset_for_pc) {
|
||||
Printf("INFO: __sanitizer_symbolize_pc or "
|
||||
"__sanitizer_get_module_and_offset_for_pc is not available,"
|
||||
" not printing coverage\n");
|
||||
return;
|
||||
}
|
||||
std::map<std::string, std::vector<uintptr_t>> CoveredPCsPerModule;
|
||||
std::map<std::string, uintptr_t> ModuleOffsets;
|
||||
std::set<std::string> CoveredDirs, CoveredFiles, CoveredFunctions,
|
||||
CoveredLines;
|
||||
Printf("COVERAGE:\n");
|
||||
for (size_t i = 1; i < GetNumPCs(); i++) {
|
||||
if (!PCs[i]) continue;
|
||||
std::string FileStr = DescribePC("%s", PCs[i]);
|
||||
if (!IsInterestingCoverageFile(FileStr)) continue;
|
||||
std::string FixedPCStr = DescribePC("%p", PCs[i]);
|
||||
std::string FunctionStr = DescribePC("%F", PCs[i]);
|
||||
std::string LineStr = DescribePC("%l", PCs[i]);
|
||||
char ModulePathRaw[4096] = ""; // What's PATH_MAX in portable C++?
|
||||
void *OffsetRaw = nullptr;
|
||||
if (!EF->__sanitizer_get_module_and_offset_for_pc(
|
||||
reinterpret_cast<void *>(PCs[i]), ModulePathRaw,
|
||||
sizeof(ModulePathRaw), &OffsetRaw))
|
||||
continue;
|
||||
std::string Module = ModulePathRaw;
|
||||
uintptr_t FixedPC = std::stol(FixedPCStr, 0, 16);
|
||||
uintptr_t PcOffset = reinterpret_cast<uintptr_t>(OffsetRaw);
|
||||
ModuleOffsets[Module] = FixedPC - PcOffset;
|
||||
CoveredPCsPerModule[Module].push_back(PcOffset);
|
||||
CoveredFunctions.insert(FunctionStr);
|
||||
CoveredFiles.insert(FileStr);
|
||||
CoveredDirs.insert(DirName(FileStr));
|
||||
if (!CoveredLines.insert(FileStr + ":" + LineStr).second)
|
||||
continue;
|
||||
Printf("COVERED: %s %s:%s\n", FunctionStr.c_str(),
|
||||
FileStr.c_str(), LineStr.c_str());
|
||||
}
|
||||
|
||||
std::string CoveredDirsStr;
|
||||
for (auto &Dir : CoveredDirs) {
|
||||
if (!CoveredDirsStr.empty())
|
||||
CoveredDirsStr += ",";
|
||||
CoveredDirsStr += Dir;
|
||||
}
|
||||
Printf("COVERED_DIRS: %s\n", CoveredDirsStr.c_str());
|
||||
|
||||
for (auto &M : CoveredPCsPerModule) {
|
||||
std::set<std::string> UncoveredFiles, UncoveredFunctions;
|
||||
std::map<std::string, std::set<int> > UncoveredLines; // Func+File => lines
|
||||
auto &ModuleName = M.first;
|
||||
auto &CoveredOffsets = M.second;
|
||||
uintptr_t ModuleOffset = ModuleOffsets[ModuleName];
|
||||
std::sort(CoveredOffsets.begin(), CoveredOffsets.end());
|
||||
Printf("MODULE_WITH_COVERAGE: %s\n", ModuleName.c_str());
|
||||
// sancov does not yet fully support DSOs.
|
||||
// std::string Cmd = "sancov -print-coverage-pcs " + ModuleName;
|
||||
std::string Cmd = "objdump -d " + ModuleName +
|
||||
" | grep 'call.*__sanitizer_cov_trace_pc_guard' | awk -F: '{print $1}'";
|
||||
std::string SanCovOutput;
|
||||
if (!ExecuteCommandAndReadOutput(Cmd, &SanCovOutput)) {
|
||||
Printf("INFO: Command failed: %s\n", Cmd.c_str());
|
||||
continue;
|
||||
}
|
||||
std::istringstream ISS(SanCovOutput);
|
||||
std::string S;
|
||||
while (std::getline(ISS, S, '\n')) {
|
||||
uintptr_t PcOffset = std::stol(S, 0, 16);
|
||||
if (!std::binary_search(CoveredOffsets.begin(), CoveredOffsets.end(),
|
||||
PcOffset)) {
|
||||
uintptr_t PC = ModuleOffset + PcOffset;
|
||||
auto FileStr = DescribePC("%s", PC);
|
||||
if (!IsInterestingCoverageFile(FileStr)) continue;
|
||||
if (CoveredFiles.count(FileStr) == 0) {
|
||||
UncoveredFiles.insert(FileStr);
|
||||
continue;
|
||||
}
|
||||
auto FunctionStr = DescribePC("%F", PC);
|
||||
if (CoveredFunctions.count(FunctionStr) == 0) {
|
||||
UncoveredFunctions.insert(FunctionStr);
|
||||
continue;
|
||||
}
|
||||
std::string LineStr = DescribePC("%l", PC);
|
||||
uintptr_t Line = std::stoi(LineStr);
|
||||
std::string FileLineStr = FileStr + ":" + LineStr;
|
||||
if (CoveredLines.count(FileLineStr) == 0)
|
||||
UncoveredLines[FunctionStr + " " + FileStr].insert(Line);
|
||||
}
|
||||
}
|
||||
for (auto &FileLine: UncoveredLines)
|
||||
for (int Line : FileLine.second)
|
||||
Printf("UNCOVERED_LINE: %s:%d\n", FileLine.first.c_str(), Line);
|
||||
for (auto &Func : UncoveredFunctions)
|
||||
Printf("UNCOVERED_FUNC: %s\n", Func.c_str());
|
||||
for (auto &File : UncoveredFiles)
|
||||
Printf("UNCOVERED_FILE: %s\n", File.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void TracePC::DumpCoverage() {
|
||||
__sanitizer_dump_coverage(PCs, GetNumPCs());
|
||||
}
|
||||
|
||||
// Value profile.
|
||||
// We keep track of various values that affect control flow.
|
||||
// These values are inserted into a bit-set-based hash map.
|
||||
// Every new bit in the map is treated as a new coverage.
|
||||
//
|
||||
// For memcmp/strcmp/etc the interesting value is the length of the common
|
||||
// prefix of the parameters.
|
||||
// For cmp instructions the interesting value is a XOR of the parameters.
|
||||
// The interesting value is mixed up with the PC and is then added to the map.
|
||||
|
||||
ATTRIBUTE_NO_SANITIZE_MEMORY
|
||||
void TracePC::AddValueForMemcmp(void *caller_pc, const void *s1, const void *s2,
|
||||
size_t n) {
|
||||
if (!n) return;
|
||||
size_t Len = std::min(n, (size_t)32);
|
||||
const uint8_t *A1 = reinterpret_cast<const uint8_t *>(s1);
|
||||
const uint8_t *A2 = reinterpret_cast<const uint8_t *>(s2);
|
||||
size_t I = 0;
|
||||
for (; I < Len; I++)
|
||||
if (A1[I] != A2[I])
|
||||
break;
|
||||
size_t PC = reinterpret_cast<size_t>(caller_pc);
|
||||
size_t Idx = I;
|
||||
// if (I < Len)
|
||||
// Idx += __builtin_popcountl((A1[I] ^ A2[I])) - 1;
|
||||
TPC.HandleValueProfile((PC & 4095) | (Idx << 12));
|
||||
}
|
||||
|
||||
ATTRIBUTE_NO_SANITIZE_MEMORY
|
||||
void TracePC::AddValueForStrcmp(void *caller_pc, const char *s1, const char *s2,
|
||||
size_t n) {
|
||||
if (!n) return;
|
||||
size_t Len = std::min(n, (size_t)32);
|
||||
const uint8_t *A1 = reinterpret_cast<const uint8_t *>(s1);
|
||||
const uint8_t *A2 = reinterpret_cast<const uint8_t *>(s2);
|
||||
size_t I = 0;
|
||||
for (; I < Len; I++)
|
||||
if (A1[I] != A2[I] || A1[I] == 0)
|
||||
break;
|
||||
size_t PC = reinterpret_cast<size_t>(caller_pc);
|
||||
size_t Idx = I;
|
||||
// if (I < Len && A1[I])
|
||||
// Idx += __builtin_popcountl((A1[I] ^ A2[I])) - 1;
|
||||
TPC.HandleValueProfile((PC & 4095) | (Idx << 12));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
ATTRIBUTE_TARGET_POPCNT
|
||||
#ifdef __clang__ // g++ can't handle this __attribute__ here :(
|
||||
__attribute__((always_inline))
|
||||
#endif // __clang__
|
||||
void TracePC::HandleCmp(void *PC, T Arg1, T Arg2) {
|
||||
uintptr_t PCuint = reinterpret_cast<uintptr_t>(PC);
|
||||
uint64_t ArgXor = Arg1 ^ Arg2;
|
||||
uint64_t ArgDistance = __builtin_popcountl(ArgXor) + 1; // [1,65]
|
||||
uintptr_t Idx = ((PCuint & 4095) + 1) * ArgDistance;
|
||||
if (sizeof(T) == 4)
|
||||
TORC4.Insert(ArgXor, Arg1, Arg2);
|
||||
else if (sizeof(T) == 8)
|
||||
TORC8.Insert(ArgXor, Arg1, Arg2);
|
||||
HandleValueProfile(Idx);
|
||||
}
|
||||
|
||||
} // namespace fuzzer
|
||||
|
||||
extern "C" {
|
||||
__attribute__((visibility("default")))
|
||||
void __sanitizer_cov_trace_pc_guard(uint32_t *Guard) {
|
||||
uintptr_t PC = (uintptr_t)__builtin_return_address(0);
|
||||
fuzzer::TPC.HandleTrace(Guard, PC);
|
||||
}
|
||||
|
||||
__attribute__((visibility("default")))
|
||||
void __sanitizer_cov_trace_pc_guard_init(uint32_t *Start, uint32_t *Stop) {
|
||||
fuzzer::TPC.HandleInit(Start, Stop);
|
||||
}
|
||||
|
||||
__attribute__((visibility("default")))
|
||||
void __sanitizer_cov_trace_pc_indir(uintptr_t Callee) {
|
||||
uintptr_t PC = (uintptr_t)__builtin_return_address(0);
|
||||
fuzzer::TPC.HandleCallerCallee(PC, Callee);
|
||||
}
|
||||
|
||||
__attribute__((visibility("default")))
|
||||
void __sanitizer_cov_trace_cmp8(uint64_t Arg1, uint64_t Arg2) {
|
||||
fuzzer::TPC.HandleCmp(__builtin_return_address(0), Arg1, Arg2);
|
||||
}
|
||||
__attribute__((visibility("default")))
|
||||
void __sanitizer_cov_trace_cmp4(uint32_t Arg1, uint32_t Arg2) {
|
||||
fuzzer::TPC.HandleCmp(__builtin_return_address(0), Arg1, Arg2);
|
||||
}
|
||||
__attribute__((visibility("default")))
|
||||
void __sanitizer_cov_trace_cmp2(uint16_t Arg1, uint16_t Arg2) {
|
||||
fuzzer::TPC.HandleCmp(__builtin_return_address(0), Arg1, Arg2);
|
||||
}
|
||||
__attribute__((visibility("default")))
|
||||
void __sanitizer_cov_trace_cmp1(uint8_t Arg1, uint8_t Arg2) {
|
||||
fuzzer::TPC.HandleCmp(__builtin_return_address(0), Arg1, Arg2);
|
||||
}
|
||||
|
||||
__attribute__((visibility("default")))
|
||||
void __sanitizer_cov_trace_switch(uint64_t Val, uint64_t *Cases) {
|
||||
// Updates the value profile based on the relative position of Val and Cases.
|
||||
// We want to handle one random case at every call (handling all is slow).
|
||||
// Since none of the arguments contain any random bits we use a thread-local
|
||||
// counter to choose the random case to handle.
|
||||
static thread_local size_t Counter;
|
||||
Counter++;
|
||||
uint64_t N = Cases[0];
|
||||
uint64_t *Vals = Cases + 2;
|
||||
char *PC = (char*)__builtin_return_address(0);
|
||||
// We need a random number < N using Counter as a seed. But w/o DIV.
|
||||
// * find a power of two >= N
|
||||
// * mask Counter with this power of two.
|
||||
// * maybe subtract N.
|
||||
size_t Nlog = sizeof(long) * 8 - __builtin_clzl((long)N);
|
||||
size_t PowerOfTwoGeN = 1U << Nlog;
|
||||
assert(PowerOfTwoGeN >= N);
|
||||
size_t Idx = Counter & (PowerOfTwoGeN - 1);
|
||||
if (Idx >= N)
|
||||
Idx -= N;
|
||||
assert(Idx < N);
|
||||
uint64_t TwoIn32 = 1ULL << 32;
|
||||
if ((Val | Vals[Idx]) < TwoIn32)
|
||||
fuzzer::TPC.HandleCmp(PC + Idx, static_cast<uint32_t>(Val),
|
||||
static_cast<uint32_t>(Vals[Idx]));
|
||||
else
|
||||
fuzzer::TPC.HandleCmp(PC + Idx, Val, Vals[Idx]);
|
||||
}
|
||||
|
||||
__attribute__((visibility("default")))
|
||||
void __sanitizer_cov_trace_div4(uint32_t Val) {
|
||||
fuzzer::TPC.HandleCmp(__builtin_return_address(0), Val, (uint32_t)0);
|
||||
}
|
||||
__attribute__((visibility("default")))
|
||||
void __sanitizer_cov_trace_div8(uint64_t Val) {
|
||||
fuzzer::TPC.HandleCmp(__builtin_return_address(0), Val, (uint64_t)0);
|
||||
}
|
||||
__attribute__((visibility("default")))
|
||||
void __sanitizer_cov_trace_gep(uintptr_t Idx) {
|
||||
fuzzer::TPC.HandleCmp(__builtin_return_address(0), Idx, (uintptr_t)0);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
@@ -1,158 +0,0 @@
|
||||
//===- FuzzerTracePC.h - Internal header for the Fuzzer ---------*- C++ -* ===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// fuzzer::TracePC
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_FUZZER_TRACE_PC
|
||||
#define LLVM_FUZZER_TRACE_PC
|
||||
|
||||
#include "FuzzerDefs.h"
|
||||
#include "FuzzerValueBitMap.h"
|
||||
#include <set>
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
// TableOfRecentCompares (TORC) remembers the most recently performed
|
||||
// comparisons of type T.
|
||||
// We record the arguments of CMP instructions in this table unconditionally
|
||||
// because it seems cheaper this way than to compute some expensive
|
||||
// conditions inside __sanitizer_cov_trace_cmp*.
|
||||
// After the unit has been executed we may decide to use the contents of
|
||||
// this table to populate a Dictionary.
|
||||
template<class T, size_t kSizeT>
|
||||
struct TableOfRecentCompares {
|
||||
static const size_t kSize = kSizeT;
|
||||
struct Pair {
|
||||
T A, B;
|
||||
};
|
||||
void Insert(size_t Idx, T Arg1, T Arg2) {
|
||||
Idx = Idx % kSize;
|
||||
Table[Idx].A = Arg1;
|
||||
Table[Idx].B = Arg2;
|
||||
}
|
||||
|
||||
Pair Get(size_t I) { return Table[I % kSize]; }
|
||||
|
||||
Pair Table[kSize];
|
||||
};
|
||||
|
||||
class TracePC {
|
||||
public:
|
||||
static const size_t kFeatureSetSize = ValueBitMap::kNumberOfItems;
|
||||
|
||||
void HandleTrace(uint32_t *guard, uintptr_t PC);
|
||||
void HandleInit(uint32_t *start, uint32_t *stop);
|
||||
void HandleCallerCallee(uintptr_t Caller, uintptr_t Callee);
|
||||
void HandleValueProfile(size_t Value) { ValueProfileMap.AddValue(Value); }
|
||||
template <class T> void HandleCmp(void *PC, T Arg1, T Arg2);
|
||||
size_t GetTotalPCCoverage();
|
||||
void SetUseCounters(bool UC) { UseCounters = UC; }
|
||||
void SetUseValueProfile(bool VP) { UseValueProfile = VP; }
|
||||
void SetPrintNewPCs(bool P) { DoPrintNewPCs = P; }
|
||||
template <class Callback> size_t CollectFeatures(Callback CB);
|
||||
bool UpdateValueProfileMap(ValueBitMap *MaxValueProfileMap) {
|
||||
return UseValueProfile && MaxValueProfileMap->MergeFrom(ValueProfileMap);
|
||||
}
|
||||
|
||||
void ResetMaps() {
|
||||
ValueProfileMap.Reset();
|
||||
memset(Counters, 0, sizeof(Counters));
|
||||
}
|
||||
|
||||
void UpdateFeatureSet(size_t CurrentElementIdx, size_t CurrentElementSize);
|
||||
void PrintFeatureSet();
|
||||
|
||||
void PrintModuleInfo();
|
||||
|
||||
void PrintCoverage();
|
||||
void DumpCoverage();
|
||||
|
||||
void AddValueForMemcmp(void *caller_pc, const void *s1, const void *s2,
|
||||
size_t n);
|
||||
void AddValueForStrcmp(void *caller_pc, const char *s1, const char *s2,
|
||||
size_t n);
|
||||
|
||||
bool UsingTracePcGuard() const {return NumModules; }
|
||||
|
||||
static const size_t kTORCSize = 1 << 5;
|
||||
TableOfRecentCompares<uint32_t, kTORCSize> TORC4;
|
||||
TableOfRecentCompares<uint64_t, kTORCSize> TORC8;
|
||||
|
||||
void PrintNewPCs();
|
||||
size_t GetNumPCs() const { return Min(kNumPCs, NumGuards + 1); }
|
||||
uintptr_t GetPC(size_t Idx) {
|
||||
assert(Idx < GetNumPCs());
|
||||
return PCs[Idx];
|
||||
}
|
||||
|
||||
private:
|
||||
bool UseCounters = false;
|
||||
bool UseValueProfile = false;
|
||||
bool DoPrintNewPCs = false;
|
||||
|
||||
struct Module {
|
||||
uint32_t *Start, *Stop;
|
||||
};
|
||||
|
||||
Module Modules[4096];
|
||||
size_t NumModules; // linker-initialized.
|
||||
size_t NumGuards; // linker-initialized.
|
||||
|
||||
static const size_t kNumCounters = 1 << 14;
|
||||
alignas(8) uint8_t Counters[kNumCounters];
|
||||
|
||||
static const size_t kNumPCs = 1 << 24;
|
||||
uintptr_t PCs[kNumPCs];
|
||||
|
||||
std::set<uintptr_t> *PrintedPCs;
|
||||
|
||||
ValueBitMap ValueProfileMap;
|
||||
};
|
||||
|
||||
template <class Callback>
|
||||
size_t TracePC::CollectFeatures(Callback CB) {
|
||||
if (!UsingTracePcGuard()) return 0;
|
||||
size_t Res = 0;
|
||||
const size_t Step = 8;
|
||||
assert(reinterpret_cast<uintptr_t>(Counters) % Step == 0);
|
||||
size_t N = Min(kNumCounters, NumGuards + 1);
|
||||
N = (N + Step - 1) & ~(Step - 1); // Round up.
|
||||
for (size_t Idx = 0; Idx < N; Idx += Step) {
|
||||
uint64_t Bundle = *reinterpret_cast<uint64_t*>(&Counters[Idx]);
|
||||
if (!Bundle) continue;
|
||||
for (size_t i = Idx; i < Idx + Step; i++) {
|
||||
uint8_t Counter = (Bundle >> ((i - Idx) * 8)) & 0xff;
|
||||
if (!Counter) continue;
|
||||
Counters[i] = 0;
|
||||
unsigned Bit = 0;
|
||||
/**/ if (Counter >= 128) Bit = 7;
|
||||
else if (Counter >= 32) Bit = 6;
|
||||
else if (Counter >= 16) Bit = 5;
|
||||
else if (Counter >= 8) Bit = 4;
|
||||
else if (Counter >= 4) Bit = 3;
|
||||
else if (Counter >= 3) Bit = 2;
|
||||
else if (Counter >= 2) Bit = 1;
|
||||
size_t Feature = (i * 8 + Bit);
|
||||
if (CB(Feature))
|
||||
Res++;
|
||||
}
|
||||
}
|
||||
if (UseValueProfile)
|
||||
ValueProfileMap.ForEach([&](size_t Idx) {
|
||||
if (CB(NumGuards * 8 + Idx))
|
||||
Res++;
|
||||
});
|
||||
return Res;
|
||||
}
|
||||
|
||||
extern TracePC TPC;
|
||||
|
||||
} // namespace fuzzer
|
||||
|
||||
#endif // LLVM_FUZZER_TRACE_PC
|
||||
@@ -1,325 +0,0 @@
|
||||
//===- FuzzerTraceState.cpp - Trace-based fuzzer mutator ------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Data tracing.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "FuzzerDictionary.h"
|
||||
#include "FuzzerInternal.h"
|
||||
#include "FuzzerIO.h"
|
||||
#include "FuzzerMutate.h"
|
||||
#include "FuzzerRandom.h"
|
||||
#include "FuzzerTracePC.h"
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <thread>
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
// For now, very simple: put Size bytes of Data at position Pos.
|
||||
struct TraceBasedMutation {
|
||||
uint32_t Pos;
|
||||
Word W;
|
||||
};
|
||||
|
||||
// Declared as static globals for faster checks inside the hooks.
|
||||
static bool RecordingMemcmp = false;
|
||||
static bool RecordingMemmem = false;
|
||||
static bool DoingMyOwnMemmem = false;
|
||||
|
||||
ScopedDoingMyOwnMemmem::ScopedDoingMyOwnMemmem() { DoingMyOwnMemmem = true; }
|
||||
ScopedDoingMyOwnMemmem::~ScopedDoingMyOwnMemmem() { DoingMyOwnMemmem = false; }
|
||||
|
||||
class TraceState {
|
||||
public:
|
||||
TraceState(MutationDispatcher &MD, const FuzzingOptions &Options,
|
||||
const Fuzzer *F)
|
||||
: MD(MD), Options(Options), F(F) {}
|
||||
|
||||
void TraceMemcmpCallback(size_t CmpSize, const uint8_t *Data1,
|
||||
const uint8_t *Data2);
|
||||
|
||||
void TraceSwitchCallback(uintptr_t PC, size_t ValSizeInBits, uint64_t Val,
|
||||
size_t NumCases, uint64_t *Cases);
|
||||
int TryToAddDesiredData(uint64_t PresentData, uint64_t DesiredData,
|
||||
size_t DataSize);
|
||||
int TryToAddDesiredData(const uint8_t *PresentData,
|
||||
const uint8_t *DesiredData, size_t DataSize);
|
||||
|
||||
void StartTraceRecording() {
|
||||
if (!Options.UseMemcmp)
|
||||
return;
|
||||
RecordingMemcmp = Options.UseMemcmp;
|
||||
RecordingMemmem = Options.UseMemmem;
|
||||
NumMutations = 0;
|
||||
InterestingWords.clear();
|
||||
MD.ClearAutoDictionary();
|
||||
}
|
||||
|
||||
void StopTraceRecording() {
|
||||
if (!RecordingMemcmp)
|
||||
return;
|
||||
RecordingMemcmp = false;
|
||||
for (size_t i = 0; i < NumMutations; i++) {
|
||||
auto &M = Mutations[i];
|
||||
if (Options.Verbosity >= 2) {
|
||||
AutoDictUnitCounts[M.W]++;
|
||||
AutoDictAdds++;
|
||||
if ((AutoDictAdds & (AutoDictAdds - 1)) == 0) {
|
||||
typedef std::pair<size_t, Word> CU;
|
||||
std::vector<CU> CountedUnits;
|
||||
for (auto &I : AutoDictUnitCounts)
|
||||
CountedUnits.push_back(std::make_pair(I.second, I.first));
|
||||
std::sort(CountedUnits.begin(), CountedUnits.end(),
|
||||
[](const CU &a, const CU &b) { return a.first > b.first; });
|
||||
Printf("AutoDict:\n");
|
||||
for (auto &I : CountedUnits) {
|
||||
Printf(" %zd ", I.first);
|
||||
PrintASCII(I.second.data(), I.second.size());
|
||||
Printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
MD.AddWordToAutoDictionary({M.W, M.Pos});
|
||||
}
|
||||
for (auto &W : InterestingWords)
|
||||
MD.AddWordToAutoDictionary({W});
|
||||
}
|
||||
|
||||
void AddMutation(uint32_t Pos, uint32_t Size, const uint8_t *Data) {
|
||||
if (NumMutations >= kMaxMutations) return;
|
||||
auto &M = Mutations[NumMutations++];
|
||||
M.Pos = Pos;
|
||||
M.W.Set(Data, Size);
|
||||
}
|
||||
|
||||
void AddMutation(uint32_t Pos, uint32_t Size, uint64_t Data) {
|
||||
assert(Size <= sizeof(Data));
|
||||
AddMutation(Pos, Size, reinterpret_cast<uint8_t*>(&Data));
|
||||
}
|
||||
|
||||
void AddInterestingWord(const uint8_t *Data, size_t Size) {
|
||||
if (!RecordingMemmem || !F->InFuzzingThread()) return;
|
||||
if (Size <= 1) return;
|
||||
Size = std::min(Size, Word::GetMaxSize());
|
||||
Word W(Data, Size);
|
||||
InterestingWords.insert(W);
|
||||
}
|
||||
|
||||
private:
|
||||
bool IsTwoByteData(uint64_t Data) {
|
||||
int64_t Signed = static_cast<int64_t>(Data);
|
||||
Signed >>= 16;
|
||||
return Signed == 0 || Signed == -1L;
|
||||
}
|
||||
|
||||
// We don't want to create too many trace-based mutations as it is both
|
||||
// expensive and useless. So after some number of mutations is collected,
|
||||
// start rejecting some of them. The more there are mutations the more we
|
||||
// reject.
|
||||
bool WantToHandleOneMoreMutation() {
|
||||
const size_t FirstN = 64;
|
||||
// Gladly handle first N mutations.
|
||||
if (NumMutations <= FirstN) return true;
|
||||
size_t Diff = NumMutations - FirstN;
|
||||
size_t DiffLog = sizeof(long) * 8 - __builtin_clzl((long)Diff);
|
||||
assert(DiffLog > 0 && DiffLog < 64);
|
||||
bool WantThisOne = MD.GetRand()(1 << DiffLog) == 0; // 1 out of DiffLog.
|
||||
return WantThisOne;
|
||||
}
|
||||
|
||||
static const size_t kMaxMutations = 1 << 16;
|
||||
size_t NumMutations;
|
||||
TraceBasedMutation Mutations[kMaxMutations];
|
||||
// TODO: std::set is too inefficient, need to have a custom DS here.
|
||||
std::set<Word> InterestingWords;
|
||||
MutationDispatcher &MD;
|
||||
const FuzzingOptions Options;
|
||||
const Fuzzer *F;
|
||||
std::map<Word, size_t> AutoDictUnitCounts;
|
||||
size_t AutoDictAdds = 0;
|
||||
};
|
||||
|
||||
int TraceState::TryToAddDesiredData(uint64_t PresentData, uint64_t DesiredData,
|
||||
size_t DataSize) {
|
||||
if (NumMutations >= kMaxMutations || !WantToHandleOneMoreMutation()) return 0;
|
||||
ScopedDoingMyOwnMemmem scoped_doing_my_own_memmem;
|
||||
const uint8_t *UnitData;
|
||||
auto UnitSize = F->GetCurrentUnitInFuzzingThead(&UnitData);
|
||||
int Res = 0;
|
||||
const uint8_t *Beg = UnitData;
|
||||
const uint8_t *End = Beg + UnitSize;
|
||||
for (const uint8_t *Cur = Beg; Cur < End; Cur++) {
|
||||
Cur = (uint8_t *)SearchMemory(Cur, End - Cur, &PresentData, DataSize);
|
||||
if (!Cur)
|
||||
break;
|
||||
size_t Pos = Cur - Beg;
|
||||
assert(Pos < UnitSize);
|
||||
AddMutation(Pos, DataSize, DesiredData);
|
||||
AddMutation(Pos, DataSize, DesiredData + 1);
|
||||
AddMutation(Pos, DataSize, DesiredData - 1);
|
||||
Res++;
|
||||
}
|
||||
return Res;
|
||||
}
|
||||
|
||||
int TraceState::TryToAddDesiredData(const uint8_t *PresentData,
|
||||
const uint8_t *DesiredData,
|
||||
size_t DataSize) {
|
||||
if (NumMutations >= kMaxMutations || !WantToHandleOneMoreMutation()) return 0;
|
||||
ScopedDoingMyOwnMemmem scoped_doing_my_own_memmem;
|
||||
const uint8_t *UnitData;
|
||||
auto UnitSize = F->GetCurrentUnitInFuzzingThead(&UnitData);
|
||||
int Res = 0;
|
||||
const uint8_t *Beg = UnitData;
|
||||
const uint8_t *End = Beg + UnitSize;
|
||||
for (const uint8_t *Cur = Beg; Cur < End; Cur++) {
|
||||
Cur = (uint8_t *)SearchMemory(Cur, End - Cur, PresentData, DataSize);
|
||||
if (!Cur)
|
||||
break;
|
||||
size_t Pos = Cur - Beg;
|
||||
assert(Pos < UnitSize);
|
||||
AddMutation(Pos, DataSize, DesiredData);
|
||||
Res++;
|
||||
}
|
||||
return Res;
|
||||
}
|
||||
|
||||
void TraceState::TraceMemcmpCallback(size_t CmpSize, const uint8_t *Data1,
|
||||
const uint8_t *Data2) {
|
||||
if (!RecordingMemcmp || !F->InFuzzingThread()) return;
|
||||
CmpSize = std::min(CmpSize, Word::GetMaxSize());
|
||||
int Added2 = TryToAddDesiredData(Data1, Data2, CmpSize);
|
||||
int Added1 = TryToAddDesiredData(Data2, Data1, CmpSize);
|
||||
if ((Added1 || Added2) && Options.Verbosity >= 3) {
|
||||
Printf("MemCmp Added %d%d: ", Added1, Added2);
|
||||
if (Added1) PrintASCII(Data1, CmpSize);
|
||||
if (Added2) PrintASCII(Data2, CmpSize);
|
||||
Printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
void TraceState::TraceSwitchCallback(uintptr_t PC, size_t ValSizeInBits,
|
||||
uint64_t Val, size_t NumCases,
|
||||
uint64_t *Cases) {
|
||||
if (F->InFuzzingThread()) return;
|
||||
size_t ValSize = ValSizeInBits / 8;
|
||||
bool TryShort = IsTwoByteData(Val);
|
||||
for (size_t i = 0; i < NumCases; i++)
|
||||
TryShort &= IsTwoByteData(Cases[i]);
|
||||
|
||||
if (Options.Verbosity >= 3)
|
||||
Printf("TraceSwitch: %p %zd # %zd; TryShort %d\n", PC, Val, NumCases,
|
||||
TryShort);
|
||||
|
||||
for (size_t i = 0; i < NumCases; i++) {
|
||||
TryToAddDesiredData(Val, Cases[i], ValSize);
|
||||
if (TryShort)
|
||||
TryToAddDesiredData(Val, Cases[i], 2);
|
||||
}
|
||||
}
|
||||
|
||||
static TraceState *TS;
|
||||
|
||||
void Fuzzer::StartTraceRecording() {
|
||||
if (!TS) return;
|
||||
TS->StartTraceRecording();
|
||||
}
|
||||
|
||||
void Fuzzer::StopTraceRecording() {
|
||||
if (!TS) return;
|
||||
TS->StopTraceRecording();
|
||||
}
|
||||
|
||||
void Fuzzer::InitializeTraceState() {
|
||||
if (!Options.UseMemcmp) return;
|
||||
TS = new TraceState(MD, Options, this);
|
||||
}
|
||||
|
||||
static size_t InternalStrnlen(const char *S, size_t MaxLen) {
|
||||
size_t Len = 0;
|
||||
for (; Len < MaxLen && S[Len]; Len++) {}
|
||||
return Len;
|
||||
}
|
||||
|
||||
} // namespace fuzzer
|
||||
|
||||
using fuzzer::TS;
|
||||
using fuzzer::RecordingMemcmp;
|
||||
|
||||
extern "C" {
|
||||
|
||||
// We may need to avoid defining weak hooks to stay compatible with older clang.
|
||||
#ifndef LLVM_FUZZER_DEFINES_SANITIZER_WEAK_HOOOKS
|
||||
# define LLVM_FUZZER_DEFINES_SANITIZER_WEAK_HOOOKS 1
|
||||
#endif
|
||||
|
||||
#if LLVM_FUZZER_DEFINES_SANITIZER_WEAK_HOOOKS
|
||||
void __sanitizer_weak_hook_memcmp(void *caller_pc, const void *s1,
|
||||
const void *s2, size_t n, int result) {
|
||||
fuzzer::TPC.AddValueForMemcmp(caller_pc, s1, s2, n);
|
||||
if (!RecordingMemcmp) return;
|
||||
if (result == 0) return; // No reason to mutate.
|
||||
if (n <= 1) return; // Not interesting.
|
||||
TS->TraceMemcmpCallback(n, reinterpret_cast<const uint8_t *>(s1),
|
||||
reinterpret_cast<const uint8_t *>(s2));
|
||||
}
|
||||
|
||||
void __sanitizer_weak_hook_strncmp(void *caller_pc, const char *s1,
|
||||
const char *s2, size_t n, int result) {
|
||||
fuzzer::TPC.AddValueForStrcmp(caller_pc, s1, s2, n);
|
||||
if (!RecordingMemcmp) return;
|
||||
if (result == 0) return; // No reason to mutate.
|
||||
size_t Len1 = fuzzer::InternalStrnlen(s1, n);
|
||||
size_t Len2 = fuzzer::InternalStrnlen(s2, n);
|
||||
n = std::min(n, Len1);
|
||||
n = std::min(n, Len2);
|
||||
if (n <= 1) return; // Not interesting.
|
||||
TS->TraceMemcmpCallback(n, reinterpret_cast<const uint8_t *>(s1),
|
||||
reinterpret_cast<const uint8_t *>(s2));
|
||||
}
|
||||
|
||||
void __sanitizer_weak_hook_strcmp(void *caller_pc, const char *s1,
|
||||
const char *s2, int result) {
|
||||
fuzzer::TPC.AddValueForStrcmp(caller_pc, s1, s2, 64);
|
||||
if (!RecordingMemcmp) return;
|
||||
if (result == 0) return; // No reason to mutate.
|
||||
size_t Len1 = strlen(s1);
|
||||
size_t Len2 = strlen(s2);
|
||||
size_t N = std::min(Len1, Len2);
|
||||
if (N <= 1) return; // Not interesting.
|
||||
TS->TraceMemcmpCallback(N, reinterpret_cast<const uint8_t *>(s1),
|
||||
reinterpret_cast<const uint8_t *>(s2));
|
||||
}
|
||||
|
||||
void __sanitizer_weak_hook_strncasecmp(void *called_pc, const char *s1,
|
||||
const char *s2, size_t n, int result) {
|
||||
return __sanitizer_weak_hook_strncmp(called_pc, s1, s2, n, result);
|
||||
}
|
||||
void __sanitizer_weak_hook_strcasecmp(void *called_pc, const char *s1,
|
||||
const char *s2, int result) {
|
||||
return __sanitizer_weak_hook_strcmp(called_pc, s1, s2, result);
|
||||
}
|
||||
void __sanitizer_weak_hook_strstr(void *called_pc, const char *s1,
|
||||
const char *s2, char *result) {
|
||||
TS->AddInterestingWord(reinterpret_cast<const uint8_t *>(s2), strlen(s2));
|
||||
}
|
||||
void __sanitizer_weak_hook_strcasestr(void *called_pc, const char *s1,
|
||||
const char *s2, char *result) {
|
||||
TS->AddInterestingWord(reinterpret_cast<const uint8_t *>(s2), strlen(s2));
|
||||
}
|
||||
void __sanitizer_weak_hook_memmem(void *called_pc, const void *s1, size_t len1,
|
||||
const void *s2, size_t len2, void *result) {
|
||||
if (fuzzer::DoingMyOwnMemmem) return;
|
||||
TS->AddInterestingWord(reinterpret_cast<const uint8_t *>(s2), len2);
|
||||
}
|
||||
|
||||
#endif // LLVM_FUZZER_DEFINES_SANITIZER_WEAK_HOOOKS
|
||||
} // extern "C"
|
||||
@@ -1,218 +0,0 @@
|
||||
//===- FuzzerUtil.cpp - Misc utils ----------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Misc utils.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "FuzzerUtil.h"
|
||||
#include "FuzzerIO.h"
|
||||
#include "FuzzerInternal.h"
|
||||
#include <cassert>
|
||||
#include <chrono>
|
||||
#include <cstring>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <sstream>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <thread>
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
void PrintHexArray(const uint8_t *Data, size_t Size,
|
||||
const char *PrintAfter) {
|
||||
for (size_t i = 0; i < Size; i++)
|
||||
Printf("0x%x,", (unsigned)Data[i]);
|
||||
Printf("%s", PrintAfter);
|
||||
}
|
||||
|
||||
void Print(const Unit &v, const char *PrintAfter) {
|
||||
PrintHexArray(v.data(), v.size(), PrintAfter);
|
||||
}
|
||||
|
||||
void PrintASCIIByte(uint8_t Byte) {
|
||||
if (Byte == '\\')
|
||||
Printf("\\\\");
|
||||
else if (Byte == '"')
|
||||
Printf("\\\"");
|
||||
else if (Byte >= 32 && Byte < 127)
|
||||
Printf("%c", Byte);
|
||||
else
|
||||
Printf("\\x%02x", Byte);
|
||||
}
|
||||
|
||||
void PrintASCII(const uint8_t *Data, size_t Size, const char *PrintAfter) {
|
||||
for (size_t i = 0; i < Size; i++)
|
||||
PrintASCIIByte(Data[i]);
|
||||
Printf("%s", PrintAfter);
|
||||
}
|
||||
|
||||
void PrintASCII(const Unit &U, const char *PrintAfter) {
|
||||
PrintASCII(U.data(), U.size(), PrintAfter);
|
||||
}
|
||||
|
||||
bool ToASCII(uint8_t *Data, size_t Size) {
|
||||
bool Changed = false;
|
||||
for (size_t i = 0; i < Size; i++) {
|
||||
uint8_t &X = Data[i];
|
||||
auto NewX = X;
|
||||
NewX &= 127;
|
||||
if (!isspace(NewX) && !isprint(NewX))
|
||||
NewX = ' ';
|
||||
Changed |= NewX != X;
|
||||
X = NewX;
|
||||
}
|
||||
return Changed;
|
||||
}
|
||||
|
||||
bool IsASCII(const Unit &U) { return IsASCII(U.data(), U.size()); }
|
||||
|
||||
bool IsASCII(const uint8_t *Data, size_t Size) {
|
||||
for (size_t i = 0; i < Size; i++)
|
||||
if (!(isprint(Data[i]) || isspace(Data[i]))) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ParseOneDictionaryEntry(const std::string &Str, Unit *U) {
|
||||
U->clear();
|
||||
if (Str.empty()) return false;
|
||||
size_t L = 0, R = Str.size() - 1; // We are parsing the range [L,R].
|
||||
// Skip spaces from both sides.
|
||||
while (L < R && isspace(Str[L])) L++;
|
||||
while (R > L && isspace(Str[R])) R--;
|
||||
if (R - L < 2) return false;
|
||||
// Check the closing "
|
||||
if (Str[R] != '"') return false;
|
||||
R--;
|
||||
// Find the opening "
|
||||
while (L < R && Str[L] != '"') L++;
|
||||
if (L >= R) return false;
|
||||
assert(Str[L] == '\"');
|
||||
L++;
|
||||
assert(L <= R);
|
||||
for (size_t Pos = L; Pos <= R; Pos++) {
|
||||
uint8_t V = (uint8_t)Str[Pos];
|
||||
if (!isprint(V) && !isspace(V)) return false;
|
||||
if (V =='\\') {
|
||||
// Handle '\\'
|
||||
if (Pos + 1 <= R && (Str[Pos + 1] == '\\' || Str[Pos + 1] == '"')) {
|
||||
U->push_back(Str[Pos + 1]);
|
||||
Pos++;
|
||||
continue;
|
||||
}
|
||||
// Handle '\xAB'
|
||||
if (Pos + 3 <= R && Str[Pos + 1] == 'x'
|
||||
&& isxdigit(Str[Pos + 2]) && isxdigit(Str[Pos + 3])) {
|
||||
char Hex[] = "0xAA";
|
||||
Hex[2] = Str[Pos + 2];
|
||||
Hex[3] = Str[Pos + 3];
|
||||
U->push_back(strtol(Hex, nullptr, 16));
|
||||
Pos += 3;
|
||||
continue;
|
||||
}
|
||||
return false; // Invalid escape.
|
||||
} else {
|
||||
// Any other character.
|
||||
U->push_back(V);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ParseDictionaryFile(const std::string &Text, std::vector<Unit> *Units) {
|
||||
if (Text.empty()) {
|
||||
Printf("ParseDictionaryFile: file does not exist or is empty\n");
|
||||
return false;
|
||||
}
|
||||
std::istringstream ISS(Text);
|
||||
Units->clear();
|
||||
Unit U;
|
||||
int LineNo = 0;
|
||||
std::string S;
|
||||
while (std::getline(ISS, S, '\n')) {
|
||||
LineNo++;
|
||||
size_t Pos = 0;
|
||||
while (Pos < S.size() && isspace(S[Pos])) Pos++; // Skip spaces.
|
||||
if (Pos == S.size()) continue; // Empty line.
|
||||
if (S[Pos] == '#') continue; // Comment line.
|
||||
if (ParseOneDictionaryEntry(S, &U)) {
|
||||
Units->push_back(U);
|
||||
} else {
|
||||
Printf("ParseDictionaryFile: error in line %d\n\t\t%s\n", LineNo,
|
||||
S.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string Base64(const Unit &U) {
|
||||
static const char Table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789+/";
|
||||
std::string Res;
|
||||
size_t i;
|
||||
for (i = 0; i + 2 < U.size(); i += 3) {
|
||||
uint32_t x = (U[i] << 16) + (U[i + 1] << 8) + U[i + 2];
|
||||
Res += Table[(x >> 18) & 63];
|
||||
Res += Table[(x >> 12) & 63];
|
||||
Res += Table[(x >> 6) & 63];
|
||||
Res += Table[x & 63];
|
||||
}
|
||||
if (i + 1 == U.size()) {
|
||||
uint32_t x = (U[i] << 16);
|
||||
Res += Table[(x >> 18) & 63];
|
||||
Res += Table[(x >> 12) & 63];
|
||||
Res += "==";
|
||||
} else if (i + 2 == U.size()) {
|
||||
uint32_t x = (U[i] << 16) + (U[i + 1] << 8);
|
||||
Res += Table[(x >> 18) & 63];
|
||||
Res += Table[(x >> 12) & 63];
|
||||
Res += Table[(x >> 6) & 63];
|
||||
Res += "=";
|
||||
}
|
||||
return Res;
|
||||
}
|
||||
|
||||
std::string DescribePC(const char *SymbolizedFMT, uintptr_t PC) {
|
||||
if (!EF->__sanitizer_symbolize_pc) return "<can not symbolize>";
|
||||
char PcDescr[1024];
|
||||
EF->__sanitizer_symbolize_pc(reinterpret_cast<void*>(PC),
|
||||
SymbolizedFMT, PcDescr, sizeof(PcDescr));
|
||||
PcDescr[sizeof(PcDescr) - 1] = 0; // Just in case.
|
||||
return PcDescr;
|
||||
}
|
||||
|
||||
void PrintPC(const char *SymbolizedFMT, const char *FallbackFMT, uintptr_t PC) {
|
||||
if (EF->__sanitizer_symbolize_pc)
|
||||
Printf("%s", DescribePC(SymbolizedFMT, PC).c_str());
|
||||
else
|
||||
Printf(FallbackFMT, PC);
|
||||
}
|
||||
|
||||
unsigned NumberOfCpuCores() {
|
||||
unsigned N = std::thread::hardware_concurrency();
|
||||
if (!N) {
|
||||
Printf("WARNING: std::thread::hardware_concurrency not well defined for "
|
||||
"your platform. Assuming CPU count of 1.\n");
|
||||
N = 1;
|
||||
}
|
||||
return N;
|
||||
}
|
||||
|
||||
bool ExecuteCommandAndReadOutput(const std::string &Command, std::string *Out) {
|
||||
FILE *Pipe = OpenProcessPipe(Command.c_str(), "r");
|
||||
if (!Pipe) return false;
|
||||
char Buff[1024];
|
||||
size_t N;
|
||||
while ((N = fread(Buff, 1, sizeof(Buff), Pipe)) > 0)
|
||||
Out->append(Buff, N);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace fuzzer
|
||||
@@ -1,72 +0,0 @@
|
||||
//===- FuzzerUtil.h - Internal header for the Fuzzer Utils ------*- C++ -* ===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Util functions.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_FUZZER_UTIL_H
|
||||
#define LLVM_FUZZER_UTIL_H
|
||||
|
||||
#include "FuzzerDefs.h"
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
void PrintHexArray(const Unit &U, const char *PrintAfter = "");
|
||||
|
||||
void PrintHexArray(const uint8_t *Data, size_t Size,
|
||||
const char *PrintAfter = "");
|
||||
|
||||
void PrintASCII(const uint8_t *Data, size_t Size, const char *PrintAfter = "");
|
||||
|
||||
void PrintASCII(const Unit &U, const char *PrintAfter = "");
|
||||
|
||||
// Changes U to contain only ASCII (isprint+isspace) characters.
|
||||
// Returns true iff U has been changed.
|
||||
bool ToASCII(uint8_t *Data, size_t Size);
|
||||
|
||||
bool IsASCII(const Unit &U);
|
||||
|
||||
bool IsASCII(const uint8_t *Data, size_t Size);
|
||||
|
||||
std::string Base64(const Unit &U);
|
||||
|
||||
void PrintPC(const char *SymbolizedFMT, const char *FallbackFMT, uintptr_t PC);
|
||||
|
||||
std::string DescribePC(const char *SymbolizedFMT, uintptr_t PC);
|
||||
|
||||
unsigned NumberOfCpuCores();
|
||||
|
||||
bool ExecuteCommandAndReadOutput(const std::string &Command, std::string *Out);
|
||||
|
||||
// Platform specific functions.
|
||||
void SetSignalHandler(const FuzzingOptions& Options);
|
||||
|
||||
void SleepSeconds(int Seconds);
|
||||
|
||||
unsigned long GetPid();
|
||||
|
||||
size_t GetPeakRSSMb();
|
||||
|
||||
int ExecuteCommand(const std::string &Command);
|
||||
|
||||
FILE *OpenProcessPipe(const char *Command, const char *Mode);
|
||||
|
||||
const void *SearchMemory(const void *haystack, size_t haystacklen,
|
||||
const void *needle, size_t needlelen);
|
||||
|
||||
std::string CloneArgsWithoutX(const std::vector<std::string> &Args,
|
||||
const char *X1, const char *X2);
|
||||
|
||||
inline std::string CloneArgsWithoutX(const std::vector<std::string> &Args,
|
||||
const char *X) {
|
||||
return CloneArgsWithoutX(Args, X, X);
|
||||
}
|
||||
|
||||
} // namespace fuzzer
|
||||
|
||||
#endif // LLVM_FUZZER_UTIL_H
|
||||
@@ -1,152 +0,0 @@
|
||||
//===- FuzzerUtilDarwin.cpp - Misc utils ----------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Misc utils for Darwin.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "FuzzerDefs.h"
|
||||
#if LIBFUZZER_APPLE
|
||||
|
||||
#include "FuzzerIO.h"
|
||||
#include <mutex>
|
||||
#include <signal.h>
|
||||
#include <spawn.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
// There is no header for this on macOS so declare here
|
||||
extern "C" char **environ;
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
static std::mutex SignalMutex;
|
||||
// Global variables used to keep track of how signal handling should be
|
||||
// restored. They should **not** be accessed without holding `SignalMutex`.
|
||||
static int ActiveThreadCount = 0;
|
||||
static struct sigaction OldSigIntAction;
|
||||
static struct sigaction OldSigQuitAction;
|
||||
static sigset_t OldBlockedSignalsSet;
|
||||
|
||||
// This is a reimplementation of Libc's `system()`. On Darwin the Libc
|
||||
// implementation contains a mutex which prevents it from being used
|
||||
// concurrently. This implementation **can** be used concurrently. It sets the
|
||||
// signal handlers when the first thread enters and restores them when the last
|
||||
// thread finishes execution of the function and ensures this is not racey by
|
||||
// using a mutex.
|
||||
int ExecuteCommand(const std::string &Command) {
|
||||
posix_spawnattr_t SpawnAttributes;
|
||||
if (posix_spawnattr_init(&SpawnAttributes))
|
||||
return -1;
|
||||
// Block and ignore signals of the current process when the first thread
|
||||
// enters.
|
||||
{
|
||||
std::lock_guard<std::mutex> Lock(SignalMutex);
|
||||
if (ActiveThreadCount == 0) {
|
||||
static struct sigaction IgnoreSignalAction;
|
||||
sigset_t BlockedSignalsSet;
|
||||
memset(&IgnoreSignalAction, 0, sizeof(IgnoreSignalAction));
|
||||
IgnoreSignalAction.sa_handler = SIG_IGN;
|
||||
|
||||
if (sigaction(SIGINT, &IgnoreSignalAction, &OldSigIntAction) == -1) {
|
||||
Printf("Failed to ignore SIGINT\n");
|
||||
(void)posix_spawnattr_destroy(&SpawnAttributes);
|
||||
return -1;
|
||||
}
|
||||
if (sigaction(SIGQUIT, &IgnoreSignalAction, &OldSigQuitAction) == -1) {
|
||||
Printf("Failed to ignore SIGQUIT\n");
|
||||
// Try our best to restore the signal handlers.
|
||||
(void)sigaction(SIGINT, &OldSigIntAction, NULL);
|
||||
(void)posix_spawnattr_destroy(&SpawnAttributes);
|
||||
return -1;
|
||||
}
|
||||
|
||||
(void)sigemptyset(&BlockedSignalsSet);
|
||||
(void)sigaddset(&BlockedSignalsSet, SIGCHLD);
|
||||
if (sigprocmask(SIG_BLOCK, &BlockedSignalsSet, &OldBlockedSignalsSet) ==
|
||||
-1) {
|
||||
Printf("Failed to block SIGCHLD\n");
|
||||
// Try our best to restore the signal handlers.
|
||||
(void)sigaction(SIGQUIT, &OldSigQuitAction, NULL);
|
||||
(void)sigaction(SIGINT, &OldSigIntAction, NULL);
|
||||
(void)posix_spawnattr_destroy(&SpawnAttributes);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
++ActiveThreadCount;
|
||||
}
|
||||
|
||||
// NOTE: Do not introduce any new `return` statements past this
|
||||
// point. It is important that `ActiveThreadCount` always be decremented
|
||||
// when leaving this function.
|
||||
|
||||
// Make sure the child process uses the default handlers for the
|
||||
// following signals rather than inheriting what the parent has.
|
||||
sigset_t DefaultSigSet;
|
||||
(void)sigemptyset(&DefaultSigSet);
|
||||
(void)sigaddset(&DefaultSigSet, SIGQUIT);
|
||||
(void)sigaddset(&DefaultSigSet, SIGINT);
|
||||
(void)posix_spawnattr_setsigdefault(&SpawnAttributes, &DefaultSigSet);
|
||||
// Make sure the child process doesn't block SIGCHLD
|
||||
(void)posix_spawnattr_setsigmask(&SpawnAttributes, &OldBlockedSignalsSet);
|
||||
short SpawnFlags = POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK;
|
||||
(void)posix_spawnattr_setflags(&SpawnAttributes, SpawnFlags);
|
||||
|
||||
pid_t Pid;
|
||||
char **Environ = environ; // Read from global
|
||||
const char *CommandCStr = Command.c_str();
|
||||
const char *Argv[] = {"sh", "-c", CommandCStr, NULL};
|
||||
int ErrorCode = 0, ProcessStatus = 0;
|
||||
// FIXME: We probably shouldn't hardcode the shell path.
|
||||
ErrorCode = posix_spawn(&Pid, "/bin/sh", NULL, &SpawnAttributes,
|
||||
(char *const *)Argv, Environ);
|
||||
(void)posix_spawnattr_destroy(&SpawnAttributes);
|
||||
if (!ErrorCode) {
|
||||
pid_t SavedPid = Pid;
|
||||
do {
|
||||
// Repeat until call completes uninterrupted.
|
||||
Pid = waitpid(SavedPid, &ProcessStatus, /*options=*/0);
|
||||
} while (Pid == -1 && errno == EINTR);
|
||||
if (Pid == -1) {
|
||||
// Fail for some other reason.
|
||||
ProcessStatus = -1;
|
||||
}
|
||||
} else if (ErrorCode == ENOMEM || ErrorCode == EAGAIN) {
|
||||
// Fork failure.
|
||||
ProcessStatus = -1;
|
||||
} else {
|
||||
// Shell execution failure.
|
||||
ProcessStatus = W_EXITCODE(127, 0);
|
||||
}
|
||||
|
||||
// Restore the signal handlers of the current process when the last thread
|
||||
// using this function finishes.
|
||||
{
|
||||
std::lock_guard<std::mutex> Lock(SignalMutex);
|
||||
--ActiveThreadCount;
|
||||
if (ActiveThreadCount == 0) {
|
||||
bool FailedRestore = false;
|
||||
if (sigaction(SIGINT, &OldSigIntAction, NULL) == -1) {
|
||||
Printf("Failed to restore SIGINT handling\n");
|
||||
FailedRestore = true;
|
||||
}
|
||||
if (sigaction(SIGQUIT, &OldSigQuitAction, NULL) == -1) {
|
||||
Printf("Failed to restore SIGQUIT handling\n");
|
||||
FailedRestore = true;
|
||||
}
|
||||
if (sigprocmask(SIG_BLOCK, &OldBlockedSignalsSet, NULL) == -1) {
|
||||
Printf("Failed to unblock SIGCHLD\n");
|
||||
FailedRestore = true;
|
||||
}
|
||||
if (FailedRestore)
|
||||
ProcessStatus = -1;
|
||||
}
|
||||
}
|
||||
return ProcessStatus;
|
||||
}
|
||||
|
||||
} // namespace fuzzer
|
||||
|
||||
#endif // LIBFUZZER_APPLE
|
||||
@@ -1,24 +0,0 @@
|
||||
//===- FuzzerUtilLinux.cpp - Misc utils for Linux. ------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Misc utils for Linux.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "FuzzerDefs.h"
|
||||
#if LIBFUZZER_LINUX
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
int ExecuteCommand(const std::string &Command) {
|
||||
return system(Command.c_str());
|
||||
}
|
||||
|
||||
} // namespace fuzzer
|
||||
|
||||
#endif // LIBFUZZER_LINUX
|
||||
@@ -1,117 +0,0 @@
|
||||
//===- FuzzerUtilPosix.cpp - Misc utils for Posix. ------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Misc utils implementation using Posix API.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "FuzzerDefs.h"
|
||||
#if LIBFUZZER_POSIX
|
||||
#include "FuzzerIO.h"
|
||||
#include "FuzzerInternal.h"
|
||||
#include <cassert>
|
||||
#include <chrono>
|
||||
#include <cstring>
|
||||
#include <errno.h>
|
||||
#include <iomanip>
|
||||
#include <signal.h>
|
||||
#include <sstream>
|
||||
#include <stdio.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <thread>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
static void AlarmHandler(int, siginfo_t *, void *) {
|
||||
Fuzzer::StaticAlarmCallback();
|
||||
}
|
||||
|
||||
static void CrashHandler(int, siginfo_t *, void *) {
|
||||
Fuzzer::StaticCrashSignalCallback();
|
||||
}
|
||||
|
||||
static void InterruptHandler(int, siginfo_t *, void *) {
|
||||
Fuzzer::StaticInterruptCallback();
|
||||
}
|
||||
|
||||
static void SetSigaction(int signum,
|
||||
void (*callback)(int, siginfo_t *, void *)) {
|
||||
struct sigaction sigact;
|
||||
memset(&sigact, 0, sizeof(sigact));
|
||||
sigact.sa_sigaction = callback;
|
||||
if (sigaction(signum, &sigact, 0)) {
|
||||
Printf("libFuzzer: sigaction failed with %d\n", errno);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void SetTimer(int Seconds) {
|
||||
struct itimerval T {
|
||||
{Seconds, 0}, { Seconds, 0 }
|
||||
};
|
||||
if (setitimer(ITIMER_REAL, &T, nullptr)) {
|
||||
Printf("libFuzzer: setitimer failed with %d\n", errno);
|
||||
exit(1);
|
||||
}
|
||||
SetSigaction(SIGALRM, AlarmHandler);
|
||||
}
|
||||
|
||||
void SetSignalHandler(const FuzzingOptions& Options) {
|
||||
if (Options.UnitTimeoutSec > 0)
|
||||
SetTimer(Options.UnitTimeoutSec / 2 + 1);
|
||||
if (Options.HandleInt)
|
||||
SetSigaction(SIGINT, InterruptHandler);
|
||||
if (Options.HandleTerm)
|
||||
SetSigaction(SIGTERM, InterruptHandler);
|
||||
if (Options.HandleSegv)
|
||||
SetSigaction(SIGSEGV, CrashHandler);
|
||||
if (Options.HandleBus)
|
||||
SetSigaction(SIGBUS, CrashHandler);
|
||||
if (Options.HandleAbrt)
|
||||
SetSigaction(SIGABRT, CrashHandler);
|
||||
if (Options.HandleIll)
|
||||
SetSigaction(SIGILL, CrashHandler);
|
||||
if (Options.HandleFpe)
|
||||
SetSigaction(SIGFPE, CrashHandler);
|
||||
}
|
||||
|
||||
void SleepSeconds(int Seconds) {
|
||||
sleep(Seconds); // Use C API to avoid coverage from instrumented libc++.
|
||||
}
|
||||
|
||||
unsigned long GetPid() { return (unsigned long)getpid(); }
|
||||
|
||||
size_t GetPeakRSSMb() {
|
||||
struct rusage usage;
|
||||
if (getrusage(RUSAGE_SELF, &usage))
|
||||
return 0;
|
||||
if (LIBFUZZER_LINUX) {
|
||||
// ru_maxrss is in KiB
|
||||
return usage.ru_maxrss >> 10;
|
||||
} else if (LIBFUZZER_APPLE) {
|
||||
// ru_maxrss is in bytes
|
||||
return usage.ru_maxrss >> 20;
|
||||
}
|
||||
assert(0 && "GetPeakRSSMb() is not implemented for your platform");
|
||||
return 0;
|
||||
}
|
||||
|
||||
FILE *OpenProcessPipe(const char *Command, const char *Mode) {
|
||||
return popen(Command, Mode);
|
||||
}
|
||||
|
||||
const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt,
|
||||
size_t PattLen) {
|
||||
return memmem(Data, DataLen, Patt, PattLen);
|
||||
}
|
||||
|
||||
} // namespace fuzzer
|
||||
|
||||
#endif // LIBFUZZER_POSIX
|
||||
@@ -1,182 +0,0 @@
|
||||
//===- FuzzerUtilWindows.cpp - Misc utils for Windows. --------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Misc utils implementation for Windows.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "FuzzerDefs.h"
|
||||
#if LIBFUZZER_WINDOWS
|
||||
#include "FuzzerIO.h"
|
||||
#include "FuzzerInternal.h"
|
||||
#include <cassert>
|
||||
#include <chrono>
|
||||
#include <cstring>
|
||||
#include <errno.h>
|
||||
#include <iomanip>
|
||||
#include <signal.h>
|
||||
#include <sstream>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <windows.h>
|
||||
#include <Psapi.h>
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
static const FuzzingOptions* HandlerOpt = nullptr;
|
||||
|
||||
LONG CALLBACK ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo) {
|
||||
switch (ExceptionInfo->ExceptionRecord->ExceptionCode) {
|
||||
case EXCEPTION_ACCESS_VIOLATION:
|
||||
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
|
||||
case EXCEPTION_STACK_OVERFLOW:
|
||||
if (HandlerOpt->HandleSegv)
|
||||
Fuzzer::StaticCrashSignalCallback();
|
||||
break;
|
||||
case EXCEPTION_DATATYPE_MISALIGNMENT:
|
||||
case EXCEPTION_IN_PAGE_ERROR:
|
||||
if (HandlerOpt->HandleBus)
|
||||
Fuzzer::StaticCrashSignalCallback();
|
||||
break;
|
||||
case EXCEPTION_ILLEGAL_INSTRUCTION:
|
||||
case EXCEPTION_PRIV_INSTRUCTION:
|
||||
if (HandlerOpt->HandleIll)
|
||||
Fuzzer::StaticCrashSignalCallback();
|
||||
break;
|
||||
case EXCEPTION_FLT_DENORMAL_OPERAND:
|
||||
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
|
||||
case EXCEPTION_FLT_INEXACT_RESULT:
|
||||
case EXCEPTION_FLT_INVALID_OPERATION:
|
||||
case EXCEPTION_FLT_OVERFLOW:
|
||||
case EXCEPTION_FLT_STACK_CHECK:
|
||||
case EXCEPTION_FLT_UNDERFLOW:
|
||||
case EXCEPTION_INT_DIVIDE_BY_ZERO:
|
||||
case EXCEPTION_INT_OVERFLOW:
|
||||
if (HandlerOpt->HandleFpe)
|
||||
Fuzzer::StaticCrashSignalCallback();
|
||||
break;
|
||||
}
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
BOOL WINAPI CtrlHandler(DWORD dwCtrlType) {
|
||||
switch (dwCtrlType) {
|
||||
case CTRL_C_EVENT:
|
||||
if (HandlerOpt->HandleInt)
|
||||
Fuzzer::StaticInterruptCallback();
|
||||
return TRUE;
|
||||
case CTRL_BREAK_EVENT:
|
||||
if (HandlerOpt->HandleTerm)
|
||||
Fuzzer::StaticInterruptCallback();
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void CALLBACK AlarmHandler(PVOID, BOOLEAN) {
|
||||
Fuzzer::StaticAlarmCallback();
|
||||
}
|
||||
|
||||
class TimerQ {
|
||||
HANDLE TimerQueue;
|
||||
public:
|
||||
TimerQ() : TimerQueue(NULL) {};
|
||||
~TimerQ() {
|
||||
if (TimerQueue)
|
||||
DeleteTimerQueueEx(TimerQueue, NULL);
|
||||
};
|
||||
void SetTimer(int Seconds) {
|
||||
if (!TimerQueue) {
|
||||
TimerQueue = CreateTimerQueue();
|
||||
if (!TimerQueue) {
|
||||
Printf("libFuzzer: CreateTimerQueue failed.\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
HANDLE Timer;
|
||||
if (!CreateTimerQueueTimer(&Timer, TimerQueue, AlarmHandler, NULL,
|
||||
Seconds*1000, Seconds*1000, 0)) {
|
||||
Printf("libFuzzer: CreateTimerQueueTimer failed.\n");
|
||||
exit(1);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
static TimerQ Timer;
|
||||
|
||||
static void CrashHandler(int) { Fuzzer::StaticCrashSignalCallback(); }
|
||||
|
||||
void SetSignalHandler(const FuzzingOptions& Options) {
|
||||
HandlerOpt = &Options;
|
||||
|
||||
if (Options.UnitTimeoutSec > 0)
|
||||
Timer.SetTimer(Options.UnitTimeoutSec / 2 + 1);
|
||||
|
||||
if (Options.HandleInt || Options.HandleTerm)
|
||||
if (!SetConsoleCtrlHandler(CtrlHandler, TRUE)) {
|
||||
DWORD LastError = GetLastError();
|
||||
Printf("libFuzzer: SetConsoleCtrlHandler failed (Error code: %lu).\n",
|
||||
LastError);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (Options.HandleSegv || Options.HandleBus || Options.HandleIll ||
|
||||
Options.HandleFpe)
|
||||
if (!AddVectoredExceptionHandler(1, ExceptionHandler)) {
|
||||
Printf("libFuzzer: AddVectoredExceptionHandler failed.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (Options.HandleAbrt)
|
||||
if (SIG_ERR == signal(SIGABRT, CrashHandler)) {
|
||||
Printf("libFuzzer: signal failed with %d\n", errno);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void SleepSeconds(int Seconds) { Sleep(Seconds * 1000); }
|
||||
|
||||
unsigned long GetPid() { return GetCurrentProcessId(); }
|
||||
|
||||
size_t GetPeakRSSMb() {
|
||||
PROCESS_MEMORY_COUNTERS info;
|
||||
if (!GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info)))
|
||||
return 0;
|
||||
return info.PeakWorkingSetSize >> 20;
|
||||
}
|
||||
|
||||
FILE *OpenProcessPipe(const char *Command, const char *Mode) {
|
||||
return _popen(Command, Mode);
|
||||
}
|
||||
|
||||
int ExecuteCommand(const std::string &Command) {
|
||||
return system(Command.c_str());
|
||||
}
|
||||
|
||||
const void *SearchMemory(const void *Data, size_t DataLen, const void *Patt,
|
||||
size_t PattLen) {
|
||||
// TODO: make this implementation more efficient.
|
||||
const char *Cdata = (const char *)Data;
|
||||
const char *Cpatt = (const char *)Patt;
|
||||
|
||||
if (!Data || !Patt || DataLen == 0 || PattLen == 0 || DataLen < PattLen)
|
||||
return NULL;
|
||||
|
||||
if (PattLen == 1)
|
||||
return memchr(Data, *Cpatt, DataLen);
|
||||
|
||||
const char *End = Cdata + DataLen - PattLen + 1;
|
||||
|
||||
for (const char *It = Cdata; It < End; ++It)
|
||||
if (It[0] == Cpatt[0] && memcmp(It, Cpatt, PattLen) == 0)
|
||||
return It;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
} // namespace fuzzer
|
||||
|
||||
#endif // LIBFUZZER_WINDOWS
|
||||
@@ -1,87 +0,0 @@
|
||||
//===- FuzzerValueBitMap.h - INTERNAL - Bit map -----------------*- C++ -* ===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ValueBitMap.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_FUZZER_VALUE_BIT_MAP_H
|
||||
#define LLVM_FUZZER_VALUE_BIT_MAP_H
|
||||
|
||||
#include "FuzzerDefs.h"
|
||||
|
||||
namespace fuzzer {
|
||||
|
||||
// A bit map containing kMapSizeInWords bits.
|
||||
struct ValueBitMap {
|
||||
static const size_t kMapSizeInBits = 65371; // Prime.
|
||||
static const size_t kMapSizeInBitsAligned = 65536; // 2^16
|
||||
static const size_t kBitsInWord = (sizeof(uintptr_t) * 8);
|
||||
static const size_t kMapSizeInWords = kMapSizeInBitsAligned / kBitsInWord;
|
||||
public:
|
||||
static const size_t kNumberOfItems = kMapSizeInBits;
|
||||
// Clears all bits.
|
||||
void Reset() { memset(Map, 0, sizeof(Map)); }
|
||||
|
||||
// Computes a hash function of Value and sets the corresponding bit.
|
||||
// Returns true if the bit was changed from 0 to 1.
|
||||
inline bool AddValue(uintptr_t Value) {
|
||||
uintptr_t Idx = Value < kMapSizeInBits ? Value : Value % kMapSizeInBits;
|
||||
uintptr_t WordIdx = Idx / kBitsInWord;
|
||||
uintptr_t BitIdx = Idx % kBitsInWord;
|
||||
uintptr_t Old = Map[WordIdx];
|
||||
uintptr_t New = Old | (1UL << BitIdx);
|
||||
Map[WordIdx] = New;
|
||||
return New != Old;
|
||||
}
|
||||
|
||||
inline bool Get(uintptr_t Idx) {
|
||||
assert(Idx < kMapSizeInBits);
|
||||
uintptr_t WordIdx = Idx / kBitsInWord;
|
||||
uintptr_t BitIdx = Idx % kBitsInWord;
|
||||
return Map[WordIdx] & (1UL << BitIdx);
|
||||
}
|
||||
|
||||
size_t GetNumBitsSinceLastMerge() const { return NumBits; }
|
||||
|
||||
// Merges 'Other' into 'this', clears 'Other', updates NumBits,
|
||||
// returns true if new bits were added.
|
||||
ATTRIBUTE_TARGET_POPCNT
|
||||
bool MergeFrom(ValueBitMap &Other) {
|
||||
uintptr_t Res = 0;
|
||||
size_t OldNumBits = NumBits;
|
||||
for (size_t i = 0; i < kMapSizeInWords; i++) {
|
||||
auto O = Other.Map[i];
|
||||
auto M = Map[i];
|
||||
if (O) {
|
||||
Map[i] = (M |= O);
|
||||
Other.Map[i] = 0;
|
||||
}
|
||||
if (M)
|
||||
Res += __builtin_popcountl(M);
|
||||
}
|
||||
NumBits = Res;
|
||||
return OldNumBits < NumBits;
|
||||
}
|
||||
|
||||
template <class Callback>
|
||||
void ForEach(Callback CB) {
|
||||
for (size_t i = 0; i < kMapSizeInWords; i++)
|
||||
if (uintptr_t M = Map[i])
|
||||
for (size_t j = 0; j < sizeof(M) * 8; j++)
|
||||
if (M & ((uintptr_t)1 << j))
|
||||
CB(i * sizeof(M) * 8 + j);
|
||||
}
|
||||
|
||||
private:
|
||||
size_t NumBits = 0;
|
||||
uintptr_t Map[kMapSizeInWords] __attribute__((aligned(512)));
|
||||
};
|
||||
|
||||
} // namespace fuzzer
|
||||
|
||||
#endif // LLVM_FUZZER_VALUE_BIT_MAP_H
|
||||
@@ -1,2 +0,0 @@
|
||||
Move to http://llvm.org/docs/LibFuzzer.html
|
||||
|
||||
@@ -1,295 +0,0 @@
|
||||
//===- afl_driver.cpp - a glue between AFL and libFuzzer --------*- C++ -* ===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/* This file allows to fuzz libFuzzer-style target functions
|
||||
(LLVMFuzzerTestOneInput) with AFL using AFL's persistent (in-process) mode.
|
||||
|
||||
Usage:
|
||||
################################################################################
|
||||
cat << EOF > test_fuzzer.cc
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||
if (size > 0 && data[0] == 'H')
|
||||
if (size > 1 && data[1] == 'I')
|
||||
if (size > 2 && data[2] == '!')
|
||||
__builtin_trap();
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
# Build your target with -fsanitize-coverage=trace-pc using fresh clang.
|
||||
clang -g -fsanitize-coverage=trace-pc test_fuzzer.cc -c
|
||||
# Build afl-llvm-rt.o.c from the AFL distribution.
|
||||
clang -c -w $AFL_HOME/llvm_mode/afl-llvm-rt.o.c
|
||||
# Build this file, link it with afl-llvm-rt.o.o and the target code.
|
||||
clang++ afl_driver.cpp test_fuzzer.o afl-llvm-rt.o.o
|
||||
# Run AFL:
|
||||
rm -rf IN OUT; mkdir IN OUT; echo z > IN/z;
|
||||
$AFL_HOME/afl-fuzz -i IN -o OUT ./a.out
|
||||
################################################################################
|
||||
Environment Variables:
|
||||
There are a few environment variables that can be set to use features that
|
||||
afl-fuzz doesn't have.
|
||||
|
||||
AFL_DRIVER_STDERR_DUPLICATE_FILENAME: Setting this *appends* stderr to the file
|
||||
specified. If the file does not exist, it is created. This is useful for getting
|
||||
stack traces (when using ASAN for example) or original error messages on hard to
|
||||
reproduce bugs.
|
||||
|
||||
AFL_DRIVER_EXTRA_STATS_FILENAME: Setting this causes afl_driver to write extra
|
||||
statistics to the file specified. Currently these are peak_rss_mb
|
||||
(the peak amount of virtual memory used in MB) and slowest_unit_time_secs. If
|
||||
the file does not exist it is created. If the file does exist then
|
||||
afl_driver assumes it was restarted by afl-fuzz and will try to read old
|
||||
statistics from the file. If that fails then the process will quit.
|
||||
|
||||
*/
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <sys/resource.h>
|
||||
#include <sys/time.h>
|
||||
// Platform detection. Copied from FuzzerInternal.h
|
||||
#ifdef __linux__
|
||||
#define LIBFUZZER_LINUX 1
|
||||
#define LIBFUZZER_APPLE 0
|
||||
#elif __APPLE__
|
||||
#define LIBFUZZER_LINUX 0
|
||||
#define LIBFUZZER_APPLE 1
|
||||
#else
|
||||
#error "Support for your platform has not been implemented"
|
||||
#endif
|
||||
|
||||
// Used to avoid repeating error checking boilerplate. If cond is false, a
|
||||
// fatal error has occurred in the program. In this event print error_message
|
||||
// to stderr and abort(). Otherwise do nothing. Note that setting
|
||||
// AFL_DRIVER_STDERR_DUPLICATE_FILENAME may cause error_message to be appended
|
||||
// to the file as well, if the error occurs after the duplication is performed.
|
||||
#define CHECK_ERROR(cond, error_message) \
|
||||
if (!(cond)) { \
|
||||
fprintf(stderr, (error_message)); \
|
||||
abort(); \
|
||||
}
|
||||
|
||||
// libFuzzer interface is thin, so we don't include any libFuzzer headers.
|
||||
extern "C" {
|
||||
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
|
||||
__attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv);
|
||||
}
|
||||
|
||||
// Notify AFL about persistent mode.
|
||||
static volatile char AFL_PERSISTENT[] = "##SIG_AFL_PERSISTENT##";
|
||||
extern "C" int __afl_persistent_loop(unsigned int);
|
||||
static volatile char suppress_warning2 = AFL_PERSISTENT[0];
|
||||
|
||||
// Notify AFL about deferred forkserver.
|
||||
static volatile char AFL_DEFER_FORKSVR[] = "##SIG_AFL_DEFER_FORKSRV##";
|
||||
extern "C" void __afl_manual_init();
|
||||
static volatile char suppress_warning1 = AFL_DEFER_FORKSVR[0];
|
||||
|
||||
// Input buffer.
|
||||
static const size_t kMaxAflInputSize = 1 << 20;
|
||||
static uint8_t AflInputBuf[kMaxAflInputSize];
|
||||
|
||||
// Variables we need for writing to the extra stats file.
|
||||
static FILE *extra_stats_file = NULL;
|
||||
static uint32_t previous_peak_rss = 0;
|
||||
static time_t slowest_unit_time_secs = 0;
|
||||
static const int kNumExtraStats = 2;
|
||||
static const char *kExtraStatsFormatString = "peak_rss_mb : %u\n"
|
||||
"slowest_unit_time_sec : %u\n";
|
||||
|
||||
// Copied from FuzzerUtil.cpp.
|
||||
size_t GetPeakRSSMb() {
|
||||
struct rusage usage;
|
||||
if (getrusage(RUSAGE_SELF, &usage))
|
||||
return 0;
|
||||
if (LIBFUZZER_LINUX) {
|
||||
// ru_maxrss is in KiB
|
||||
return usage.ru_maxrss >> 10;
|
||||
} else if (LIBFUZZER_APPLE) {
|
||||
// ru_maxrss is in bytes
|
||||
return usage.ru_maxrss >> 20;
|
||||
}
|
||||
assert(0 && "GetPeakRSSMb() is not implemented for your platform");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Based on SetSigaction in FuzzerUtil.cpp
|
||||
static void SetSigaction(int signum,
|
||||
void (*callback)(int, siginfo_t *, void *)) {
|
||||
struct sigaction sigact;
|
||||
memset(&sigact, 0, sizeof(sigact));
|
||||
sigact.sa_sigaction = callback;
|
||||
if (sigaction(signum, &sigact, 0)) {
|
||||
fprintf(stderr, "libFuzzer: sigaction failed with %d\n", errno);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Write extra stats to the file specified by the user. If none is specified
|
||||
// this function will never be called.
|
||||
static void write_extra_stats() {
|
||||
uint32_t peak_rss = GetPeakRSSMb();
|
||||
|
||||
if (peak_rss < previous_peak_rss)
|
||||
peak_rss = previous_peak_rss;
|
||||
|
||||
int chars_printed = fprintf(extra_stats_file, kExtraStatsFormatString,
|
||||
peak_rss, slowest_unit_time_secs);
|
||||
|
||||
CHECK_ERROR(chars_printed != 0, "Failed to write extra_stats_file");
|
||||
|
||||
CHECK_ERROR(fclose(extra_stats_file) == 0,
|
||||
"Failed to close extra_stats_file");
|
||||
}
|
||||
|
||||
// Call write_extra_stats before we exit.
|
||||
static void crash_handler(int, siginfo_t *, void *) {
|
||||
// Make sure we don't try calling write_extra_stats again if we crashed while
|
||||
// trying to call it.
|
||||
static bool first_crash = true;
|
||||
CHECK_ERROR(first_crash,
|
||||
"Crashed in crash signal handler. This is a bug in the fuzzer.");
|
||||
|
||||
first_crash = false;
|
||||
write_extra_stats();
|
||||
}
|
||||
|
||||
// If the user has specified an extra_stats_file through the environment
|
||||
// variable AFL_DRIVER_EXTRA_STATS_FILENAME, then perform necessary set up
|
||||
// to write stats to it on exit. If no file is specified, do nothing. Otherwise
|
||||
// install signal and exit handlers to write to the file when the process exits.
|
||||
// Then if the file doesn't exist create it and set extra stats to 0. But if it
|
||||
// does exist then read the initial values of the extra stats from the file
|
||||
// and check that the file is writable.
|
||||
static void maybe_initialize_extra_stats() {
|
||||
// If AFL_DRIVER_EXTRA_STATS_FILENAME isn't set then we have nothing to do.
|
||||
char *extra_stats_filename = getenv("AFL_DRIVER_EXTRA_STATS_FILENAME");
|
||||
if (!extra_stats_filename)
|
||||
return;
|
||||
|
||||
// Open the file and find the previous peak_rss_mb value.
|
||||
// This is necessary because the fuzzing process is restarted after N
|
||||
// iterations are completed. So we may need to get this value from a previous
|
||||
// process to be accurate.
|
||||
extra_stats_file = fopen(extra_stats_filename, "r");
|
||||
|
||||
// If extra_stats_file already exists: read old stats from it.
|
||||
if (extra_stats_file) {
|
||||
int matches = fscanf(extra_stats_file, kExtraStatsFormatString,
|
||||
&previous_peak_rss, &slowest_unit_time_secs);
|
||||
|
||||
// Make sure we have read a real extra stats file and that we have used it
|
||||
// to set slowest_unit_time_secs and previous_peak_rss.
|
||||
CHECK_ERROR(matches == kNumExtraStats, "Extra stats file is corrupt");
|
||||
|
||||
CHECK_ERROR(fclose(extra_stats_file) == 0, "Failed to close file");
|
||||
|
||||
// Now open the file for writing.
|
||||
extra_stats_file = fopen(extra_stats_filename, "w");
|
||||
CHECK_ERROR(extra_stats_file,
|
||||
"Failed to open extra stats file for writing");
|
||||
} else {
|
||||
// Looks like this is the first time in a fuzzing job this is being called.
|
||||
extra_stats_file = fopen(extra_stats_filename, "w+");
|
||||
CHECK_ERROR(extra_stats_file, "failed to create extra stats file");
|
||||
}
|
||||
|
||||
// Make sure that crash_handler gets called on any kind of fatal error.
|
||||
int crash_signals[] = {SIGSEGV, SIGBUS, SIGABRT, SIGILL, SIGFPE, SIGINT,
|
||||
SIGTERM};
|
||||
|
||||
const size_t num_signals = sizeof(crash_signals) / sizeof(crash_signals[0]);
|
||||
|
||||
for (size_t idx = 0; idx < num_signals; idx++)
|
||||
SetSigaction(crash_signals[idx], crash_handler);
|
||||
|
||||
// Make sure it gets called on other kinds of exits.
|
||||
atexit(write_extra_stats);
|
||||
}
|
||||
|
||||
// If the user asks us to duplicate stderr, then do it.
|
||||
static void maybe_duplicate_stderr() {
|
||||
char* stderr_duplicate_filename =
|
||||
getenv("AFL_DRIVER_STDERR_DUPLICATE_FILENAME");
|
||||
|
||||
if (!stderr_duplicate_filename)
|
||||
return;
|
||||
|
||||
FILE* stderr_duplicate_stream =
|
||||
freopen(stderr_duplicate_filename, "a+", stderr);
|
||||
|
||||
if (!stderr_duplicate_stream) {
|
||||
fprintf(
|
||||
stderr,
|
||||
"Failed to duplicate stderr to AFL_DRIVER_STDERR_DUPLICATE_FILENAME");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
fprintf(stderr, "======================= INFO =========================\n"
|
||||
"This binary is built for AFL-fuzz.\n"
|
||||
"To run the target function on a single input execute this:\n"
|
||||
" %s < INPUT_FILE\n"
|
||||
"To run the fuzzing execute this:\n"
|
||||
" afl-fuzz [afl-flags] %s [N] "
|
||||
"-- run N fuzzing iterations before "
|
||||
"re-spawning the process (default: 1000)\n"
|
||||
"======================================================\n",
|
||||
argv[0], argv[0]);
|
||||
if (LLVMFuzzerInitialize)
|
||||
LLVMFuzzerInitialize(&argc, &argv);
|
||||
// Do any other expensive one-time initialization here.
|
||||
|
||||
maybe_duplicate_stderr();
|
||||
maybe_initialize_extra_stats();
|
||||
|
||||
__afl_manual_init();
|
||||
|
||||
int N = 1000;
|
||||
if (argc >= 2)
|
||||
N = atoi(argv[1]);
|
||||
assert(N > 0);
|
||||
time_t unit_time_secs;
|
||||
int num_runs = 0;
|
||||
while (__afl_persistent_loop(N)) {
|
||||
ssize_t n_read = read(0, AflInputBuf, kMaxAflInputSize);
|
||||
if (n_read > 0) {
|
||||
// Copy AflInputBuf into a separate buffer to let asan find buffer
|
||||
// overflows. Don't use unique_ptr/etc to avoid extra dependencies.
|
||||
uint8_t *copy = new uint8_t[n_read];
|
||||
memcpy(copy, AflInputBuf, n_read);
|
||||
|
||||
struct timeval unit_start_time;
|
||||
CHECK_ERROR(gettimeofday(&unit_start_time, NULL) == 0,
|
||||
"Calling gettimeofday failed");
|
||||
|
||||
num_runs++;
|
||||
LLVMFuzzerTestOneInput(copy, n_read);
|
||||
|
||||
struct timeval unit_stop_time;
|
||||
CHECK_ERROR(gettimeofday(&unit_stop_time, NULL) == 0,
|
||||
"Calling gettimeofday failed");
|
||||
|
||||
// Update slowest_unit_time_secs if we see a new max.
|
||||
unit_time_secs = unit_stop_time.tv_sec - unit_start_time.tv_sec;
|
||||
if (slowest_unit_time_secs < unit_time_secs)
|
||||
slowest_unit_time_secs = unit_time_secs;
|
||||
|
||||
delete[] copy;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "%s: successfully executed %d input(s)\n", argv[0], num_runs);
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
#!/bin/bash
|
||||
LIBFUZZER_SRC_DIR=$(dirname $0)
|
||||
for f in $LIBFUZZER_SRC_DIR/*.cpp; do
|
||||
clang -g -O2 -fno-omit-frame-pointer -std=c++11 $f -c &
|
||||
done
|
||||
wait
|
||||
rm -f libFuzzer.a
|
||||
ar ru libFuzzer.a Fuzzer*.o
|
||||
rm -f Fuzzer*.o
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
"++"
|
||||
"--"
|
||||
"<<"
|
||||
">>"
|
||||
"+="
|
||||
"-="
|
||||
"*="
|
||||
"/="
|
||||
">>="
|
||||
"<<="
|
||||
"&="
|
||||
"|="
|
||||
"^="
|
||||
"%="
|
||||
"!="
|
||||
"&&"
|
||||
"||"
|
||||
"=="
|
||||
">="
|
||||
"<="
|
||||
"->"
|
||||
"alignas"
|
||||
"alignof"
|
||||
"and"
|
||||
"and_eq"
|
||||
"asm"
|
||||
"auto"
|
||||
"bitand"
|
||||
"bitor"
|
||||
"bool"
|
||||
"break"
|
||||
"case"
|
||||
"catch"
|
||||
"char"
|
||||
"char16_t"
|
||||
"char32_t"
|
||||
"class"
|
||||
"compl"
|
||||
"concept"
|
||||
"const"
|
||||
"constexpr"
|
||||
"const_cast"
|
||||
"continue"
|
||||
"decltype"
|
||||
"default"
|
||||
"delete"
|
||||
"do"
|
||||
"double"
|
||||
"dynamic_cast"
|
||||
"else"
|
||||
"enum"
|
||||
"explicit"
|
||||
"export"
|
||||
"extern"
|
||||
"false"
|
||||
"float"
|
||||
"for"
|
||||
"friend"
|
||||
"goto"
|
||||
"if"
|
||||
"inline"
|
||||
"int"
|
||||
"long"
|
||||
"mutable"
|
||||
"namespace"
|
||||
"new"
|
||||
"noexcept"
|
||||
"not"
|
||||
"not_eq"
|
||||
"nullptr"
|
||||
"operator"
|
||||
"or"
|
||||
"or_eq"
|
||||
"private"
|
||||
"protected"
|
||||
"public"
|
||||
"register"
|
||||
"reinterpret_cast"
|
||||
"requires"
|
||||
"return"
|
||||
"short"
|
||||
"signed"
|
||||
"sizeof"
|
||||
"static"
|
||||
"static_assert"
|
||||
"static_cast"
|
||||
"struct"
|
||||
"switch"
|
||||
"template"
|
||||
"this"
|
||||
"thread_local"
|
||||
"throw"
|
||||
"true"
|
||||
"try"
|
||||
"typedef"
|
||||
"typeid"
|
||||
"typename"
|
||||
"union"
|
||||
"unsigned"
|
||||
"using"
|
||||
"virtual"
|
||||
"void"
|
||||
"volatile"
|
||||
"wchar_t"
|
||||
"while"
|
||||
"xor"
|
||||
"xor_eq"
|
||||
"if"
|
||||
"elif"
|
||||
"else"
|
||||
"endif"
|
||||
"defined"
|
||||
"ifdef"
|
||||
"ifndef"
|
||||
"define"
|
||||
"undef"
|
||||
"include"
|
||||
"line"
|
||||
"error"
|
||||
"pragma"
|
||||
"override"
|
||||
"final"
|
||||
@@ -1,41 +0,0 @@
|
||||
/*===- StandaloneFuzzTargetMain.c - standalone main() for fuzz targets. ---===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
// This main() function can be linked to a fuzz target (i.e. a library
|
||||
// that exports LLVMFuzzerTestOneInput() and possibly LLVMFuzzerInitialize())
|
||||
// instead of libFuzzer. This main() function will not perform any fuzzing
|
||||
// but will simply feed all input files one by one to the fuzz target.
|
||||
//
|
||||
// Use this file to provide reproducers for bugs when linking against libFuzzer
|
||||
// or other fuzzing engine is undesirable.
|
||||
//===----------------------------------------------------------------------===*/
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
extern int LLVMFuzzerTestOneInput(const unsigned char *data, size_t size);
|
||||
__attribute__((weak)) extern int LLVMFuzzerInitialize(int *argc, char ***argv);
|
||||
int main(int argc, char **argv) {
|
||||
fprintf(stderr, "StandaloneFuzzTargetMain: running %d inputs\n", argc - 1);
|
||||
if (LLVMFuzzerInitialize)
|
||||
LLVMFuzzerInitialize(&argc, &argv);
|
||||
for (int i = 1; i < argc; i++) {
|
||||
fprintf(stderr, "Running: %s\n", argv[i]);
|
||||
FILE *f = fopen(argv[i], "r");
|
||||
assert(f);
|
||||
fseek(f, 0, SEEK_END);
|
||||
size_t len = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
unsigned char *buf = (unsigned char*)malloc(len);
|
||||
size_t n_read = fread(buf, 1, len, f);
|
||||
assert(n_read == len);
|
||||
LLVMFuzzerTestOneInput(buf, len);
|
||||
free(buf);
|
||||
fprintf(stderr, "Done: %s: (%zd bytes)\n", argv[i], n_read);
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
|
||||
// Contains dummy functions used to avoid dependency on AFL.
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
extern "C" void __afl_manual_init() {}
|
||||
|
||||
extern "C" int __afl_persistent_loop(unsigned int) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// This declaration exists to prevent the Darwin linker
|
||||
// from complaining about this being a missing weak symbol.
|
||||
extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
return 0;
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
|
||||
// abs(x) < 0 and y == Const puzzle, 64-bit variant.
|
||||
#include <cstring>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
if (Size < 16) return 0;
|
||||
int64_t x;
|
||||
uint64_t y;
|
||||
memcpy(&x, Data, sizeof(x));
|
||||
memcpy(&y, Data + sizeof(x), sizeof(y));
|
||||
if (labs(x) < 0 && y == 0xbaddcafedeadbeefUL) {
|
||||
printf("BINGO; Found the target, exiting; x = 0x%lx y 0x%lx\n", x, y);
|
||||
exit(1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
|
||||
// abs(x) < 0 and y == Const puzzle.
|
||||
#include <cstring>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
if (Size < 8) return 0;
|
||||
int x;
|
||||
unsigned y;
|
||||
memcpy(&x, Data, sizeof(x));
|
||||
memcpy(&y, Data + sizeof(x), sizeof(y));
|
||||
if (abs(x) < 0 && y == 0xbaddcafe) {
|
||||
printf("BINGO; Found the target, exiting; x = 0x%x y 0x%x\n", x, y);
|
||||
exit(1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
|
||||
// Test with a more mallocs than frees, but no leak.
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
|
||||
const int kAllocatedPointersSize = 10000;
|
||||
int NumAllocatedPointers = 0;
|
||||
int *AllocatedPointers[kAllocatedPointersSize];
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
|
||||
if (NumAllocatedPointers < kAllocatedPointersSize)
|
||||
AllocatedPointers[NumAllocatedPointers++] = new int;
|
||||
return 0;
|
||||
}
|
||||
|
||||