Coverage Report

Created: 2026-09-01 06:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/simdutf/fuzz/safe_conversion.cpp
Line
Count
Source
1
#include <algorithm>
2
#include <cassert>
3
#include <cstdlib>
4
#include <type_traits>
5
#include <vector>
6
7
#include "simdutf.h"
8
9
void test_latin1_to_utf8(std::span<const uint8_t> input_bytes,
10
730
                         std::size_t output_size) {
11
730
  std::vector<char> output(output_size);
12
730
  const auto written_bytes_safe =
13
730
      simdutf::convert_latin1_to_utf8_safe(input_bytes, output);
14
730
  if (written_bytes_safe > output_size) {
15
0
    std::abort();
16
0
  }
17
730
  const auto needed_size = simdutf::utf8_length_from_latin1(input_bytes);
18
730
  std::vector<char> reference(needed_size);
19
730
  const auto written_bytes_unsafe =
20
730
      simdutf::convert_latin1_to_utf8(input_bytes, reference);
21
730
  if (written_bytes_unsafe != needed_size) {
22
0
    std::abort();
23
0
  }
24
730
  if (written_bytes_safe > needed_size) {
25
    // convert_latin1_to_utf8_safe wrote more output buffer than the unsafe
26
    // version needed!
27
0
    std::abort();
28
0
  }
29
  // ensure output is equal to the beginning of reference
30
730
  if (!std::ranges::equal(
31
730
          std::span(output).subspan(0, written_bytes_safe),
32
730
          std::span(reference).subspan(0, written_bytes_safe))) {
33
0
    std::abort();
34
0
  }
35
730
}
36
37
void test_utf16_to_utf8(std::span<const char16_t> input,
38
1.01k
                        std::size_t output_size) {
39
1.01k
  std::vector<char> output(output_size);
40
1.01k
  const auto written_bytes_safe =
41
1.01k
      simdutf::convert_utf16_to_utf8_safe(input, output);
42
1.01k
  if (written_bytes_safe > output_size) {
43
0
    std::abort();
44
0
  }
45
  // result is implementation defined in case of garbage input
46
1.01k
  const auto unreliable_needed_size = simdutf::utf8_length_from_utf16(input);
47
1.01k
  std::vector<char> reference(unreliable_needed_size);
48
1.01k
  const auto written_bytes_unsafe =
49
1.01k
      simdutf::convert_utf16_to_utf8(input, reference);
50
51
  // ensure output is equal to the beginning of reference
52
1.01k
  const auto Ncompare =
53
1.01k
      simdutf::detail::min(written_bytes_safe, written_bytes_unsafe);
54
1.01k
  const auto matches =
55
1.01k
      std::ranges::equal(std::span(output).subspan(0, Ncompare),
56
1.01k
                         std::span(reference).subspan(0, Ncompare));
57
1.01k
  assert(matches);
58
1.01k
  if (!matches) {
59
0
    std::abort();
60
0
  }
61
1.01k
}
62
63
1.74k
void select_implementation(auto index) {
64
1.74k
  static const auto implementations = []() {
65
1
    const auto list = simdutf::get_available_implementations();
66
1
    using Impl = std::decay_t<decltype(*list.begin())>;
67
1
    std::vector<Impl> ret;
68
4
    for (auto& e : list) {
69
4
      if (e->supported_by_runtime_system()) {
70
3
        ret.push_back(e);
71
3
      }
72
4
    }
73
1
    return ret;
74
1
  }();
75
1.74k
  assert(!implementations.empty());
76
1.74k
  simdutf::get_active_implementation() =
77
1.74k
      implementations.at(index % implementations.size());
78
1.74k
}
79
80
4.85k
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
81
82
4.85k
  if (size < 4) {
83
6
    return 0;
84
6
  }
85
86
4.84k
  const auto action = data[0] & 0x1;
87
4.84k
  const auto output_size = (data[1] << 8 | data[2]);
88
4.84k
  const auto implementation_index = data[3] & 0b0111;
89
4.84k
  data += 4;
90
4.84k
  size -= 4;
91
92
4.84k
  const std::span<const uint8_t> input_bytes{data, data + size};
93
94
4.84k
  select_implementation(implementation_index);
95
96
4.84k
  switch (action) {
97
2.32k
  case 0:
98
2.32k
    test_latin1_to_utf8(input_bytes, output_size);
99
2.32k
    break;
100
2.52k
  case 1: {
101
2.52k
    const auto* ptr = reinterpret_cast<const char16_t*>(input_bytes.data());
102
2.52k
    test_utf16_to_utf8(std::span(ptr, ptr + input_bytes.size() / 2),
103
2.52k
                       output_size);
104
2.52k
  } break;
105
4.84k
  }
106
107
4.84k
  return 0;
108
4.84k
}