Coverage Report

Created: 2026-10-28 06:58

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/args/fuzz/numeric_parser_fuzzer.cpp
Line
Count
Source
1
#include <string>
2
#include <cstdint>
3
#include <args.hxx>
4
5
/*
6
 * Numeric conversion harness for args::ValueReader.
7
 *
8
 * Repaired for OSS-Fuzz: ValueReader::operator() throws args::ParseError
9
 * for any input the requested type cannot represent, and the original
10
 * harness had no exception handling, so the first malformed byte string
11
 * aborted the whole target before later conversions could run.
12
 *
13
 * Each conversion is now attempted independently, with the expected
14
 * rejection swallowed per type, so a single input reaches every numeric
15
 * path: strtoll/strtoull-based integers (with range and narrowing
16
 * checks), sign rejection for unsigned types, trailing-whitespace
17
 * tolerance, and istringstream-based parsing for bool, char, and
18
 * floating-point types. Embedded NUL bytes are preserved on purpose:
19
 * the readers deliberately distinguish "12\0junk" from "12".
20
 */
21
22
// Accumulates converted values so the conversions cannot be optimized away.
23
unsigned long g_sink = 0;
24
25
template <typename T>
26
static T AttemptConversion(args::ValueReader &reader, const std::string &input)
27
7.45k
{
28
7.45k
    T destination{};
29
7.45k
    try
30
7.45k
    {
31
7.45k
        reader("fuzz_test", input, destination);
32
7.45k
    }
33
7.45k
    catch (...)
34
7.45k
    {
35
        // Expected rejection for values this type cannot represent.
36
4.42k
    }
37
7.45k
    return destination;
38
7.45k
}
numeric_parser_fuzzer.cpp:bool AttemptConversion<bool>(args::ValueReader&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Line
Count
Source
27
497
{
28
497
    T destination{};
29
497
    try
30
497
    {
31
497
        reader("fuzz_test", input, destination);
32
497
    }
33
497
    catch (...)
34
497
    {
35
        // Expected rejection for values this type cannot represent.
36
489
    }
37
497
    return destination;
38
497
}
numeric_parser_fuzzer.cpp:char AttemptConversion<char>(args::ValueReader&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Line
Count
Source
27
497
{
28
497
    T destination{};
29
497
    try
30
497
    {
31
497
        reader("fuzz_test", input, destination);
32
497
    }
33
497
    catch (...)
34
497
    {
35
        // Expected rejection for values this type cannot represent.
36
465
    }
37
497
    return destination;
38
497
}
numeric_parser_fuzzer.cpp:signed char AttemptConversion<signed char>(args::ValueReader&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Line
Count
Source
27
497
{
28
497
    T destination{};
29
497
    try
30
497
    {
31
497
        reader("fuzz_test", input, destination);
32
497
    }
33
497
    catch (...)
34
497
    {
35
        // Expected rejection for values this type cannot represent.
36
465
    }
37
497
    return destination;
38
497
}
numeric_parser_fuzzer.cpp:unsigned char AttemptConversion<unsigned char>(args::ValueReader&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Line
Count
Source
27
497
{
28
497
    T destination{};
29
497
    try
30
497
    {
31
497
        reader("fuzz_test", input, destination);
32
497
    }
33
497
    catch (...)
34
497
    {
35
        // Expected rejection for values this type cannot represent.
36
465
    }
37
497
    return destination;
38
497
}
numeric_parser_fuzzer.cpp:short AttemptConversion<short>(args::ValueReader&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Line
Count
Source
27
497
{
28
497
    T destination{};
29
497
    try
30
497
    {
31
497
        reader("fuzz_test", input, destination);
32
497
    }
33
497
    catch (...)
34
497
    {
35
        // Expected rejection for values this type cannot represent.
36
436
    }
37
497
    return destination;
38
497
}
numeric_parser_fuzzer.cpp:int AttemptConversion<int>(args::ValueReader&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Line
Count
Source
27
497
{
28
497
    T destination{};
29
497
    try
30
497
    {
31
497
        reader("fuzz_test", input, destination);
32
497
    }
33
497
    catch (...)
34
497
    {
35
        // Expected rejection for values this type cannot represent.
36
306
    }
37
497
    return destination;
38
497
}
numeric_parser_fuzzer.cpp:long AttemptConversion<long>(args::ValueReader&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Line
Count
Source
27
497
{
28
497
    T destination{};
29
497
    try
30
497
    {
31
497
        reader("fuzz_test", input, destination);
32
497
    }
33
497
    catch (...)
34
497
    {
35
        // Expected rejection for values this type cannot represent.
36
146
    }
37
497
    return destination;
38
497
}
numeric_parser_fuzzer.cpp:long long AttemptConversion<long long>(args::ValueReader&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Line
Count
Source
27
497
{
28
497
    T destination{};
29
497
    try
30
497
    {
31
497
        reader("fuzz_test", input, destination);
32
497
    }
33
497
    catch (...)
34
497
    {
35
        // Expected rejection for values this type cannot represent.
36
146
    }
37
497
    return destination;
38
497
}
numeric_parser_fuzzer.cpp:unsigned short AttemptConversion<unsigned short>(args::ValueReader&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Line
Count
Source
27
497
{
28
497
    T destination{};
29
497
    try
30
497
    {
31
497
        reader("fuzz_test", input, destination);
32
497
    }
33
497
    catch (...)
34
497
    {
35
        // Expected rejection for values this type cannot represent.
36
434
    }
37
497
    return destination;
38
497
}
numeric_parser_fuzzer.cpp:unsigned int AttemptConversion<unsigned int>(args::ValueReader&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Line
Count
Source
27
497
{
28
497
    T destination{};
29
497
    try
30
497
    {
31
497
        reader("fuzz_test", input, destination);
32
497
    }
33
497
    catch (...)
34
497
    {
35
        // Expected rejection for values this type cannot represent.
36
345
    }
37
497
    return destination;
38
497
}
numeric_parser_fuzzer.cpp:unsigned long AttemptConversion<unsigned long>(args::ValueReader&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Line
Count
Source
27
497
{
28
497
    T destination{};
29
497
    try
30
497
    {
31
497
        reader("fuzz_test", input, destination);
32
497
    }
33
497
    catch (...)
34
497
    {
35
        // Expected rejection for values this type cannot represent.
36
232
    }
37
497
    return destination;
38
497
}
numeric_parser_fuzzer.cpp:unsigned long long AttemptConversion<unsigned long long>(args::ValueReader&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Line
Count
Source
27
497
{
28
497
    T destination{};
29
497
    try
30
497
    {
31
497
        reader("fuzz_test", input, destination);
32
497
    }
33
497
    catch (...)
34
497
    {
35
        // Expected rejection for values this type cannot represent.
36
232
    }
37
497
    return destination;
38
497
}
numeric_parser_fuzzer.cpp:float AttemptConversion<float>(args::ValueReader&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Line
Count
Source
27
497
{
28
497
    T destination{};
29
497
    try
30
497
    {
31
497
        reader("fuzz_test", input, destination);
32
497
    }
33
497
    catch (...)
34
497
    {
35
        // Expected rejection for values this type cannot represent.
36
91
    }
37
497
    return destination;
38
497
}
numeric_parser_fuzzer.cpp:double AttemptConversion<double>(args::ValueReader&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Line
Count
Source
27
497
{
28
497
    T destination{};
29
497
    try
30
497
    {
31
497
        reader("fuzz_test", input, destination);
32
497
    }
33
497
    catch (...)
34
497
    {
35
        // Expected rejection for values this type cannot represent.
36
88
    }
37
497
    return destination;
38
497
}
numeric_parser_fuzzer.cpp:long double AttemptConversion<long double>(args::ValueReader&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Line
Count
Source
27
497
{
28
497
    T destination{};
29
497
    try
30
497
    {
31
497
        reader("fuzz_test", input, destination);
32
497
    }
33
497
    catch (...)
34
497
    {
35
        // Expected rejection for values this type cannot represent.
36
86
    }
37
497
    return destination;
38
497
}
39
40
497
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
41
    // Create a string from fuzzer input, preserving embedded NULs
42
497
    std::string input(reinterpret_cast<const char*>(data), size);
43
44
497
    args::ValueReader reader;
45
46
    // Character-ish types (istringstream-based paths)
47
497
    g_sink += static_cast<unsigned long>(AttemptConversion<bool>(reader, input));
48
497
    g_sink += static_cast<unsigned long>(AttemptConversion<char>(reader, input));
49
497
    g_sink += static_cast<unsigned long>(AttemptConversion<signed char>(reader, input));
50
497
    g_sink += static_cast<unsigned long>(AttemptConversion<unsigned char>(reader, input));
51
52
    // Test signed integer types (strtoll-based path, narrowing checks)
53
497
    g_sink += static_cast<unsigned long>(AttemptConversion<short>(reader, input));
54
497
    g_sink += static_cast<unsigned long>(AttemptConversion<int>(reader, input));
55
497
    g_sink += static_cast<unsigned long>(AttemptConversion<long>(reader, input));
56
497
    g_sink += static_cast<unsigned long>(AttemptConversion<long long>(reader, input));
57
58
    // Test unsigned integer types (strtoull-based path, sign rejection)
59
497
    g_sink += static_cast<unsigned long>(AttemptConversion<unsigned short>(reader, input));
60
497
    g_sink += static_cast<unsigned long>(AttemptConversion<unsigned int>(reader, input));
61
497
    g_sink += static_cast<unsigned long>(AttemptConversion<unsigned long>(reader, input));
62
497
    g_sink += static_cast<unsigned long>(AttemptConversion<unsigned long long>(reader, input));
63
64
    // Test floating point types (istringstream-based path)
65
497
    g_sink += static_cast<unsigned long>(AttemptConversion<float>(reader, input));
66
497
    g_sink += static_cast<unsigned long>(AttemptConversion<double>(reader, input));
67
497
    g_sink += static_cast<unsigned long>(AttemptConversion<long double>(reader, input));
68
69
497
    return 0;
70
497
}